xref: /petsc/src/dm/impls/plex/plexgmsh.c (revision 11c56cb0be1d3c006bf09d25d4ce948793e4b15c)
1 #define PETSCDM_DLL
2 #include <petsc/private/dmpleximpl.h>    /*I   "petscdmplex.h"   I*/
3 
4 /*@C
5   DMPlexCreateGmshFromFile - Create a DMPlex mesh from a Gmsh file
6 
7 + comm        - The MPI communicator
8 . filename    - Name of the Gmsh file
9 - interpolate - Create faces and edges in the mesh
10 
11   Output Parameter:
12 . dm  - The DM object representing the mesh
13 
14   Level: beginner
15 
16 .seealso: DMPlexCreateFromFile(), DMPlexCreateGmsh(), DMPlexCreate()
17 @*/
18 PetscErrorCode DMPlexCreateGmshFromFile(MPI_Comm comm, const char filename[], PetscBool interpolate, DM *dm)
19 {
20   PetscViewer     viewer;
21   PetscMPIInt     rank;
22   int             fileType;
23   PetscViewerType vtype;
24   PetscErrorCode  ierr;
25 
26   PetscFunctionBegin;
27   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
28 
29   /* Determine Gmsh file type (ASCII or binary) from file header */
30   if (!rank) {
31     PetscViewer vheader;
32     char        line[PETSC_MAX_PATH_LEN];
33     PetscBool   match;
34     int         snum;
35     float       version;
36 
37     ierr = PetscViewerCreate(PETSC_COMM_SELF, &vheader);CHKERRQ(ierr);
38     ierr = PetscViewerSetType(vheader, PETSCVIEWERASCII);CHKERRQ(ierr);
39     ierr = PetscViewerFileSetMode(vheader, FILE_MODE_READ);CHKERRQ(ierr);
40     ierr = PetscViewerFileSetName(vheader, filename);CHKERRQ(ierr);
41     /* Read only the first two lines of the Gmsh file */
42     ierr = PetscViewerRead(vheader, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);
43     ierr = PetscStrncmp(line, "$MeshFormat", sizeof(line), &match);CHKERRQ(ierr);
44     if (!match) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
45     ierr = PetscViewerRead(vheader, line, 2, NULL, PETSC_STRING);CHKERRQ(ierr);
46     snum = sscanf(line, "%f %d", &version, &fileType);
47     if (snum != 2) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Gmsh file header: %s", line);
48     if (version < 2.0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Gmsh file must be at least version 2.0");
49     ierr = PetscViewerDestroy(&vheader);CHKERRQ(ierr);
50   }
51   ierr = MPI_Bcast(&fileType, 1, MPI_INT, 0, comm);CHKERRQ(ierr);
52   vtype = (fileType == 0) ? PETSCVIEWERASCII : PETSCVIEWERBINARY;
53 
54   /* Create appropriate viewer and build plex */
55   ierr = PetscViewerCreate(comm, &viewer);CHKERRQ(ierr);
56   ierr = PetscViewerSetType(viewer, vtype);CHKERRQ(ierr);
57   ierr = PetscViewerFileSetMode(viewer, FILE_MODE_READ);CHKERRQ(ierr);
58   ierr = PetscViewerFileSetName(viewer, filename);CHKERRQ(ierr);
59   ierr = DMPlexCreateGmsh(comm, viewer, interpolate, dm);CHKERRQ(ierr);
60   ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
61   PetscFunctionReturn(0);
62 }
63 
64 static PetscErrorCode DMPlexCreateGmsh_ReadNodes(PetscViewer viewer, PetscBool binary, PetscBool byteSwap, int shift, int numVertices, double **coordinates)
65 {
66   int            v,nid;
67   PetscErrorCode ierr;
68 
69   PetscFunctionBegin;
70   ierr = PetscMalloc1(numVertices*3, coordinates);CHKERRQ(ierr);
71   for (v = 0; v < numVertices; ++v) {
72     double *xyz = *coordinates + v*3;
73     ierr = PetscViewerRead(viewer, &nid, 1, NULL, PETSC_ENUM);CHKERRQ(ierr);
74     if (byteSwap) {ierr = PetscByteSwap(&nid, PETSC_ENUM, 1);CHKERRQ(ierr);}
75     if (nid != v+shift) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unexpected node number %d should be %d", nid, v+shift);
76     ierr = PetscViewerRead(viewer, xyz, 3, NULL, PETSC_DOUBLE);CHKERRQ(ierr);
77     if (byteSwap) {ierr = PetscByteSwap(xyz, PETSC_DOUBLE, 3);CHKERRQ(ierr);}
78   }
79   PetscFunctionReturn(0);
80 }
81 
82 static PetscErrorCode DMPlexCreateGmsh_ReadElements(PetscViewer viewer, PetscBool binary, PetscBool byteSwap, PETSC_UNUSED int shift, int numCells, GmshElement **gmsh_elems)
83 {
84   GmshElement   *elements;
85   int            i, c, p, ibuf[1+4+512];
86   int            cellType, dim, numNodes, numNodesIgnore, numElem, numTags;
87   PetscErrorCode ierr;
88 
89   PetscFunctionBegin;
90   ierr = PetscMalloc1(numCells, &elements);CHKERRQ(ierr);
91   for (c = 0; c < numCells;) {
92     ierr = PetscViewerRead(viewer, ibuf, 3, NULL, PETSC_ENUM);CHKERRQ(ierr);
93     if (byteSwap) {ierr = PetscByteSwap(ibuf, PETSC_ENUM, 3);CHKERRQ(ierr);}
94     if (binary) {
95       cellType = ibuf[0];
96       numElem = ibuf[1];
97       numTags = ibuf[2];
98     } else {
99       elements[c].id = ibuf[0];
100       cellType = ibuf[1];
101       numTags = ibuf[2];
102       numElem = 1;
103     }
104     /* http://gmsh.info/doc/texinfo/gmsh.html#MSH-ASCII-file-format */
105     numNodesIgnore = 0;
106     switch (cellType) {
107     case 1: /* 2-node line */
108       dim = 1;
109       numNodes = 2;
110       break;
111     case 2: /* 3-node triangle */
112       dim = 2;
113       numNodes = 3;
114       break;
115     case 3: /* 4-node quadrangle */
116       dim = 2;
117       numNodes = 4;
118       break;
119     case 4: /* 4-node tetrahedron */
120       dim  = 3;
121       numNodes = 4;
122       break;
123     case 5: /* 8-node hexahedron */
124       dim = 3;
125       numNodes = 8;
126       break;
127     case 8: /* 3-node 2nd order line */
128       dim = 1;
129       numNodes = 2;
130       numNodesIgnore = 1;
131       break;
132     case 9: /* 6-node 2nd order triangle */
133       dim = 2;
134       numNodes = 3;
135       numNodesIgnore = 3;
136       break;
137     case 15: /* 1-node vertex */
138       dim = 0;
139       numNodes = 1;
140       break;
141     case 6: /* 6-node prism */
142     case 7: /* 5-node pyramid */
143     case 10: /* 9-node 2nd order quadrangle */
144     case 11: /* 10-node 2nd order tetrahedron */
145     case 12: /* 27-node 2nd order hexhedron */
146     case 13: /* 19-node 2nd order prism */
147     case 14: /* 14-node 2nd order pyramid */
148     default:
149       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported Gmsh element type %d", cellType);
150     }
151     if (binary) {
152       const int nint = 1 + numTags + numNodes + numNodesIgnore;
153       /* Loop over element blocks */
154       for (i = 0; i < numElem; ++i, ++c) {
155         ierr = PetscViewerRead(viewer, ibuf, nint, NULL, PETSC_ENUM);CHKERRQ(ierr);
156         if (byteSwap) {ierr = PetscByteSwap(ibuf, PETSC_ENUM, nint);CHKERRQ(ierr);}
157         elements[c].dim = dim;
158         elements[c].numNodes = numNodes;
159         elements[c].numTags = numTags;
160         elements[c].id = ibuf[0];
161         for (p = 0; p < numTags; p++) elements[c].tags[p] = ibuf[1 + p];
162         for (p = 0; p < numNodes; p++) elements[c].nodes[p] = ibuf[1 + numTags + p];
163       }
164     } else {
165       elements[c].dim = dim;
166       elements[c].numNodes = numNodes;
167       elements[c].numTags = numTags;
168       ierr = PetscViewerRead(viewer, elements[c].tags, elements[c].numTags, NULL, PETSC_ENUM);CHKERRQ(ierr);
169       ierr = PetscViewerRead(viewer, elements[c].nodes, elements[c].numNodes, NULL, PETSC_ENUM);CHKERRQ(ierr);
170       ierr = PetscViewerRead(viewer, ibuf, numNodesIgnore, NULL, PETSC_ENUM);CHKERRQ(ierr);
171       c++;
172     }
173   }
174   *gmsh_elems = elements;
175   PetscFunctionReturn(0);
176 }
177 
178 /*@
179   DMPlexCreateGmsh - Create a DMPlex mesh from a Gmsh file viewer
180 
181   Collective on comm
182 
183   Input Parameters:
184 + comm  - The MPI communicator
185 . viewer - The Viewer associated with a Gmsh file
186 - interpolate - Create faces and edges in the mesh
187 
188   Output Parameter:
189 . dm  - The DM object representing the mesh
190 
191   Note: http://www.geuz.org/gmsh/doc/texinfo/#MSH-ASCII-file-format
192   and http://www.geuz.org/gmsh/doc/texinfo/#MSH-binary-file-format
193 
194   Level: beginner
195 
196 .keywords: mesh,Gmsh
197 .seealso: DMPLEX, DMCreate()
198 @*/
199 PetscErrorCode DMPlexCreateGmsh(MPI_Comm comm, PetscViewer viewer, PetscBool interpolate, DM *dm)
200 {
201   PetscViewer    parentviewer = NULL;
202   double        *coordsIn = NULL;
203   GmshElement   *gmsh_elem = NULL;
204   PetscSection   coordSection;
205   Vec            coordinates;
206   PetscBT        periodicV = NULL, periodicC = NULL;
207   PetscScalar   *coords;
208   PetscInt       dim = 0, embedDim, coordSize, c, v, d, r, cell, *periodicMap = NULL, *periodicMapI = NULL;
209   int            i, numVertices = 0, numCells = 0, trueNumCells = 0, numRegions = 0, snum, shift = 1;
210   PetscMPIInt    rank;
211   char           line[PETSC_MAX_PATH_LEN];
212   PetscBool      binary, mpiio, byteSwap = PETSC_FALSE, zerobase = PETSC_FALSE, isbd = PETSC_FALSE, periodic = PETSC_FALSE, usemarker = PETSC_FALSE;
213   PetscErrorCode ierr;
214 
215   PetscFunctionBegin;
216   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
217   ierr = PetscOptionsGetBool(NULL, NULL, "-dm_plex_gmsh_periodic", &periodic, NULL);CHKERRQ(ierr);
218   ierr = PetscOptionsGetBool(NULL, NULL, "-dm_plex_gmsh_usemarker", &usemarker, NULL);CHKERRQ(ierr);
219   ierr = PetscOptionsGetBool(NULL, NULL, "-gmsh_zero_base", &zerobase, NULL);CHKERRQ(ierr);
220   ierr = PetscOptionsGetBool(NULL, NULL, "-gmsh_bd", &isbd, NULL);CHKERRQ(ierr);
221   if (zerobase) shift = 0;
222 
223   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
224   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
225   ierr = PetscLogEventBegin(DMPLEX_CreateGmsh,*dm,0,0,0);CHKERRQ(ierr);
226 
227   ierr = PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &binary);CHKERRQ(ierr);
228   ierr = PetscViewerBinaryGetUseMPIIO(viewer, &mpiio);CHKERRQ(ierr);
229 
230   /* Binary viewers read on all ranks, get subviewer to read only in rank 0 */
231   if (binary && !mpiio) {
232     parentviewer = viewer;
233     ierr = PetscViewerGetSubViewer(parentviewer, PETSC_COMM_SELF, &viewer);CHKERRQ(ierr);
234   }
235 
236   if (!rank || mpiio) {
237     PetscBool match;
238     int       fileType, dataSize;
239     float     version;
240 
241     /* Read header */
242     ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);
243     ierr = PetscStrncmp(line, "$MeshFormat", PETSC_MAX_PATH_LEN, &match);CHKERRQ(ierr);
244     if (!match) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
245     ierr = PetscViewerRead(viewer, line, 3, NULL, PETSC_STRING);CHKERRQ(ierr);
246     snum = sscanf(line, "%f %d %d", &version, &fileType, &dataSize);
247     if (snum != 3) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Gmsh file header: %s", line);
248     if (version < 2.0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Gmsh file must be at least version 2.0");
249     if (dataSize != sizeof(double)) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Data size %d is not valid for a Gmsh file", dataSize);
250     if (binary) {
251       int checkInt;
252       ierr = PetscViewerRead(viewer, &checkInt, 1, NULL, PETSC_ENUM);CHKERRQ(ierr);
253       if (checkInt != 1) {
254         ierr = PetscByteSwap(&checkInt, PETSC_ENUM, 1);CHKERRQ(ierr);
255         if (checkInt == 1) byteSwap = PETSC_TRUE;
256         else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File type %d is not a valid Gmsh binary file", fileType);
257       }
258     } else if (fileType) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File type %d is not a valid Gmsh ASCII file", fileType);
259     ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);
260     ierr = PetscStrncmp(line, "$EndMeshFormat", PETSC_MAX_PATH_LEN, &match);CHKERRQ(ierr);
261     if (!match) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
262 
263     /* OPTIONAL Read physical names */
264     ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);
265     ierr = PetscStrncmp(line, "$PhysicalNames", PETSC_MAX_PATH_LEN, &match);CHKERRQ(ierr);
266     if (match) {
267       ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);
268       snum = sscanf(line, "%d", &numRegions);
269       if (snum != 1) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
270       for (r = 0; r < numRegions; ++r) {
271         ierr = PetscViewerRead(viewer, line, 3, NULL, PETSC_STRING);CHKERRQ(ierr);
272       }
273       ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);
274       ierr = PetscStrncmp(line, "$EndPhysicalNames", PETSC_MAX_PATH_LEN, &match);CHKERRQ(ierr);
275       if (!match) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
276       /* Initial read for vertex section */
277       ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);
278     }
279 
280     /* Read vertices */
281     ierr = PetscStrncmp(line, "$Nodes", PETSC_MAX_PATH_LEN, &match);CHKERRQ(ierr);
282     if (!match) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
283     ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);
284     snum = sscanf(line, "%d", &numVertices);
285     if (snum != 1) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
286     ierr = DMPlexCreateGmsh_ReadNodes(viewer, binary, byteSwap, shift, numVertices, &coordsIn);CHKERRQ(ierr);
287     ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);;
288     ierr = PetscStrncmp(line, "$EndNodes", PETSC_MAX_PATH_LEN, &match);CHKERRQ(ierr);
289     if (!match) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
290 
291     /* Read cells */
292     ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);;
293     ierr = PetscStrncmp(line, "$Elements", PETSC_MAX_PATH_LEN, &match);CHKERRQ(ierr);
294     if (!match) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
295     ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);;
296     snum = sscanf(line, "%d", &numCells);
297     if (snum != 1) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
298     /* Gmsh elements can be of any dimension/co-dimension, so we need to traverse the
299        file contents multiple times to figure out the true number of cells and facets
300        in the given mesh. To make this more efficient we read the file contents only
301        once and store them in memory, while determining the true number of cells. */
302     ierr = DMPlexCreateGmsh_ReadElements(viewer, binary, byteSwap, shift, numCells, &gmsh_elem);CHKERRQ(ierr);
303     for (trueNumCells=0, c = 0; c < numCells; ++c) {
304       if (gmsh_elem[c].dim > dim) {dim = gmsh_elem[c].dim; trueNumCells = 0;}
305       if (gmsh_elem[c].dim == dim) trueNumCells++;
306     }
307     ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);
308     ierr = PetscStrncmp(line, "$EndElements", 12, &match);CHKERRQ(ierr);
309     if (!match) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
310 
311     /* OPTIONAL Read periodic section */
312     if (periodic) {
313       PetscInt pVert, *periodicMapT, *aux;
314       int      numPeriodic;
315 
316       ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);
317       ierr = PetscStrncmp(line, "$Periodic", 9, &match);CHKERRQ(ierr);
318       if (!match) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
319       ierr = PetscMalloc1(numVertices, &periodicMapT);CHKERRQ(ierr);
320       ierr = PetscBTCreate(numVertices, &periodicV);CHKERRQ(ierr);
321       for (i = 0; i < numVertices; i++) periodicMapT[i] = i;
322       ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);
323       snum = sscanf(line, "%d", &numPeriodic);
324       if (snum != 1) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
325       for (i = 0; i < numPeriodic; i++) {
326         int j, edim = -1, slaveTag = -1, masterTag = -1, nNodes;
327 
328         ierr = PetscViewerRead(viewer, line, 3, NULL, PETSC_STRING);CHKERRQ(ierr);
329         snum = sscanf(line, "%d %d %d", &edim, &slaveTag, &masterTag); /* slaveTag and masterTag are unused */
330         if (snum != 3) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
331         /* Type of tranformation, discarded */
332         ierr = PetscViewerRead(viewer, line, -PETSC_MAX_PATH_LEN, NULL, PETSC_STRING);CHKERRQ(ierr);
333         ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);
334         snum = sscanf(line, "%d", &nNodes);
335         if (snum != 1) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
336         for (j = 0; j < nNodes; j++) {
337           int slaveNode, masterNode;
338 
339           ierr = PetscViewerRead(viewer, line, 2, NULL, PETSC_STRING);CHKERRQ(ierr);
340           snum = sscanf(line, "%d %d", &slaveNode, &masterNode);
341           if (snum != 2) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
342           periodicMapT[slaveNode - shift] = masterNode - shift;
343           ierr = PetscBTSet(periodicV, slaveNode - shift);CHKERRQ(ierr);
344           ierr = PetscBTSet(periodicV, masterNode - shift);CHKERRQ(ierr);
345         }
346       }
347       ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);
348       ierr = PetscStrncmp(line, "$EndPeriodic", 12, &match);CHKERRQ(ierr);
349       if (!match) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
350       /* we may have slaves of slaves */
351       for (i = 0; i < numVertices; i++) {
352         while (periodicMapT[periodicMapT[i]] != periodicMapT[i]) {
353           periodicMapT[i] = periodicMapT[periodicMapT[i]];
354         }
355       }
356       /* periodicMap : from old to new numbering (periodic vertices excluded)
357          periodicMapI: from new to old numbering */
358       ierr = PetscMalloc1(numVertices, &periodicMap);CHKERRQ(ierr);
359       ierr = PetscMalloc1(numVertices, &periodicMapI);CHKERRQ(ierr);
360       ierr = PetscMalloc1(numVertices, &aux);CHKERRQ(ierr);
361       for (i = 0, pVert = 0; i < numVertices; i++) {
362         if (periodicMapT[i] != i) {
363           pVert++;
364         } else {
365           aux[i] = i - pVert;
366           periodicMapI[i - pVert] = i;
367         }
368       }
369       for (i = 0 ; i < numVertices; i++) {
370         periodicMap[i] = aux[periodicMapT[i]];
371       }
372       ierr = PetscFree(periodicMapT);CHKERRQ(ierr);
373       ierr = PetscFree(aux);CHKERRQ(ierr);
374       /* remove periodic vertices */
375       numVertices = numVertices - pVert;
376     }
377   }
378 
379   /* For (binary) MPI I/O we read on all ranks, but only build the plex on rank 0 */
380   if (mpiio && rank) {
381     numVertices = 0; numCells = 0; trueNumCells = 0;
382     ierr = PetscFree(periodicMap);CHKERRQ(ierr);
383     ierr = PetscFree(periodicMapI);CHKERRQ(ierr);
384   }
385 
386   if (parentviewer) {
387     ierr = PetscViewerRestoreSubViewer(parentviewer, PETSC_COMM_SELF, &viewer);CHKERRQ(ierr);
388   }
389 
390   /* Allocate the cell-vertex mesh */
391   ierr = DMPlexSetChart(*dm, 0, trueNumCells+numVertices);CHKERRQ(ierr);
392   for (cell = 0, c = 0; c < numCells; ++c) {
393     if (gmsh_elem[c].dim == dim) {
394       ierr = DMPlexSetConeSize(*dm, cell, gmsh_elem[c].numNodes);CHKERRQ(ierr);
395       cell++;
396     }
397   }
398   ierr = DMSetUp(*dm);CHKERRQ(ierr);
399   /* Add cell-vertex connections */
400   for (cell = 0, c = 0; c < numCells; ++c) {
401     if (gmsh_elem[c].dim == dim) {
402       PetscInt pcone[8], corner;
403       for (corner = 0; corner < gmsh_elem[c].numNodes; ++corner) {
404         const PetscInt cc = gmsh_elem[c].nodes[corner] - shift;
405         pcone[corner] = (periodicMap ? periodicMap[cc] : cc) + trueNumCells;
406       }
407       if (dim == 3) {
408         /* Tetrahedra are inverted */
409         if (gmsh_elem[c].numNodes == 4) {
410           PetscInt tmp = pcone[0];
411           pcone[0] = pcone[1];
412           pcone[1] = tmp;
413         }
414         /* Hexahedra are inverted */
415         if (gmsh_elem[c].numNodes == 8) {
416           PetscInt tmp = pcone[1];
417           pcone[1] = pcone[3];
418           pcone[3] = tmp;
419         }
420       }
421       ierr = DMPlexSetCone(*dm, cell, pcone);CHKERRQ(ierr);
422       cell++;
423     }
424   }
425   ierr = MPI_Bcast(&dim, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
426   ierr = DMSetDimension(*dm, dim);CHKERRQ(ierr);
427   ierr = DMPlexSymmetrize(*dm);CHKERRQ(ierr);
428   ierr = DMPlexStratify(*dm);CHKERRQ(ierr);
429   if (interpolate) {
430     DM idm = NULL;
431 
432     ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr);
433     ierr = DMDestroy(dm);CHKERRQ(ierr);
434     *dm  = idm;
435   }
436 
437   if (!rank && usemarker) {
438     PetscInt f, fStart, fEnd;
439 
440     ierr = DMCreateLabel(*dm, "marker");CHKERRQ(ierr);
441     ierr = DMPlexGetHeightStratum(*dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
442     for (f = fStart; f < fEnd; ++f) {
443       PetscInt suppSize;
444 
445       ierr = DMPlexGetSupportSize(*dm, f, &suppSize);CHKERRQ(ierr);
446       if (suppSize == 1) {
447         PetscInt *cone = NULL, coneSize, p;
448 
449         ierr = DMPlexGetTransitiveClosure(*dm, f, PETSC_TRUE, &coneSize, &cone);CHKERRQ(ierr);
450         for (p = 0; p < coneSize; p += 2) {
451           ierr = DMSetLabelValue(*dm, "marker", cone[p], 1);CHKERRQ(ierr);
452         }
453         ierr = DMPlexRestoreTransitiveClosure(*dm, f, PETSC_TRUE, &coneSize, &cone);CHKERRQ(ierr);
454       }
455     }
456   }
457 
458   if (!rank) {
459     PetscInt vStart, vEnd;
460 
461     ierr = DMPlexGetDepthStratum(*dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
462     for (cell = 0, c = 0; c < numCells; ++c) {
463 
464       /* Create face sets */
465       if (gmsh_elem[c].dim == dim-1) {
466         const PetscInt *join;
467         PetscInt        joinSize, pcone[8], corner;
468         /* Find the relevant facet with vertex joins */
469         for (corner = 0; corner < gmsh_elem[c].numNodes; ++corner) {
470           const PetscInt cc = gmsh_elem[c].nodes[corner] - shift;
471           pcone[corner] = (periodicMap ? periodicMap[cc] : cc) + vStart;
472         }
473         ierr = DMPlexGetFullJoin(*dm, gmsh_elem[c].numNodes, pcone, &joinSize, &join);CHKERRQ(ierr);
474         if (joinSize != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not determine Plex facet for element %d", gmsh_elem[c].id);
475         ierr = DMSetLabelValue(*dm, "Face Sets", join[0], gmsh_elem[c].tags[0]);CHKERRQ(ierr);
476         ierr = DMPlexRestoreJoin(*dm, gmsh_elem[c].numNodes, (const PetscInt *) pcone, &joinSize, &join);CHKERRQ(ierr);
477       }
478 
479       /* Create cell sets */
480       if (gmsh_elem[c].dim == dim) {
481         if (gmsh_elem[c].numTags > 0) {
482           ierr = DMSetLabelValue(*dm, "Cell Sets", cell, gmsh_elem[c].tags[0]);CHKERRQ(ierr);
483         }
484         cell++;
485       }
486 
487       /* Create vertex sets */
488       if (gmsh_elem[c].dim == 0) {
489         if (gmsh_elem[c].numTags > 0) {
490           const PetscInt cc = gmsh_elem[c].nodes[0] - shift;
491           const PetscInt vid = (periodicMap ? periodicMap[cc] : cc) + vStart;
492           ierr = DMSetLabelValue(*dm, "Vertex Sets", vid, gmsh_elem[c].tags[0]);CHKERRQ(ierr);
493         }
494       }
495     }
496   }
497 
498   /* Create coordinates */
499   embedDim = isbd ? dim+1 : dim;
500   ierr = DMGetCoordinateSection(*dm, &coordSection);CHKERRQ(ierr);
501   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
502   ierr = PetscSectionSetFieldComponents(coordSection, 0, embedDim);CHKERRQ(ierr);
503   if (periodicMap) { /* we need to localize coordinates on cells */
504     ierr = PetscSectionSetChart(coordSection, 0, trueNumCells + numVertices);CHKERRQ(ierr);
505   } else {
506     ierr = PetscSectionSetChart(coordSection, trueNumCells, trueNumCells + numVertices);CHKERRQ(ierr);
507   }
508   for (v = trueNumCells; v < trueNumCells+numVertices; ++v) {
509     ierr = PetscSectionSetDof(coordSection, v, embedDim);CHKERRQ(ierr);
510     ierr = PetscSectionSetFieldDof(coordSection, v, 0, embedDim);CHKERRQ(ierr);
511   }
512   if (periodicMap) {
513     ierr = PetscBTCreate(trueNumCells, &periodicC);CHKERRQ(ierr);
514     for (cell = 0, c = 0; c < numCells; ++c) {
515       if (gmsh_elem[c].dim == dim) {
516         PetscInt  corner;
517         PetscBool pc = PETSC_FALSE;
518         for (corner = 0; corner < gmsh_elem[c].numNodes; ++corner) {
519           pc = (PetscBool)(pc || PetscBTLookup(periodicV, gmsh_elem[c].nodes[corner] - shift));
520         }
521         if (pc) {
522           PetscInt dof = gmsh_elem[c].numNodes*embedDim;
523           ierr = PetscBTSet(periodicC, cell);CHKERRQ(ierr);
524           ierr = PetscSectionSetDof(coordSection, cell, dof);CHKERRQ(ierr);
525           ierr = PetscSectionSetFieldDof(coordSection, cell, 0, dof);CHKERRQ(ierr);
526         }
527         cell++;
528       }
529     }
530   }
531   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
532   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
533   ierr = VecCreate(PETSC_COMM_SELF, &coordinates);CHKERRQ(ierr);
534   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
535   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
536   ierr = VecSetBlockSize(coordinates, embedDim);CHKERRQ(ierr);
537   ierr = VecSetType(coordinates, VECSTANDARD);CHKERRQ(ierr);
538   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
539   if (periodicMap) {
540     PetscInt off;
541 
542     for (cell = 0, c = 0; c < numCells; ++c) {
543       PetscInt pcone[8], corner;
544       if (gmsh_elem[c].dim == dim) {
545         if (PetscUnlikely(PetscBTLookup(periodicC, cell))) {
546           for (corner = 0; corner < gmsh_elem[c].numNodes; ++corner) {
547             pcone[corner] = gmsh_elem[c].nodes[corner] - shift;
548           }
549           if (dim == 3) {
550             /* Tetrahedra are inverted */
551             if (gmsh_elem[c].numNodes == 4) {
552               PetscInt tmp = pcone[0];
553               pcone[0] = pcone[1];
554               pcone[1] = tmp;
555             }
556             /* Hexahedra are inverted */
557             if (gmsh_elem[c].numNodes == 8) {
558               PetscInt tmp = pcone[1];
559               pcone[1] = pcone[3];
560               pcone[3] = tmp;
561             }
562           }
563           ierr = PetscSectionGetOffset(coordSection, cell, &off);CHKERRQ(ierr);
564           for (corner = 0; corner < gmsh_elem[c].numNodes; ++corner) {
565             v = pcone[corner];
566             for (d = 0; d < embedDim; ++d) {
567               coords[off++] = (PetscReal) coordsIn[v*3+d];
568             }
569           }
570         }
571         cell++;
572       }
573     }
574     for (v = 0; v < numVertices; ++v) {
575       ierr = PetscSectionGetOffset(coordSection, v + trueNumCells, &off);CHKERRQ(ierr);
576       for (d = 0; d < embedDim; ++d) {
577         coords[off+d] = (PetscReal) coordsIn[periodicMapI[v]*3+d];
578       }
579     }
580   } else {
581     for (v = 0; v < numVertices; ++v) {
582       for (d = 0; d < embedDim; ++d) {
583         coords[v*embedDim+d] = (PetscReal) coordsIn[v*3+d];
584       }
585     }
586   }
587   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
588   ierr = DMSetCoordinatesLocal(*dm, coordinates);CHKERRQ(ierr);
589   ierr = DMSetPeriodicity(*dm, periodic, NULL, NULL, NULL);CHKERRQ(ierr);
590 
591   ierr = PetscFree(coordsIn);CHKERRQ(ierr);
592   ierr = PetscFree(gmsh_elem);CHKERRQ(ierr);
593   ierr = PetscFree(periodicMap);CHKERRQ(ierr);
594   ierr = PetscFree(periodicMapI);CHKERRQ(ierr);
595   ierr = PetscBTDestroy(&periodicV);CHKERRQ(ierr);
596   ierr = PetscBTDestroy(&periodicC);CHKERRQ(ierr);
597   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
598 
599   ierr = PetscLogEventEnd(DMPLEX_CreateGmsh,*dm,0,0,0);CHKERRQ(ierr);
600   PetscFunctionReturn(0);
601 }
602