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