xref: /petsc/src/dm/impls/plex/plexgmsh.c (revision 12b8b152df104b41bf3dbbfc4ea0d1b23f6f600a)
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;
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;
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_periodic_gmsh",&periodic,NULL);CHKERRQ(ierr);
206   if (!rank || binary) {
207     PetscBool match;
208     int       fileType, dataSize;
209     float     version;
210 
211     /* Read header */
212     ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);
213     ierr = PetscStrncmp(line, "$MeshFormat", PETSC_MAX_PATH_LEN, &match);CHKERRQ(ierr);
214     if (!match) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
215     ierr = PetscViewerRead(viewer, line, 3, NULL, PETSC_STRING);CHKERRQ(ierr);
216     snum = sscanf(line, "%f %d %d", &version, &fileType, &dataSize);
217     if (snum != 3) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unable to parse Gmsh file header: %s", line);
218     if (version < 2.0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Gmsh file must be at least version 2.0");
219     if (dataSize != sizeof(double)) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Data size %d is not valid for a Gmsh file", dataSize);
220     if (binary) {
221       int checkInt;
222       ierr = PetscViewerRead(viewer, &checkInt, 1, NULL, PETSC_ENUM);CHKERRQ(ierr);
223       if (checkInt != 1) {
224         ierr = PetscByteSwap(&checkInt, PETSC_ENUM, 1);CHKERRQ(ierr);
225         if (checkInt == 1) bswap = PETSC_TRUE;
226         else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File type %d is not a valid Gmsh binary file", fileType);
227       }
228     } else if (fileType) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File type %d is not a valid Gmsh ASCII file", fileType);
229     ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);
230     ierr = PetscStrncmp(line, "$EndMeshFormat", PETSC_MAX_PATH_LEN, &match);CHKERRQ(ierr);
231     if (!match) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
232     /* OPTIONAL Read physical names */
233     ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);
234     ierr = PetscStrncmp(line, "$PhysicalNames", PETSC_MAX_PATH_LEN, &match);CHKERRQ(ierr);
235     if (match) {
236       ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);
237       snum = sscanf(line, "%d", &numRegions);
238       if (snum != 1) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
239       for (r = 0; r < numRegions; ++r) {ierr = PetscViewerRead(viewer, line, 3, NULL, PETSC_STRING);CHKERRQ(ierr);}
240       ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);
241       ierr = PetscStrncmp(line, "$EndPhysicalNames", PETSC_MAX_PATH_LEN, &match);CHKERRQ(ierr);
242       if (!match) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
243       /* Initial read for vertex section */
244       ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);
245     }
246     /* Read vertices */
247     ierr = PetscStrncmp(line, "$Nodes", PETSC_MAX_PATH_LEN, &match);CHKERRQ(ierr);
248     if (!match) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
249     ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);
250     snum = sscanf(line, "%d", &numVertices);
251     if (snum != 1) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
252     ierr = PetscMalloc1(numVertices*3, &coordsIn);CHKERRQ(ierr);
253     if (binary) {
254       size_t doubleSize, intSize;
255       PetscInt elementSize;
256       char *buffer;
257       PetscScalar *baseptr;
258       ierr = PetscDataTypeGetSize(PETSC_ENUM, &intSize);CHKERRQ(ierr);
259       ierr = PetscDataTypeGetSize(PETSC_DOUBLE, &doubleSize);CHKERRQ(ierr);
260       elementSize = (intSize + 3*doubleSize);
261       ierr = PetscMalloc1(elementSize*numVertices, &buffer);CHKERRQ(ierr);
262       ierr = PetscViewerRead(viewer, buffer, elementSize*numVertices, NULL, PETSC_CHAR);CHKERRQ(ierr);
263       if (bswap) ierr = PetscByteSwap(buffer, PETSC_CHAR, elementSize*numVertices);CHKERRQ(ierr);
264       for (v = 0; v < numVertices; ++v) {
265         baseptr = ((PetscScalar*)(buffer+v*elementSize+intSize));
266         coordsIn[v*3+0] = baseptr[0];
267         coordsIn[v*3+1] = baseptr[1];
268         coordsIn[v*3+2] = baseptr[2];
269       }
270       ierr = PetscFree(buffer);CHKERRQ(ierr);
271     } else {
272       for (v = 0; v < numVertices; ++v) {
273         ierr = PetscViewerRead(viewer, &i, 1, NULL, PETSC_ENUM);CHKERRQ(ierr);
274         ierr = PetscViewerRead(viewer, &(coordsIn[v*3]), 3, NULL, PETSC_DOUBLE);CHKERRQ(ierr);
275         if (i != (int)v+1) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid node number %d should be %d", i, v+1);
276       }
277     }
278     ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);;
279     ierr = PetscStrncmp(line, "$EndNodes", PETSC_MAX_PATH_LEN, &match);CHKERRQ(ierr);
280     if (!match) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
281     /* Read cells */
282     ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);;
283     ierr = PetscStrncmp(line, "$Elements", PETSC_MAX_PATH_LEN, &match);CHKERRQ(ierr);
284     if (!match) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
285     ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);;
286     snum = sscanf(line, "%d", &numCells);
287     if (snum != 1) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
288   }
289 
290   if (!rank || binary) {
291     /* Gmsh elements can be of any dimension/co-dimension, so we need to traverse the
292        file contents multiple times to figure out the true number of cells and facets
293        in the given mesh. To make this more efficient we read the file contents only
294        once and store them in memory, while determining the true number of cells. */
295     ierr = DMPlexCreateGmsh_ReadElement(viewer, numCells, binary, bswap, &gmsh_elem);CHKERRQ(ierr);
296     for (trueNumCells=0, c = 0; c < numCells; ++c) {
297       if (gmsh_elem[c].dim > dim) {dim = gmsh_elem[c].dim; trueNumCells = 0;}
298       if (gmsh_elem[c].dim == dim) trueNumCells++;
299     }
300     ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);
301     ierr = PetscStrncmp(line, "$EndElements", 12, &match);CHKERRQ(ierr);
302     if (!match) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
303     if (periodic) {
304       int numPeriodic;
305 
306       ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);
307       ierr = PetscStrncmp(line, "$Periodic", 9, &match);CHKERRQ(ierr);
308       if (!match) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
309       ierr = PetscMalloc1(numVertices, &periodicMap);CHKERRQ(ierr);
310       for (i = 0; i < numVertices; i++) periodicMap[i] = i;
311       ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);
312       snum = sscanf(line, "%d", &numPeriodic);
313       if (snum != 1) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
314       for (i = 0; i < numPeriodic; i++) {
315         int j, edim = -1, slaveTag = -1, masterTag = -1, nNodes;
316 
317         ierr = PetscViewerRead(viewer, line, 3, NULL, PETSC_STRING);CHKERRQ(ierr);
318         snum = sscanf(line, "%d %d %d", &edim, &slaveTag, &masterTag); /* slaveTag and masterTag are unused */
319         if (snum != 3) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
320         ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);
321         snum = sscanf(line, "%d", &nNodes);
322         if (snum != 1) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
323         for (j = 0; j < nNodes; j++) {
324           PetscInt slaveNode, masterNode;
325 
326           ierr = PetscViewerRead(viewer, line, 2, NULL, PETSC_STRING);CHKERRQ(ierr);
327           snum = sscanf(line, "%d %d", &slaveNode, &masterNode);
328           if (snum != 2) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
329           periodicMap[slaveNode - 1] = masterNode - 1;
330         }
331       }
332       ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);
333       ierr = PetscStrncmp(line, "$EndPeriodic", 12, &match);CHKERRQ(ierr);
334       if (!match) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "File is not a valid Gmsh file");
335       /* we may have slaves of slaves */
336       for (i = 0; i < numVertices; i++) {
337         while (periodicMap[periodicMap[i]] != periodicMap[i]) {
338           periodicMap[i] = periodicMap[periodicMap[i]];
339         }
340       }
341     }
342   }
343   /* For binary we read on all ranks, but only build the plex on rank 0 */
344   if (binary && rank) {trueNumCells = 0; numVertices = 0;};
345   /* Allocate the cell-vertex mesh */
346   ierr = DMPlexSetChart(*dm, 0, trueNumCells+numVertices);CHKERRQ(ierr);
347   if (!rank) {
348     for (cell = 0, c = 0; c < numCells; ++c) {
349       if (gmsh_elem[c].dim == dim) {
350         ierr = DMPlexSetConeSize(*dm, cell, gmsh_elem[c].numNodes);CHKERRQ(ierr);
351         cell++;
352       }
353     }
354   }
355   ierr = DMSetUp(*dm);CHKERRQ(ierr);
356   /* Add cell-vertex connections */
357   if (!rank) {
358     PetscInt pcone[8], corner;
359     for (cell = 0, c = 0; c < numCells; ++c) {
360       if (gmsh_elem[c].dim == dim) {
361         for (corner = 0; corner < gmsh_elem[c].numNodes; ++corner) {
362           pcone[corner] = periodicMap ? periodicMap[gmsh_elem[c].nodes[corner] - 1] + trueNumCells
363                                       : gmsh_elem[c].nodes[corner] -1 + trueNumCells;
364         }
365         if (dim == 3) {
366           /* Tetrahedra are inverted */
367           if (gmsh_elem[c].numNodes == 4) {
368             PetscInt tmp = pcone[0];
369             pcone[0] = pcone[1];
370             pcone[1] = tmp;
371           }
372           /* Hexahedra are inverted */
373           if (gmsh_elem[c].numNodes == 8) {
374             PetscInt tmp = pcone[1];
375             pcone[1] = pcone[3];
376             pcone[3] = tmp;
377           }
378         }
379         ierr = DMPlexSetCone(*dm, cell, pcone);CHKERRQ(ierr);
380         cell++;
381       }
382     }
383   }
384   ierr = MPI_Bcast(&dim, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
385   ierr = DMSetDimension(*dm, dim);CHKERRQ(ierr);
386   ierr = DMPlexSymmetrize(*dm);CHKERRQ(ierr);
387   ierr = DMPlexStratify(*dm);CHKERRQ(ierr);
388   if (interpolate) {
389     DM idm = NULL;
390 
391     ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr);
392     ierr = DMDestroy(dm);CHKERRQ(ierr);
393     *dm  = idm;
394   }
395 
396   if (!rank) {
397     /* Apply boundary IDs by finding the relevant facets with vertex joins */
398     PetscInt pcone[8], corner, vStart, vEnd;
399 
400     ierr = DMPlexGetDepthStratum(*dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
401     for (c = 0; c < numCells; ++c) {
402       if (gmsh_elem[c].dim == dim-1) {
403         PetscInt joinSize;
404         const PetscInt *join;
405         for (corner = 0; corner < gmsh_elem[c].numNodes; ++corner) {
406           pcone[corner] = periodicMap ? periodicMap[gmsh_elem[c].nodes[corner] - 1] + vStart
407                                       : gmsh_elem[c].nodes[corner] - 1 + vStart;
408         }
409         ierr = DMPlexGetFullJoin(*dm, gmsh_elem[c].numNodes, (const PetscInt *) pcone, &joinSize, &join);CHKERRQ(ierr);
410         if (joinSize != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not determine Plex facet for element %d", gmsh_elem[c].id);
411         ierr = DMSetLabelValue(*dm, "Face Sets", join[0], gmsh_elem[c].tags[0]);CHKERRQ(ierr);
412         ierr = DMPlexRestoreJoin(*dm, gmsh_elem[c].numNodes, (const PetscInt *) pcone, &joinSize, &join);CHKERRQ(ierr);
413       }
414     }
415 
416     /* Create cell sets */
417     for (cell = 0, c = 0; c < numCells; ++c) {
418       if (gmsh_elem[c].dim == dim) {
419         if (gmsh_elem[c].numTags > 0) {
420           ierr = DMSetLabelValue(*dm, "Cell Sets", cell, gmsh_elem[c].tags[0]);CHKERRQ(ierr);
421           cell++;
422         }
423       }
424     }
425 
426     /* Create vertex sets */
427     for (c = 0; c < numCells; ++c) {
428       if (gmsh_elem[c].dim == 0) {
429         if (gmsh_elem[c].numTags > 0) {
430           PetscInt vid =  periodicMap ? periodicMap[gmsh_elem[c].nodes[0] - 1] + vStart
431                                       : gmsh_elem[c].nodes[0] - 1 + vStart;
432           ierr = DMSetLabelValue(*dm, "Vertex Sets", vid, gmsh_elem[c].tags[0]);CHKERRQ(ierr);
433         }
434       }
435     }
436   }
437 
438   /* Read coordinates */
439   ierr = DMGetCoordinateSection(*dm, &coordSection);CHKERRQ(ierr);
440   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
441   ierr = PetscSectionSetFieldComponents(coordSection, 0, dim);CHKERRQ(ierr);
442   ierr = PetscSectionSetChart(coordSection, trueNumCells, trueNumCells + numVertices);CHKERRQ(ierr);
443   for (v = trueNumCells; v < trueNumCells+numVertices; ++v) {
444     ierr = PetscSectionSetDof(coordSection, v, dim);CHKERRQ(ierr);
445     ierr = PetscSectionSetFieldDof(coordSection, v, 0, dim);CHKERRQ(ierr);
446   }
447   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
448   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
449   ierr = VecCreate(PETSC_COMM_SELF, &coordinates);CHKERRQ(ierr);
450   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
451   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
452   ierr = VecSetBlockSize(coordinates, dim);CHKERRQ(ierr);
453   ierr = VecSetType(coordinates, VECSTANDARD);CHKERRQ(ierr);
454   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
455   if (!rank) {
456     for (v = 0; v < numVertices; ++v) {
457       for (d = 0; d < dim; ++d) {
458         coords[v*dim+d] = coordsIn[v*3+d];
459       }
460     }
461   }
462   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
463   ierr = PetscFree(coordsIn);CHKERRQ(ierr);
464   if (periodicMap) { /* we need to localize coordinates on cells */
465     PetscSection newSection;
466     Vec          newcoordinates;
467     PetscScalar  *coords2;
468     PetscInt     Nc;
469 
470     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)*dm), &newSection);CHKERRQ(ierr);
471     ierr = PetscSectionSetNumFields(newSection, 1);CHKERRQ(ierr);
472     ierr = PetscSectionGetFieldComponents(coordSection, 0, &Nc);CHKERRQ(ierr);
473     ierr = PetscSectionSetFieldComponents(newSection, 0, Nc);CHKERRQ(ierr);
474     ierr = PetscSectionSetChart(newSection, 0, trueNumCells + numVertices);CHKERRQ(ierr);
475     for (cell = 0, c = 0; c < numCells; ++c) {
476       if (gmsh_elem[c].dim == dim) {
477         ierr = PetscSectionSetDof(newSection, cell, gmsh_elem[c].numNodes*dim);CHKERRQ(ierr);
478         ierr = PetscSectionSetFieldDof(newSection, cell, 0, gmsh_elem[c].numNodes*dim);CHKERRQ(ierr);
479         cell++;
480       }
481     }
482     for (v = trueNumCells; v < trueNumCells+numVertices; ++v) {
483       ierr = PetscSectionSetDof(newSection, v, dim);CHKERRQ(ierr);
484       ierr = PetscSectionSetFieldDof(newSection, v, 0, dim);CHKERRQ(ierr);
485     }
486     ierr = PetscSectionSetUp(newSection);CHKERRQ(ierr);
487     ierr = PetscSectionGetStorageSize(newSection, &coordSize);CHKERRQ(ierr);
488     ierr = VecCreate(PETSC_COMM_SELF, &newcoordinates);CHKERRQ(ierr);
489     ierr = PetscObjectSetName((PetscObject)newcoordinates,"coordinates");CHKERRQ(ierr);
490     ierr = VecSetBlockSize(newcoordinates, dim);CHKERRQ(ierr);
491     ierr = VecSetSizes(newcoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
492     ierr = VecSetType(newcoordinates, VECSTANDARD);CHKERRQ(ierr);
493     ierr = VecGetArrayRead(coordinates, (const PetscScalar**)&coords);CHKERRQ(ierr);
494     ierr = VecGetArray(newcoordinates, &coords2);CHKERRQ(ierr);
495     for (v = 0; v < numVertices; ++v) {
496       PetscInt dof, off, off2, vn = v + trueNumCells, d, vp;
497 
498       vp   = periodicMap[v] + trueNumCells;
499       ierr = PetscSectionGetDof(coordSection, vp, &dof);CHKERRQ(ierr);
500       ierr = PetscSectionGetOffset(coordSection, vp, &off);CHKERRQ(ierr);
501       ierr = PetscSectionGetOffset(newSection, vn, &off2);CHKERRQ(ierr);
502       for (d = 0; d < dim; ++d) coords2[off2+d] = coords[off+d];
503     }
504     for (c = 0; c < trueNumCells; ++c) {
505       PetscScalar *cellCoords = NULL;
506       PetscInt    dof, off, d;
507 
508       ierr = DMPlexVecGetClosure(*dm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
509       ierr = PetscSectionGetOffset(newSection, c, &off);CHKERRQ(ierr);
510       for (d = 0; d < dof; ++d) coords2[off+d] = cellCoords[d];
511       ierr = DMPlexVecRestoreClosure(*dm, coordSection, coordinates, c, &dof, &cellCoords);CHKERRQ(ierr);
512     }
513     ierr = VecRestoreArray(newcoordinates, &coords2);CHKERRQ(ierr);
514     ierr = VecRestoreArrayRead(coordinates, (const PetscScalar**)&coords);CHKERRQ(ierr);
515     ierr = DMSetCoordinateSection(*dm, PETSC_DETERMINE, newSection);CHKERRQ(ierr);
516     ierr = PetscSectionDestroy(&newSection);CHKERRQ(ierr);
517     ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
518     coordinates = newcoordinates;
519   }
520   ierr = DMSetCoordinatesLocal(*dm, coordinates);CHKERRQ(ierr);
521   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
522   ierr = PetscFree(periodicMap);CHKERRQ(ierr);
523   /* Clean up intermediate storage */
524   if (!rank || binary) ierr = PetscFree(gmsh_elem);CHKERRQ(ierr);
525   ierr = PetscLogEventEnd(DMPLEX_CreateGmsh,*dm,0,0,0);CHKERRQ(ierr);
526   PetscFunctionReturn(0);
527 }
528