xref: /petsc/src/dm/impls/plex/plexgmsh.c (revision a77d671b1191ed14ce34133f22d77229bbb91e89)
1 #define PETSCDM_DLL
2 #include <petsc/private/dmpleximpl.h> /*I   "petscdmplex.h"   I*/
3 #include <petsc/private/hashmapi.h>
4 
5 #include <../src/dm/impls/plex/gmshlex.h>
6 
7 #define GMSH_LEXORDER_ITEM(T, p) \
8   static int *GmshLexOrder_##T##_##p(void) \
9   { \
10     static int Gmsh_LexOrder_##T##_##p[GmshNumNodes_##T(p)] = {-1}; \
11     int       *lex                                          = Gmsh_LexOrder_##T##_##p; \
12     if (lex[0] == -1) (void)GmshLexOrder_##T(p, lex, 0); \
13     return lex; \
14   }
15 
16 static int *GmshLexOrder_QUA_2_Serendipity(void)
17 {
18   static int Gmsh_LexOrder_QUA_2_Serendipity[9] = {-1};
19   int       *lex                                = Gmsh_LexOrder_QUA_2_Serendipity;
20   if (lex[0] == -1) {
21     /* Vertices */
22     lex[0] = 0;
23     lex[2] = 1;
24     lex[8] = 2;
25     lex[6] = 3;
26     /* Edges */
27     lex[1] = 4;
28     lex[5] = 5;
29     lex[7] = 6;
30     lex[3] = 7;
31     /* Cell */
32     lex[4] = -8;
33   }
34   return lex;
35 }
36 
37 static int *GmshLexOrder_HEX_2_Serendipity(void)
38 {
39   static int Gmsh_LexOrder_HEX_2_Serendipity[27] = {-1};
40   int       *lex                                 = Gmsh_LexOrder_HEX_2_Serendipity;
41   if (lex[0] == -1) {
42     /* Vertices */
43     lex[0]  = 0;
44     lex[2]  = 1;
45     lex[8]  = 2;
46     lex[6]  = 3;
47     lex[18] = 4;
48     lex[20] = 5;
49     lex[26] = 6;
50     lex[24] = 7;
51     /* Edges */
52     lex[1]  = 8;
53     lex[3]  = 9;
54     lex[9]  = 10;
55     lex[5]  = 11;
56     lex[11] = 12;
57     lex[7]  = 13;
58     lex[17] = 14;
59     lex[15] = 15;
60     lex[19] = 16;
61     lex[21] = 17;
62     lex[23] = 18;
63     lex[25] = 19;
64     /* Faces */
65     lex[4]  = -20;
66     lex[10] = -21;
67     lex[12] = -22;
68     lex[14] = -23;
69     lex[16] = -24;
70     lex[22] = -25;
71     /* Cell */
72     lex[13] = -26;
73   }
74   return lex;
75 }
76 
77 #define GMSH_LEXORDER_LIST(T) \
78   GMSH_LEXORDER_ITEM(T, 1) \
79   GMSH_LEXORDER_ITEM(T, 2) \
80   GMSH_LEXORDER_ITEM(T, 3) \
81   GMSH_LEXORDER_ITEM(T, 4) \
82   GMSH_LEXORDER_ITEM(T, 5) \
83   GMSH_LEXORDER_ITEM(T, 6) \
84   GMSH_LEXORDER_ITEM(T, 7) \
85   GMSH_LEXORDER_ITEM(T, 8) \
86   GMSH_LEXORDER_ITEM(T, 9) \
87   GMSH_LEXORDER_ITEM(T, 10)
88 
89 GMSH_LEXORDER_ITEM(VTX, 0)
90 GMSH_LEXORDER_LIST(SEG)
91 GMSH_LEXORDER_LIST(TRI)
92 GMSH_LEXORDER_LIST(QUA)
93 GMSH_LEXORDER_LIST(TET)
94 GMSH_LEXORDER_LIST(HEX)
95 GMSH_LEXORDER_LIST(PRI)
96 GMSH_LEXORDER_LIST(PYR)
97 
98 typedef enum {
99   GMSH_VTX           = 0,
100   GMSH_SEG           = 1,
101   GMSH_TRI           = 2,
102   GMSH_QUA           = 3,
103   GMSH_TET           = 4,
104   GMSH_HEX           = 5,
105   GMSH_PRI           = 6,
106   GMSH_PYR           = 7,
107   GMSH_NUM_POLYTOPES = 8
108 } GmshPolytopeType;
109 
110 typedef struct {
111   int cellType;
112   int polytope;
113   int dim;
114   int order;
115   int numVerts;
116   int numNodes;
117   int *(*lexorder)(void);
118 } GmshCellInfo;
119 
120 // clang-format off
121 #define GmshCellEntry(cellType, polytope, dim, order) {cellType, GMSH_##polytope, dim, order, GmshNumNodes_##polytope(1), GmshNumNodes_##polytope(order), GmshLexOrder_##polytope##_##order}
122 // clang-format on
123 
124 static const GmshCellInfo GmshCellTable[] = {
125   GmshCellEntry(15, VTX, 0, 0),
126 
127   GmshCellEntry(1, SEG, 1, 1),   GmshCellEntry(8, SEG, 1, 2),   GmshCellEntry(26, SEG, 1, 3),
128   GmshCellEntry(27, SEG, 1, 4),  GmshCellEntry(28, SEG, 1, 5),  GmshCellEntry(62, SEG, 1, 6),
129   GmshCellEntry(63, SEG, 1, 7),  GmshCellEntry(64, SEG, 1, 8),  GmshCellEntry(65, SEG, 1, 9),
130   GmshCellEntry(66, SEG, 1, 10),
131 
132   GmshCellEntry(2, TRI, 2, 1),   GmshCellEntry(9, TRI, 2, 2),   GmshCellEntry(21, TRI, 2, 3),
133   GmshCellEntry(23, TRI, 2, 4),  GmshCellEntry(25, TRI, 2, 5),  GmshCellEntry(42, TRI, 2, 6),
134   GmshCellEntry(43, TRI, 2, 7),  GmshCellEntry(44, TRI, 2, 8),  GmshCellEntry(45, TRI, 2, 9),
135   GmshCellEntry(46, TRI, 2, 10),
136 
137   GmshCellEntry(3, QUA, 2, 1),   GmshCellEntry(10, QUA, 2, 2),  {16, GMSH_QUA, 2, 2, 4, 8,  GmshLexOrder_QUA_2_Serendipity},
138   GmshCellEntry(36, QUA, 2, 3),  GmshCellEntry(37, QUA, 2, 4),  GmshCellEntry(38, QUA, 2, 5),
139   GmshCellEntry(47, QUA, 2, 6),  GmshCellEntry(48, QUA, 2, 7),  GmshCellEntry(49, QUA, 2, 8),
140   GmshCellEntry(50, QUA, 2, 9),  GmshCellEntry(51, QUA, 2, 10),
141 
142   GmshCellEntry(4, TET, 3, 1),   GmshCellEntry(11, TET, 3, 2),  GmshCellEntry(29, TET, 3, 3),
143   GmshCellEntry(30, TET, 3, 4),  GmshCellEntry(31, TET, 3, 5),  GmshCellEntry(71, TET, 3, 6),
144   GmshCellEntry(72, TET, 3, 7),  GmshCellEntry(73, TET, 3, 8),  GmshCellEntry(74, TET, 3, 9),
145   GmshCellEntry(75, TET, 3, 10),
146 
147   GmshCellEntry(5, HEX, 3, 1),   GmshCellEntry(12, HEX, 3, 2),  {17, GMSH_HEX, 3, 2, 8, 20, GmshLexOrder_HEX_2_Serendipity},
148   GmshCellEntry(92, HEX, 3, 3),  GmshCellEntry(93, HEX, 3, 4),  GmshCellEntry(94, HEX, 3, 5),
149   GmshCellEntry(95, HEX, 3, 6),  GmshCellEntry(96, HEX, 3, 7),  GmshCellEntry(97, HEX, 3, 8),
150   GmshCellEntry(98, HEX, 3, 9),  GmshCellEntry(-1, HEX, 3, 10),
151 
152   GmshCellEntry(6, PRI, 3, 1),   GmshCellEntry(13, PRI, 3, 2),  GmshCellEntry(90, PRI, 3, 3),
153   GmshCellEntry(91, PRI, 3, 4),  GmshCellEntry(106, PRI, 3, 5), GmshCellEntry(107, PRI, 3, 6),
154   GmshCellEntry(108, PRI, 3, 7), GmshCellEntry(109, PRI, 3, 8), GmshCellEntry(110, PRI, 3, 9),
155   GmshCellEntry(-1, PRI, 3, 10),
156 
157   GmshCellEntry(7, PYR, 3, 1),   GmshCellEntry(14, PYR, 3, 2),  GmshCellEntry(118, PYR, 3, 3),
158   GmshCellEntry(119, PYR, 3, 4), GmshCellEntry(120, PYR, 3, 5), GmshCellEntry(121, PYR, 3, 6),
159   GmshCellEntry(122, PYR, 3, 7), GmshCellEntry(123, PYR, 3, 8), GmshCellEntry(124, PYR, 3, 9),
160   GmshCellEntry(-1, PYR, 3, 10)
161 
162 #if 0
163   {20, GMSH_TRI, 2, 3, 3,  9, NULL},
164   {18, GMSH_PRI, 3, 2, 6, 15, NULL},
165   {19, GMSH_PYR, 3, 2, 5, 13, NULL},
166 #endif
167 };
168 
169 static GmshCellInfo GmshCellMap[150];
170 
171 static PetscErrorCode GmshCellInfoSetUp(void)
172 {
173   size_t           i, n;
174   static PetscBool called = PETSC_FALSE;
175 
176   PetscFunctionBegin;
177   if (called) PetscFunctionReturn(PETSC_SUCCESS);
178   called = PETSC_TRUE;
179   n      = PETSC_STATIC_ARRAY_LENGTH(GmshCellMap);
180   for (i = 0; i < n; ++i) {
181     GmshCellMap[i].cellType = -1;
182     GmshCellMap[i].polytope = -1;
183   }
184   n = PETSC_STATIC_ARRAY_LENGTH(GmshCellTable);
185   for (i = 0; i < n; ++i) {
186     if (GmshCellTable[i].cellType <= 0) continue;
187     GmshCellMap[GmshCellTable[i].cellType] = GmshCellTable[i];
188   }
189   PetscFunctionReturn(PETSC_SUCCESS);
190 }
191 
192 #define GmshCellTypeCheck(ct) \
193   PetscMacroReturnStandard(const int _ct_ = (int)ct; PetscCheck(_ct_ >= 0 && _ct_ < (int)PETSC_STATIC_ARRAY_LENGTH(GmshCellMap), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid Gmsh element type %d", _ct_); PetscCheck(GmshCellMap[_ct_].cellType == _ct_, PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported Gmsh element type %d", _ct_); \
194                            PetscCheck(GmshCellMap[_ct_].polytope != -1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported Gmsh element type %d", _ct_);)
195 
196 typedef struct {
197   PetscViewer viewer;
198   int         fileFormat;
199   int         dataSize;
200   PetscBool   binary;
201   PetscBool   byteSwap;
202   size_t      wlen;
203   void       *wbuf;
204   size_t      slen;
205   void       *sbuf;
206   PetscInt   *nbuf;
207   PetscInt    nodeStart;
208   PetscInt    nodeEnd;
209   PetscInt   *nodeMap;
210 } GmshFile;
211 
212 static PetscErrorCode GmshBufferGet(GmshFile *gmsh, size_t count, size_t eltsize, void *buf)
213 {
214   size_t size = count * eltsize;
215 
216   PetscFunctionBegin;
217   if (gmsh->wlen < size) {
218     PetscCall(PetscFree(gmsh->wbuf));
219     PetscCall(PetscMalloc(size, &gmsh->wbuf));
220     gmsh->wlen = size;
221   }
222   *(void **)buf = size ? gmsh->wbuf : NULL;
223   PetscFunctionReturn(PETSC_SUCCESS);
224 }
225 
226 static PetscErrorCode GmshBufferSizeGet(GmshFile *gmsh, size_t count, void *buf)
227 {
228   size_t dataSize = (size_t)gmsh->dataSize;
229   size_t size     = count * dataSize;
230 
231   PetscFunctionBegin;
232   if (gmsh->slen < size) {
233     PetscCall(PetscFree(gmsh->sbuf));
234     PetscCall(PetscMalloc(size, &gmsh->sbuf));
235     gmsh->slen = size;
236   }
237   *(void **)buf = size ? gmsh->sbuf : NULL;
238   PetscFunctionReturn(PETSC_SUCCESS);
239 }
240 
241 static PetscErrorCode GmshRead(GmshFile *gmsh, void *buf, PetscInt count, PetscDataType dtype)
242 {
243   PetscFunctionBegin;
244   PetscCall(PetscViewerRead(gmsh->viewer, buf, count, NULL, dtype));
245   if (gmsh->byteSwap) PetscCall(PetscByteSwap(buf, dtype, count));
246   PetscFunctionReturn(PETSC_SUCCESS);
247 }
248 
249 static PetscErrorCode GmshReadString(GmshFile *gmsh, char *buf, PetscInt count)
250 {
251   PetscFunctionBegin;
252   PetscCall(PetscViewerRead(gmsh->viewer, buf, count, NULL, PETSC_STRING));
253   PetscFunctionReturn(PETSC_SUCCESS);
254 }
255 
256 static PetscErrorCode GmshMatch(PETSC_UNUSED GmshFile *gmsh, const char Section[], char line[PETSC_MAX_PATH_LEN], PetscBool *match)
257 {
258   PetscFunctionBegin;
259   PetscCall(PetscStrcmp(line, Section, match));
260   PetscFunctionReturn(PETSC_SUCCESS);
261 }
262 
263 static PetscErrorCode GmshExpect(GmshFile *gmsh, const char Section[], char line[PETSC_MAX_PATH_LEN])
264 {
265   PetscBool match;
266 
267   PetscFunctionBegin;
268   PetscCall(GmshMatch(gmsh, Section, line, &match));
269   PetscCheck(match, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file, expecting %s, not %s", Section, line);
270   PetscFunctionReturn(PETSC_SUCCESS);
271 }
272 
273 static PetscErrorCode GmshReadSection(GmshFile *gmsh, char line[PETSC_MAX_PATH_LEN])
274 {
275   PetscBool match;
276 
277   PetscFunctionBegin;
278   while (PETSC_TRUE) {
279     PetscCall(GmshReadString(gmsh, line, 1));
280     PetscCall(GmshMatch(gmsh, "$Comments", line, &match));
281     if (!match) break;
282     while (PETSC_TRUE) {
283       PetscCall(GmshReadString(gmsh, line, 1));
284       PetscCall(GmshMatch(gmsh, "$EndComments", line, &match));
285       if (match) break;
286     }
287   }
288   PetscFunctionReturn(PETSC_SUCCESS);
289 }
290 
291 static PetscErrorCode GmshReadEndSection(GmshFile *gmsh, const char EndSection[], char line[PETSC_MAX_PATH_LEN])
292 {
293   PetscFunctionBegin;
294   PetscCall(GmshReadString(gmsh, line, 1));
295   PetscCall(GmshExpect(gmsh, EndSection, line));
296   PetscFunctionReturn(PETSC_SUCCESS);
297 }
298 
299 static PetscErrorCode GmshReadSize(GmshFile *gmsh, PetscInt *buf, PetscInt count)
300 {
301   PetscInt i;
302   size_t   dataSize = (size_t)gmsh->dataSize;
303 
304   PetscFunctionBegin;
305   if (dataSize == sizeof(PetscInt)) {
306     PetscCall(GmshRead(gmsh, buf, count, PETSC_INT));
307   } else if (dataSize == sizeof(int)) {
308     int *ibuf = NULL;
309     PetscCall(GmshBufferSizeGet(gmsh, count, &ibuf));
310     PetscCall(GmshRead(gmsh, ibuf, count, PETSC_ENUM));
311     for (i = 0; i < count; ++i) buf[i] = (PetscInt)ibuf[i];
312   } else if (dataSize == sizeof(long)) {
313     long *ibuf = NULL;
314     PetscCall(GmshBufferSizeGet(gmsh, count, &ibuf));
315     PetscCall(GmshRead(gmsh, ibuf, count, PETSC_LONG));
316     for (i = 0; i < count; ++i) buf[i] = (PetscInt)ibuf[i];
317   } else if (dataSize == sizeof(PetscInt64)) {
318     PetscInt64 *ibuf = NULL;
319     PetscCall(GmshBufferSizeGet(gmsh, count, &ibuf));
320     PetscCall(GmshRead(gmsh, ibuf, count, PETSC_INT64));
321     for (i = 0; i < count; ++i) buf[i] = (PetscInt)ibuf[i];
322   }
323   PetscFunctionReturn(PETSC_SUCCESS);
324 }
325 
326 static PetscErrorCode GmshReadInt(GmshFile *gmsh, int *buf, PetscInt count)
327 {
328   PetscFunctionBegin;
329   PetscCall(GmshRead(gmsh, buf, count, PETSC_ENUM));
330   PetscFunctionReturn(PETSC_SUCCESS);
331 }
332 
333 static PetscErrorCode GmshReadDouble(GmshFile *gmsh, double *buf, PetscInt count)
334 {
335   PetscFunctionBegin;
336   PetscCall(GmshRead(gmsh, buf, count, PETSC_DOUBLE));
337   PetscFunctionReturn(PETSC_SUCCESS);
338 }
339 
340 #define GMSH_MAX_TAGS 16
341 
342 typedef struct {
343   PetscInt id;                  /* Entity ID */
344   PetscInt dim;                 /* Dimension */
345   double   bbox[6];             /* Bounding box */
346   PetscInt numTags;             /* Size of tag array */
347   int      tags[GMSH_MAX_TAGS]; /* Tag array */
348 } GmshEntity;
349 
350 typedef struct {
351   GmshEntity *entity[4];
352   PetscHMapI  entityMap[4];
353 } GmshEntities;
354 
355 static PetscErrorCode GmshEntitiesCreate(PetscInt count[4], GmshEntities **entities)
356 {
357   PetscInt dim;
358 
359   PetscFunctionBegin;
360   PetscCall(PetscNew(entities));
361   for (dim = 0; dim < 4; ++dim) {
362     PetscCall(PetscCalloc1(count[dim], &(*entities)->entity[dim]));
363     PetscCall(PetscHMapICreate(&(*entities)->entityMap[dim]));
364   }
365   PetscFunctionReturn(PETSC_SUCCESS);
366 }
367 
368 static PetscErrorCode GmshEntitiesDestroy(GmshEntities **entities)
369 {
370   PetscInt dim;
371 
372   PetscFunctionBegin;
373   if (!*entities) PetscFunctionReturn(PETSC_SUCCESS);
374   for (dim = 0; dim < 4; ++dim) {
375     PetscCall(PetscFree((*entities)->entity[dim]));
376     PetscCall(PetscHMapIDestroy(&(*entities)->entityMap[dim]));
377   }
378   PetscCall(PetscFree(*entities));
379   PetscFunctionReturn(PETSC_SUCCESS);
380 }
381 
382 static PetscErrorCode GmshEntitiesAdd(GmshEntities *entities, PetscInt index, PetscInt dim, PetscInt eid, GmshEntity **entity)
383 {
384   PetscFunctionBegin;
385   PetscCall(PetscHMapISet(entities->entityMap[dim], eid, index));
386   entities->entity[dim][index].dim = dim;
387   entities->entity[dim][index].id  = eid;
388   if (entity) *entity = &entities->entity[dim][index];
389   PetscFunctionReturn(PETSC_SUCCESS);
390 }
391 
392 static PetscErrorCode GmshEntitiesGet(GmshEntities *entities, PetscInt dim, PetscInt eid, GmshEntity **entity)
393 {
394   PetscInt index;
395 
396   PetscFunctionBegin;
397   PetscCall(PetscHMapIGet(entities->entityMap[dim], eid, &index));
398   *entity = &entities->entity[dim][index];
399   PetscFunctionReturn(PETSC_SUCCESS);
400 }
401 
402 typedef struct {
403   PetscInt *id;  /* Node IDs */
404   double   *xyz; /* Coordinates */
405   PetscInt *tag; /* Physical tag */
406 } GmshNodes;
407 
408 static PetscErrorCode GmshNodesCreate(PetscInt count, GmshNodes **nodes)
409 {
410   PetscFunctionBegin;
411   PetscCall(PetscNew(nodes));
412   PetscCall(PetscMalloc1(count * 1, &(*nodes)->id));
413   PetscCall(PetscMalloc1(count * 3, &(*nodes)->xyz));
414   PetscCall(PetscMalloc1(count * GMSH_MAX_TAGS, &(*nodes)->tag));
415   PetscFunctionReturn(PETSC_SUCCESS);
416 }
417 
418 static PetscErrorCode GmshNodesDestroy(GmshNodes **nodes)
419 {
420   PetscFunctionBegin;
421   if (!*nodes) PetscFunctionReturn(PETSC_SUCCESS);
422   PetscCall(PetscFree((*nodes)->id));
423   PetscCall(PetscFree((*nodes)->xyz));
424   PetscCall(PetscFree((*nodes)->tag));
425   PetscCall(PetscFree(*nodes));
426   PetscFunctionReturn(PETSC_SUCCESS);
427 }
428 
429 typedef struct {
430   PetscInt  id;                  /* Element ID */
431   PetscInt  dim;                 /* Dimension */
432   PetscInt  cellType;            /* Cell type */
433   PetscInt  numVerts;            /* Size of vertex array */
434   PetscInt  numNodes;            /* Size of node array */
435   PetscInt *nodes;               /* Vertex/Node array */
436   PetscInt  numTags;             /* Size of physical tag array */
437   int       tags[GMSH_MAX_TAGS]; /* Physical tag array */
438 } GmshElement;
439 
440 static PetscErrorCode GmshElementsCreate(PetscInt count, GmshElement **elements)
441 {
442   PetscFunctionBegin;
443   PetscCall(PetscCalloc1(count, elements));
444   PetscFunctionReturn(PETSC_SUCCESS);
445 }
446 
447 static PetscErrorCode GmshElementsDestroy(GmshElement **elements)
448 {
449   PetscFunctionBegin;
450   if (!*elements) PetscFunctionReturn(PETSC_SUCCESS);
451   PetscCall(PetscFree(*elements));
452   PetscFunctionReturn(PETSC_SUCCESS);
453 }
454 
455 typedef struct {
456   PetscInt       dim;
457   PetscInt       order;
458   GmshEntities  *entities;
459   PetscInt       numNodes;
460   GmshNodes     *nodelist;
461   PetscInt       numElems;
462   GmshElement   *elements;
463   PetscInt       numVerts;
464   PetscInt       numCells;
465   PetscInt      *periodMap;
466   PetscInt      *vertexMap;
467   PetscSegBuffer segbuf;
468   PetscInt       numRegions;
469   PetscInt      *regionDims;
470   PetscInt      *regionTags;
471   char         **regionNames;
472 } GmshMesh;
473 
474 static PetscErrorCode GmshMeshCreate(GmshMesh **mesh)
475 {
476   PetscFunctionBegin;
477   PetscCall(PetscNew(mesh));
478   PetscCall(PetscSegBufferCreate(sizeof(PetscInt), 0, &(*mesh)->segbuf));
479   PetscFunctionReturn(PETSC_SUCCESS);
480 }
481 
482 static PetscErrorCode GmshMeshDestroy(GmshMesh **mesh)
483 {
484   PetscInt r;
485 
486   PetscFunctionBegin;
487   if (!*mesh) PetscFunctionReturn(PETSC_SUCCESS);
488   PetscCall(GmshEntitiesDestroy(&(*mesh)->entities));
489   PetscCall(GmshNodesDestroy(&(*mesh)->nodelist));
490   PetscCall(GmshElementsDestroy(&(*mesh)->elements));
491   PetscCall(PetscFree((*mesh)->periodMap));
492   PetscCall(PetscFree((*mesh)->vertexMap));
493   PetscCall(PetscSegBufferDestroy(&(*mesh)->segbuf));
494   for (r = 0; r < (*mesh)->numRegions; ++r) PetscCall(PetscFree((*mesh)->regionNames[r]));
495   PetscCall(PetscFree3((*mesh)->regionDims, (*mesh)->regionTags, (*mesh)->regionNames));
496   PetscCall(PetscFree(*mesh));
497   PetscFunctionReturn(PETSC_SUCCESS);
498 }
499 
500 static PetscErrorCode GmshReadNodes_v22(GmshFile *gmsh, GmshMesh *mesh)
501 {
502   PetscViewer viewer   = gmsh->viewer;
503   PetscBool   byteSwap = gmsh->byteSwap;
504   char        line[PETSC_MAX_PATH_LEN];
505   int         n, t, num, nid, snum;
506   GmshNodes  *nodes;
507 
508   PetscFunctionBegin;
509   PetscCall(PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING));
510   snum = sscanf(line, "%d", &num);
511   PetscCheck(snum == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
512   PetscCall(GmshNodesCreate(num, &nodes));
513   mesh->numNodes = num;
514   mesh->nodelist = nodes;
515   for (n = 0; n < num; ++n) {
516     double *xyz = nodes->xyz + n * 3;
517     PetscCall(PetscViewerRead(viewer, &nid, 1, NULL, PETSC_ENUM));
518     PetscCall(PetscViewerRead(viewer, xyz, 3, NULL, PETSC_DOUBLE));
519     if (byteSwap) PetscCall(PetscByteSwap(&nid, PETSC_ENUM, 1));
520     if (byteSwap) PetscCall(PetscByteSwap(xyz, PETSC_DOUBLE, 3));
521     nodes->id[n] = nid;
522     for (t = 0; t < GMSH_MAX_TAGS; ++t) nodes->tag[n * GMSH_MAX_TAGS + t] = -1;
523   }
524   PetscFunctionReturn(PETSC_SUCCESS);
525 }
526 
527 /* Gmsh elements can be of any dimension/co-dimension, so we need to traverse the
528    file contents multiple times to figure out the true number of cells and facets
529    in the given mesh. To make this more efficient we read the file contents only
530    once and store them in memory, while determining the true number of cells. */
531 static PetscErrorCode GmshReadElements_v22(GmshFile *gmsh, GmshMesh *mesh)
532 {
533   PetscViewer  viewer   = gmsh->viewer;
534   PetscBool    binary   = gmsh->binary;
535   PetscBool    byteSwap = gmsh->byteSwap;
536   char         line[PETSC_MAX_PATH_LEN];
537   int          i, c, p, num, ibuf[1 + 4 + 1000], snum;
538   int          cellType, numElem, numVerts, numNodes, numTags;
539   GmshElement *elements;
540   PetscInt    *nodeMap = gmsh->nodeMap;
541 
542   PetscFunctionBegin;
543   PetscCall(PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING));
544   snum = sscanf(line, "%d", &num);
545   PetscCheck(snum == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
546   PetscCall(GmshElementsCreate(num, &elements));
547   mesh->numElems = num;
548   mesh->elements = elements;
549   for (c = 0; c < num;) {
550     PetscCall(PetscViewerRead(viewer, ibuf, 3, NULL, PETSC_ENUM));
551     if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, 3));
552 
553     cellType = binary ? ibuf[0] : ibuf[1];
554     numElem  = binary ? ibuf[1] : 1;
555     numTags  = ibuf[2];
556 
557     PetscCall(GmshCellTypeCheck(cellType));
558     numVerts = GmshCellMap[cellType].numVerts;
559     numNodes = GmshCellMap[cellType].numNodes;
560 
561     for (i = 0; i < numElem; ++i, ++c) {
562       GmshElement *element = elements + c;
563       const int    off = binary ? 0 : 1, nint = 1 + numTags + numNodes - off;
564       const int   *id = ibuf, *nodes = ibuf + 1 + numTags, *tags = ibuf + 1;
565       PetscCall(PetscViewerRead(viewer, ibuf + off, nint, NULL, PETSC_ENUM));
566       if (byteSwap) PetscCall(PetscByteSwap(ibuf + off, PETSC_ENUM, nint));
567       element->id       = id[0];
568       element->dim      = GmshCellMap[cellType].dim;
569       element->cellType = cellType;
570       element->numVerts = numVerts;
571       element->numNodes = numNodes;
572       element->numTags  = PetscMin(numTags, GMSH_MAX_TAGS);
573       PetscCall(PetscSegBufferGet(mesh->segbuf, (size_t)element->numNodes, &element->nodes));
574       for (p = 0; p < element->numNodes; p++) element->nodes[p] = nodeMap[nodes[p]];
575       for (p = 0; p < element->numTags; p++) element->tags[p] = tags[p];
576     }
577   }
578   PetscFunctionReturn(PETSC_SUCCESS);
579 }
580 
581 /*
582 $Entities
583   numPoints(unsigned long) numCurves(unsigned long)
584     numSurfaces(unsigned long) numVolumes(unsigned long)
585   // points
586   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
587     boxMaxX(double) boxMaxY(double) boxMaxZ(double)
588     numPhysicals(unsigned long) phyisicalTag[...](int)
589   ...
590   // curves
591   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
592      boxMaxX(double) boxMaxY(double) boxMaxZ(double)
593      numPhysicals(unsigned long) physicalTag[...](int)
594      numBREPVert(unsigned long) tagBREPVert[...](int)
595   ...
596   // surfaces
597   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
598     boxMaxX(double) boxMaxY(double) boxMaxZ(double)
599     numPhysicals(unsigned long) physicalTag[...](int)
600     numBREPCurve(unsigned long) tagBREPCurve[...](int)
601   ...
602   // volumes
603   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
604     boxMaxX(double) boxMaxY(double) boxMaxZ(double)
605     numPhysicals(unsigned long) physicalTag[...](int)
606     numBREPSurfaces(unsigned long) tagBREPSurfaces[...](int)
607   ...
608 $EndEntities
609 */
610 static PetscErrorCode GmshReadEntities_v40(GmshFile *gmsh, GmshMesh *mesh)
611 {
612   PetscViewer viewer   = gmsh->viewer;
613   PetscBool   byteSwap = gmsh->byteSwap;
614   long        index, num, lbuf[4];
615   int         dim, eid, numTags, *ibuf, t;
616   PetscInt    count[4], i;
617   GmshEntity *entity = NULL;
618 
619   PetscFunctionBegin;
620   PetscCall(PetscViewerRead(viewer, lbuf, 4, NULL, PETSC_LONG));
621   if (byteSwap) PetscCall(PetscByteSwap(lbuf, PETSC_LONG, 4));
622   for (i = 0; i < 4; ++i) count[i] = lbuf[i];
623   PetscCall(GmshEntitiesCreate(count, &mesh->entities));
624   for (dim = 0; dim < 4; ++dim) {
625     for (index = 0; index < count[dim]; ++index) {
626       PetscCall(PetscViewerRead(viewer, &eid, 1, NULL, PETSC_ENUM));
627       if (byteSwap) PetscCall(PetscByteSwap(&eid, PETSC_ENUM, 1));
628       PetscCall(GmshEntitiesAdd(mesh->entities, (PetscInt)index, dim, eid, &entity));
629       PetscCall(PetscViewerRead(viewer, entity->bbox, 6, NULL, PETSC_DOUBLE));
630       if (byteSwap) PetscCall(PetscByteSwap(entity->bbox, PETSC_DOUBLE, 6));
631       PetscCall(PetscViewerRead(viewer, &num, 1, NULL, PETSC_LONG));
632       if (byteSwap) PetscCall(PetscByteSwap(&num, PETSC_LONG, 1));
633       PetscCall(GmshBufferGet(gmsh, num, sizeof(int), &ibuf));
634       PetscCall(PetscViewerRead(viewer, ibuf, num, NULL, PETSC_ENUM));
635       if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, num));
636       entity->numTags = numTags = (int)PetscMin(num, GMSH_MAX_TAGS);
637       for (t = 0; t < numTags; ++t) entity->tags[t] = ibuf[t];
638       if (dim == 0) continue;
639       PetscCall(PetscViewerRead(viewer, &num, 1, NULL, PETSC_LONG));
640       if (byteSwap) PetscCall(PetscByteSwap(&num, PETSC_LONG, 1));
641       PetscCall(GmshBufferGet(gmsh, num, sizeof(int), &ibuf));
642       PetscCall(PetscViewerRead(viewer, ibuf, num, NULL, PETSC_ENUM));
643       if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, num));
644     }
645   }
646   PetscFunctionReturn(PETSC_SUCCESS);
647 }
648 
649 /*
650 $Nodes
651   numEntityBlocks(unsigned long) numNodes(unsigned long)
652   tagEntity(int) dimEntity(int) typeNode(int) numNodes(unsigned long)
653     tag(int) x(double) y(double) z(double)
654     ...
655   ...
656 $EndNodes
657 */
658 static PetscErrorCode GmshReadNodes_v40(GmshFile *gmsh, GmshMesh *mesh)
659 {
660   PetscViewer viewer   = gmsh->viewer;
661   PetscBool   byteSwap = gmsh->byteSwap;
662   long        block, node, n, t, numEntityBlocks, numTotalNodes, numNodes;
663   int         info[3], nid;
664   GmshNodes  *nodes;
665 
666   PetscFunctionBegin;
667   PetscCall(PetscViewerRead(viewer, &numEntityBlocks, 1, NULL, PETSC_LONG));
668   if (byteSwap) PetscCall(PetscByteSwap(&numEntityBlocks, PETSC_LONG, 1));
669   PetscCall(PetscViewerRead(viewer, &numTotalNodes, 1, NULL, PETSC_LONG));
670   if (byteSwap) PetscCall(PetscByteSwap(&numTotalNodes, PETSC_LONG, 1));
671   PetscCall(GmshNodesCreate(numTotalNodes, &nodes));
672   mesh->numNodes = numTotalNodes;
673   mesh->nodelist = nodes;
674   for (n = 0, block = 0; block < numEntityBlocks; ++block) {
675     PetscCall(PetscViewerRead(viewer, info, 3, NULL, PETSC_ENUM));
676     PetscCall(PetscViewerRead(viewer, &numNodes, 1, NULL, PETSC_LONG));
677     if (byteSwap) PetscCall(PetscByteSwap(&numNodes, PETSC_LONG, 1));
678     if (gmsh->binary) {
679       size_t nbytes = sizeof(int) + 3 * sizeof(double);
680       char  *cbuf   = NULL; /* dummy value to prevent warning from compiler about possible uninitialized value */
681       PetscCall(GmshBufferGet(gmsh, numNodes, nbytes, &cbuf));
682       PetscCall(PetscViewerRead(viewer, cbuf, numNodes * nbytes, NULL, PETSC_CHAR));
683       for (node = 0; node < numNodes; ++node, ++n) {
684         char   *cnid = cbuf + node * nbytes, *cxyz = cnid + sizeof(int);
685         double *xyz = nodes->xyz + n * 3;
686         if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(cnid, PETSC_ENUM, 1));
687         if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(cxyz, PETSC_DOUBLE, 3));
688         PetscCall(PetscMemcpy(&nid, cnid, sizeof(int)));
689         PetscCall(PetscMemcpy(xyz, cxyz, 3 * sizeof(double)));
690         if (byteSwap) PetscCall(PetscByteSwap(&nid, PETSC_ENUM, 1));
691         if (byteSwap) PetscCall(PetscByteSwap(xyz, PETSC_DOUBLE, 3));
692         nodes->id[n] = nid;
693         for (t = 0; t < GMSH_MAX_TAGS; ++t) nodes->tag[n * GMSH_MAX_TAGS + t] = -1;
694       }
695     } else {
696       for (node = 0; node < numNodes; ++node, ++n) {
697         double *xyz = nodes->xyz + n * 3;
698         PetscCall(PetscViewerRead(viewer, &nid, 1, NULL, PETSC_ENUM));
699         PetscCall(PetscViewerRead(viewer, xyz, 3, NULL, PETSC_DOUBLE));
700         if (byteSwap) PetscCall(PetscByteSwap(&nid, PETSC_ENUM, 1));
701         if (byteSwap) PetscCall(PetscByteSwap(xyz, PETSC_DOUBLE, 3));
702         nodes->id[n] = nid;
703         for (t = 0; t < GMSH_MAX_TAGS; ++t) nodes->tag[n * GMSH_MAX_TAGS + t] = -1;
704       }
705     }
706   }
707   PetscFunctionReturn(PETSC_SUCCESS);
708 }
709 
710 /*
711 $Elements
712   numEntityBlocks(unsigned long) numElements(unsigned long)
713   tagEntity(int) dimEntity(int) typeEle(int) numElements(unsigned long)
714     tag(int) numVert[...](int)
715     ...
716   ...
717 $EndElements
718 */
719 static PetscErrorCode GmshReadElements_v40(GmshFile *gmsh, GmshMesh *mesh)
720 {
721   PetscViewer  viewer   = gmsh->viewer;
722   PetscBool    byteSwap = gmsh->byteSwap;
723   long         c, block, numEntityBlocks, numTotalElements, elem, numElements;
724   int          p, info[3], *ibuf = NULL;
725   int          eid, dim, cellType, numVerts, numNodes, numTags;
726   GmshEntity  *entity = NULL;
727   GmshElement *elements;
728   PetscInt    *nodeMap = gmsh->nodeMap;
729 
730   PetscFunctionBegin;
731   PetscCall(PetscViewerRead(viewer, &numEntityBlocks, 1, NULL, PETSC_LONG));
732   if (byteSwap) PetscCall(PetscByteSwap(&numEntityBlocks, PETSC_LONG, 1));
733   PetscCall(PetscViewerRead(viewer, &numTotalElements, 1, NULL, PETSC_LONG));
734   if (byteSwap) PetscCall(PetscByteSwap(&numTotalElements, PETSC_LONG, 1));
735   PetscCall(GmshElementsCreate(numTotalElements, &elements));
736   mesh->numElems = numTotalElements;
737   mesh->elements = elements;
738   for (c = 0, block = 0; block < numEntityBlocks; ++block) {
739     PetscCall(PetscViewerRead(viewer, info, 3, NULL, PETSC_ENUM));
740     if (byteSwap) PetscCall(PetscByteSwap(info, PETSC_ENUM, 3));
741     eid      = info[0];
742     dim      = info[1];
743     cellType = info[2];
744     PetscCall(GmshEntitiesGet(mesh->entities, dim, eid, &entity));
745     PetscCall(GmshCellTypeCheck(cellType));
746     numVerts = GmshCellMap[cellType].numVerts;
747     numNodes = GmshCellMap[cellType].numNodes;
748     numTags  = entity->numTags;
749     PetscCall(PetscViewerRead(viewer, &numElements, 1, NULL, PETSC_LONG));
750     if (byteSwap) PetscCall(PetscByteSwap(&numElements, PETSC_LONG, 1));
751     PetscCall(GmshBufferGet(gmsh, (1 + numNodes) * numElements, sizeof(int), &ibuf));
752     PetscCall(PetscViewerRead(viewer, ibuf, (1 + numNodes) * numElements, NULL, PETSC_ENUM));
753     if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, (1 + numNodes) * numElements));
754     for (elem = 0; elem < numElements; ++elem, ++c) {
755       GmshElement *element = elements + c;
756       const int   *id = ibuf + elem * (1 + numNodes), *nodes = id + 1;
757       element->id       = id[0];
758       element->dim      = dim;
759       element->cellType = cellType;
760       element->numVerts = numVerts;
761       element->numNodes = numNodes;
762       element->numTags  = numTags;
763       PetscCall(PetscSegBufferGet(mesh->segbuf, (size_t)element->numNodes, &element->nodes));
764       for (p = 0; p < element->numNodes; p++) element->nodes[p] = nodeMap[nodes[p]];
765       for (p = 0; p < element->numTags; p++) element->tags[p] = entity->tags[p];
766     }
767   }
768   PetscFunctionReturn(PETSC_SUCCESS);
769 }
770 
771 static PetscErrorCode GmshReadPeriodic_v40(GmshFile *gmsh, PetscInt periodicMap[])
772 {
773   PetscViewer viewer     = gmsh->viewer;
774   int         fileFormat = gmsh->fileFormat;
775   PetscBool   binary     = gmsh->binary;
776   PetscBool   byteSwap   = gmsh->byteSwap;
777   int         numPeriodic, snum, i;
778   char        line[PETSC_MAX_PATH_LEN];
779   PetscInt   *nodeMap = gmsh->nodeMap;
780 
781   PetscFunctionBegin;
782   if (fileFormat == 22 || !binary) {
783     PetscCall(PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING));
784     snum = sscanf(line, "%d", &numPeriodic);
785     PetscCheck(snum == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
786   } else {
787     PetscCall(PetscViewerRead(viewer, &numPeriodic, 1, NULL, PETSC_ENUM));
788     if (byteSwap) PetscCall(PetscByteSwap(&numPeriodic, PETSC_ENUM, 1));
789   }
790   for (i = 0; i < numPeriodic; i++) {
791     int    ibuf[3], correspondingDim = -1, correspondingTag = -1, primaryTag = -1, correspondingNode, primaryNode;
792     long   j, nNodes;
793     double affine[16];
794 
795     if (fileFormat == 22 || !binary) {
796       PetscCall(PetscViewerRead(viewer, line, 3, NULL, PETSC_STRING));
797       snum = sscanf(line, "%d %d %d", &correspondingDim, &correspondingTag, &primaryTag);
798       PetscCheck(snum == 3, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
799     } else {
800       PetscCall(PetscViewerRead(viewer, ibuf, 3, NULL, PETSC_ENUM));
801       if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, 3));
802       correspondingDim = ibuf[0];
803       correspondingTag = ibuf[1];
804       primaryTag       = ibuf[2];
805     }
806     (void)correspondingDim;
807     (void)correspondingTag;
808     (void)primaryTag; /* unused */
809 
810     if (fileFormat == 22 || !binary) {
811       PetscCall(PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING));
812       snum = sscanf(line, "%ld", &nNodes);
813       if (snum != 1) { /* discard transformation and try again */
814         PetscCall(PetscViewerRead(viewer, line, -PETSC_MAX_PATH_LEN, NULL, PETSC_STRING));
815         PetscCall(PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING));
816         snum = sscanf(line, "%ld", &nNodes);
817         PetscCheck(snum == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
818       }
819     } else {
820       PetscCall(PetscViewerRead(viewer, &nNodes, 1, NULL, PETSC_LONG));
821       if (byteSwap) PetscCall(PetscByteSwap(&nNodes, PETSC_LONG, 1));
822       if (nNodes == -1) { /* discard transformation and try again */
823         PetscCall(PetscViewerRead(viewer, affine, 16, NULL, PETSC_DOUBLE));
824         PetscCall(PetscViewerRead(viewer, &nNodes, 1, NULL, PETSC_LONG));
825         if (byteSwap) PetscCall(PetscByteSwap(&nNodes, PETSC_LONG, 1));
826       }
827     }
828 
829     for (j = 0; j < nNodes; j++) {
830       if (fileFormat == 22 || !binary) {
831         PetscCall(PetscViewerRead(viewer, line, 2, NULL, PETSC_STRING));
832         snum = sscanf(line, "%d %d", &correspondingNode, &primaryNode);
833         PetscCheck(snum == 2, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
834       } else {
835         PetscCall(PetscViewerRead(viewer, ibuf, 2, NULL, PETSC_ENUM));
836         if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, 2));
837         correspondingNode = ibuf[0];
838         primaryNode       = ibuf[1];
839       }
840       correspondingNode              = (int)nodeMap[correspondingNode];
841       primaryNode                    = (int)nodeMap[primaryNode];
842       periodicMap[correspondingNode] = primaryNode;
843     }
844   }
845   PetscFunctionReturn(PETSC_SUCCESS);
846 }
847 
848 /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
849 $Entities
850   numPoints(size_t) numCurves(size_t)
851     numSurfaces(size_t) numVolumes(size_t)
852   pointTag(int) X(double) Y(double) Z(double)
853     numPhysicalTags(size_t) physicalTag(int) ...
854   ...
855   curveTag(int) minX(double) minY(double) minZ(double)
856     maxX(double) maxY(double) maxZ(double)
857     numPhysicalTags(size_t) physicalTag(int) ...
858     numBoundingPoints(size_t) pointTag(int) ...
859   ...
860   surfaceTag(int) minX(double) minY(double) minZ(double)
861     maxX(double) maxY(double) maxZ(double)
862     numPhysicalTags(size_t) physicalTag(int) ...
863     numBoundingCurves(size_t) curveTag(int) ...
864   ...
865   volumeTag(int) minX(double) minY(double) minZ(double)
866     maxX(double) maxY(double) maxZ(double)
867     numPhysicalTags(size_t) physicalTag(int) ...
868     numBoundngSurfaces(size_t) surfaceTag(int) ...
869   ...
870 $EndEntities
871 */
872 static PetscErrorCode GmshReadEntities_v41(GmshFile *gmsh, GmshMesh *mesh)
873 {
874   PetscInt    count[4], index, numTags, i;
875   int         dim, eid, *tags = NULL;
876   GmshEntity *entity = NULL;
877 
878   PetscFunctionBegin;
879   PetscCall(GmshReadSize(gmsh, count, 4));
880   PetscCall(GmshEntitiesCreate(count, &mesh->entities));
881   for (dim = 0; dim < 4; ++dim) {
882     for (index = 0; index < count[dim]; ++index) {
883       PetscCall(GmshReadInt(gmsh, &eid, 1));
884       PetscCall(GmshEntitiesAdd(mesh->entities, (PetscInt)index, dim, eid, &entity));
885       PetscCall(GmshReadDouble(gmsh, entity->bbox, (dim == 0) ? 3 : 6));
886       PetscCall(GmshReadSize(gmsh, &numTags, 1));
887       PetscCall(GmshBufferGet(gmsh, numTags, sizeof(int), &tags));
888       PetscCall(GmshReadInt(gmsh, tags, numTags));
889       PetscCheck(numTags <= GMSH_MAX_TAGS, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "PETSc currently supports up to %" PetscInt_FMT " tags per entity, not %" PetscInt_FMT, (PetscInt)GMSH_MAX_TAGS, numTags);
890       entity->numTags = numTags;
891       for (i = 0; i < entity->numTags; ++i) entity->tags[i] = tags[i];
892       if (dim == 0) continue;
893       PetscCall(GmshReadSize(gmsh, &numTags, 1));
894       PetscCall(GmshBufferGet(gmsh, numTags, sizeof(int), &tags));
895       PetscCall(GmshReadInt(gmsh, tags, numTags));
896       /* Currently, we do not save the ids for the bounding entities */
897     }
898   }
899   PetscFunctionReturn(PETSC_SUCCESS);
900 }
901 
902 /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
903 $Nodes
904   numEntityBlocks(size_t) numNodes(size_t)
905     minNodeTag(size_t) maxNodeTag(size_t)
906   entityDim(int) entityTag(int) parametric(int; 0 or 1) numNodesBlock(size_t)
907     nodeTag(size_t)
908     ...
909     x(double) y(double) z(double)
910        < u(double; if parametric and entityDim = 1 or entityDim = 2) >
911        < v(double; if parametric and entityDim = 2) >
912     ...
913   ...
914 $EndNodes
915 */
916 static PetscErrorCode GmshReadNodes_v41(GmshFile *gmsh, GmshMesh *mesh)
917 {
918   int         info[3], dim, eid, parametric;
919   PetscInt    sizes[4], numEntityBlocks, numTags, t, numNodes, numNodesBlock = 0, block, node, n;
920   GmshEntity *entity = NULL;
921   GmshNodes  *nodes;
922 
923   PetscFunctionBegin;
924   PetscCall(GmshReadSize(gmsh, sizes, 4));
925   numEntityBlocks = sizes[0];
926   numNodes        = sizes[1];
927   PetscCall(GmshNodesCreate(numNodes, &nodes));
928   mesh->numNodes = numNodes;
929   mesh->nodelist = nodes;
930   if (numEntityBlocks && !mesh->entities) PetscCall(PetscInfo(NULL, "File specifies %" PetscInt_FMT " entity blocks, but was missing the $Entities section\n", numEntityBlocks));
931   for (block = 0, node = 0; block < numEntityBlocks; ++block, node += numNodesBlock) {
932     PetscCall(GmshReadInt(gmsh, info, 3));
933     dim        = info[0];
934     eid        = info[1];
935     parametric = info[2];
936     if (mesh->entities) PetscCall(GmshEntitiesGet(mesh->entities, dim, eid, &entity));
937     numTags = entity ? entity->numTags : 0;
938     PetscCheck(!parametric, PETSC_COMM_SELF, PETSC_ERR_SUP, "Parametric coordinates not supported");
939     PetscCall(GmshReadSize(gmsh, &numNodesBlock, 1));
940     PetscCall(GmshReadSize(gmsh, nodes->id + node, numNodesBlock));
941     PetscCall(GmshReadDouble(gmsh, nodes->xyz + node * 3, numNodesBlock * 3));
942     for (n = 0; n < numNodesBlock; ++n) {
943       PetscInt *tags = &nodes->tag[node * GMSH_MAX_TAGS];
944 
945       for (t = 0; t < numTags; ++t) tags[n * GMSH_MAX_TAGS + t] = entity->tags[t];
946       for (t = numTags; t < GMSH_MAX_TAGS; ++t) tags[n * GMSH_MAX_TAGS + t] = -1;
947     }
948   }
949   gmsh->nodeStart = sizes[2];
950   gmsh->nodeEnd   = sizes[3] + 1;
951   PetscFunctionReturn(PETSC_SUCCESS);
952 }
953 
954 /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
955 $Elements
956   numEntityBlocks(size_t) numElements(size_t)
957     minElementTag(size_t) maxElementTag(size_t)
958   entityDim(int) entityTag(int) elementType(int; see below) numElementsBlock(size_t)
959     elementTag(size_t) nodeTag(size_t) ...
960     ...
961   ...
962 $EndElements
963 */
964 static PetscErrorCode GmshReadElements_v41(GmshFile *gmsh, GmshMesh *mesh)
965 {
966   int          info[3], eid, dim, cellType;
967   PetscInt     sizes[4], *ibuf = NULL, numEntityBlocks, numElements, numBlockElements, numVerts, numNodes, numTags, block, elem, c, p;
968   GmshEntity  *entity = NULL;
969   GmshElement *elements;
970   PetscInt    *nodeMap = gmsh->nodeMap;
971 
972   PetscFunctionBegin;
973   PetscCall(GmshReadSize(gmsh, sizes, 4));
974   numEntityBlocks = sizes[0];
975   numElements     = sizes[1];
976   PetscCall(GmshElementsCreate(numElements, &elements));
977   mesh->numElems = numElements;
978   mesh->elements = elements;
979   if (numEntityBlocks && !mesh->entities) PetscCall(PetscInfo(NULL, "File specifies %" PetscInt_FMT " entity blocks, but was missing the $Entities section\n", numEntityBlocks));
980   for (c = 0, block = 0; block < numEntityBlocks; ++block) {
981     PetscCall(GmshReadInt(gmsh, info, 3));
982     dim      = info[0];
983     eid      = info[1];
984     cellType = info[2];
985     if (mesh->entities) PetscCall(GmshEntitiesGet(mesh->entities, dim, eid, &entity));
986     PetscCall(GmshCellTypeCheck(cellType));
987     numVerts = GmshCellMap[cellType].numVerts;
988     numNodes = GmshCellMap[cellType].numNodes;
989     numTags  = entity ? entity->numTags : 0;
990     PetscCall(GmshReadSize(gmsh, &numBlockElements, 1));
991     PetscCall(GmshBufferGet(gmsh, (1 + numNodes) * numBlockElements, sizeof(PetscInt), &ibuf));
992     PetscCall(GmshReadSize(gmsh, ibuf, (1 + numNodes) * numBlockElements));
993     for (elem = 0; elem < numBlockElements; ++elem, ++c) {
994       GmshElement    *element = elements + c;
995       const PetscInt *id = ibuf + elem * (1 + numNodes), *nodes = id + 1;
996       element->id       = id[0];
997       element->dim      = dim;
998       element->cellType = cellType;
999       element->numVerts = numVerts;
1000       element->numNodes = numNodes;
1001       element->numTags  = numTags;
1002       PetscCall(PetscSegBufferGet(mesh->segbuf, (size_t)element->numNodes, &element->nodes));
1003       for (p = 0; p < element->numNodes; p++) element->nodes[p] = nodeMap[nodes[p]];
1004       for (p = 0; p < element->numTags; p++) element->tags[p] = entity->tags[p];
1005     }
1006   }
1007   PetscFunctionReturn(PETSC_SUCCESS);
1008 }
1009 
1010 /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
1011 $Periodic
1012   numPeriodicLinks(size_t)
1013   entityDim(int) entityTag(int) entityTagPrimary(int)
1014   numAffine(size_t) value(double) ...
1015   numCorrespondingNodes(size_t)
1016     nodeTag(size_t) nodeTagPrimary(size_t)
1017     ...
1018   ...
1019 $EndPeriodic
1020 */
1021 static PetscErrorCode GmshReadPeriodic_v41(GmshFile *gmsh, PetscInt periodicMap[])
1022 {
1023   int       info[3];
1024   double    dbuf[16];
1025   PetscInt  numPeriodicLinks, numAffine, numCorrespondingNodes, *nodeTags = NULL, link, node;
1026   PetscInt *nodeMap = gmsh->nodeMap;
1027 
1028   PetscFunctionBegin;
1029   PetscCall(GmshReadSize(gmsh, &numPeriodicLinks, 1));
1030   for (link = 0; link < numPeriodicLinks; ++link) {
1031     PetscCall(GmshReadInt(gmsh, info, 3));
1032     PetscCall(GmshReadSize(gmsh, &numAffine, 1));
1033     PetscCall(GmshReadDouble(gmsh, dbuf, numAffine));
1034     PetscCall(GmshReadSize(gmsh, &numCorrespondingNodes, 1));
1035     PetscCall(GmshBufferGet(gmsh, numCorrespondingNodes, sizeof(PetscInt), &nodeTags));
1036     PetscCall(GmshReadSize(gmsh, nodeTags, numCorrespondingNodes * 2));
1037     for (node = 0; node < numCorrespondingNodes; ++node) {
1038       PetscInt correspondingNode     = nodeMap[nodeTags[node * 2 + 0]];
1039       PetscInt primaryNode           = nodeMap[nodeTags[node * 2 + 1]];
1040       periodicMap[correspondingNode] = primaryNode;
1041     }
1042   }
1043   PetscFunctionReturn(PETSC_SUCCESS);
1044 }
1045 
1046 /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
1047 $MeshFormat // same as MSH version 2
1048   version(ASCII double; currently 4.1)
1049   file-type(ASCII int; 0 for ASCII mode, 1 for binary mode)
1050   data-size(ASCII int; sizeof(size_t))
1051   < int with value one; only in binary mode, to detect endianness >
1052 $EndMeshFormat
1053 */
1054 static PetscErrorCode GmshReadMeshFormat(GmshFile *gmsh)
1055 {
1056   char  line[PETSC_MAX_PATH_LEN];
1057   int   snum, fileType, fileFormat, dataSize, checkEndian;
1058   float version;
1059 
1060   PetscFunctionBegin;
1061   PetscCall(GmshReadString(gmsh, line, 3));
1062   snum       = sscanf(line, "%f %d %d", &version, &fileType, &dataSize);
1063   fileFormat = (int)roundf(version * 10);
1064   PetscCheck(snum == 3, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to parse Gmsh file header: %s", line);
1065   PetscCheck(fileFormat >= 22, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at least 2.2", (double)version);
1066   PetscCheck((int)version != 3, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f not supported", (double)version);
1067   PetscCheck(fileFormat <= 41, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at most 4.1", (double)version);
1068   PetscCheck(!gmsh->binary || fileType, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Viewer is binary but Gmsh file is ASCII");
1069   PetscCheck(gmsh->binary || !fileType, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Viewer is ASCII but Gmsh file is binary");
1070   PetscCheck(fileFormat > 40 || dataSize == sizeof(double), PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Data size %d is not valid for a Gmsh file", dataSize);
1071   PetscCheck(fileFormat < 41 || dataSize == sizeof(int) || dataSize == sizeof(PetscInt64), PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Data size %d is not valid for a Gmsh file", dataSize);
1072   gmsh->fileFormat = fileFormat;
1073   gmsh->dataSize   = dataSize;
1074   gmsh->byteSwap   = PETSC_FALSE;
1075   if (gmsh->binary) {
1076     PetscCall(GmshReadInt(gmsh, &checkEndian, 1));
1077     if (checkEndian != 1) {
1078       PetscCall(PetscByteSwap(&checkEndian, PETSC_ENUM, 1));
1079       PetscCheck(checkEndian == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to detect endianness in Gmsh file header: %s", line);
1080       gmsh->byteSwap = PETSC_TRUE;
1081     }
1082   }
1083   PetscFunctionReturn(PETSC_SUCCESS);
1084 }
1085 
1086 /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
1087 Neper: https://neper.info/ adds this section
1088 
1089 $MeshVersion
1090   <major>.<minor>,<patch>
1091 $EndMeshVersion
1092 */
1093 static PetscErrorCode GmshReadMeshVersion(GmshFile *gmsh)
1094 {
1095   char line[PETSC_MAX_PATH_LEN];
1096   int  snum, major, minor, patch;
1097 
1098   PetscFunctionBegin;
1099   PetscCall(GmshReadString(gmsh, line, 1));
1100   snum = sscanf(line, "%d.%d.%d", &major, &minor, &patch);
1101   PetscCheck(snum == 3, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to parse Gmsh file header: %s", line);
1102   PetscFunctionReturn(PETSC_SUCCESS);
1103 }
1104 
1105 /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
1106 Neper: https://neper.info/ adds this section
1107 
1108 $Domain
1109   <shape>
1110 $EndDomain
1111 */
1112 static PetscErrorCode GmshReadMeshDomain(GmshFile *gmsh)
1113 {
1114   char line[PETSC_MAX_PATH_LEN];
1115 
1116   PetscFunctionBegin;
1117   PetscCall(GmshReadString(gmsh, line, 1));
1118   PetscFunctionReturn(PETSC_SUCCESS);
1119 }
1120 
1121 /*
1122 PhysicalNames
1123   numPhysicalNames(ASCII int)
1124   dimension(ASCII int) physicalTag(ASCII int) "name"(127 characters max)
1125   ...
1126 $EndPhysicalNames
1127 */
1128 static PetscErrorCode GmshReadPhysicalNames(GmshFile *gmsh, GmshMesh *mesh)
1129 {
1130   char line[PETSC_MAX_PATH_LEN], name[128 + 2], *p = NULL, *q = NULL, *r = NULL;
1131   int  snum, region, dim, tag;
1132 
1133   PetscFunctionBegin;
1134   PetscCall(GmshReadString(gmsh, line, 1));
1135   snum             = sscanf(line, "%d", &region);
1136   mesh->numRegions = region;
1137   PetscCheck(snum == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
1138   PetscCall(PetscMalloc3(mesh->numRegions, &mesh->regionDims, mesh->numRegions, &mesh->regionTags, mesh->numRegions, &mesh->regionNames));
1139   for (region = 0; region < mesh->numRegions; ++region) {
1140     PetscCall(GmshReadString(gmsh, line, 2));
1141     snum = sscanf(line, "%d %d", &dim, &tag);
1142     PetscCheck(snum == 2, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
1143     PetscCall(GmshReadString(gmsh, line, -(PetscInt)sizeof(line)));
1144     PetscCall(PetscStrchr(line, '"', &p));
1145     PetscCheck(p, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
1146     PetscCall(PetscStrrchr(line, '"', &q));
1147     PetscCheck(q != p, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
1148     PetscCall(PetscStrrchr(line, ':', &r));
1149     if (p != r) q = r;
1150     PetscCall(PetscStrncpy(name, p + 1, (size_t)(q - p - 1)));
1151     mesh->regionDims[region] = dim;
1152     mesh->regionTags[region] = tag;
1153     PetscCall(PetscStrallocpy(name, &mesh->regionNames[region]));
1154   }
1155   PetscFunctionReturn(PETSC_SUCCESS);
1156 }
1157 
1158 static PetscErrorCode GmshReadEntities(GmshFile *gmsh, GmshMesh *mesh)
1159 {
1160   PetscFunctionBegin;
1161   switch (gmsh->fileFormat) {
1162   case 41:
1163     PetscCall(GmshReadEntities_v41(gmsh, mesh));
1164     break;
1165   default:
1166     PetscCall(GmshReadEntities_v40(gmsh, mesh));
1167     break;
1168   }
1169   PetscFunctionReturn(PETSC_SUCCESS);
1170 }
1171 
1172 static PetscErrorCode GmshReadNodes(GmshFile *gmsh, GmshMesh *mesh)
1173 {
1174   PetscFunctionBegin;
1175   switch (gmsh->fileFormat) {
1176   case 41:
1177     PetscCall(GmshReadNodes_v41(gmsh, mesh));
1178     break;
1179   case 40:
1180     PetscCall(GmshReadNodes_v40(gmsh, mesh));
1181     break;
1182   default:
1183     PetscCall(GmshReadNodes_v22(gmsh, mesh));
1184     break;
1185   }
1186 
1187   { /* Gmsh v2.2/v4.0 does not provide min/max node tags */
1188     if (mesh->numNodes > 0 && gmsh->nodeEnd >= gmsh->nodeStart) {
1189       PetscInt   tagMin = PETSC_MAX_INT, tagMax = PETSC_MIN_INT, n;
1190       GmshNodes *nodes = mesh->nodelist;
1191       for (n = 0; n < mesh->numNodes; ++n) {
1192         const PetscInt tag = nodes->id[n];
1193         tagMin             = PetscMin(tag, tagMin);
1194         tagMax             = PetscMax(tag, tagMax);
1195       }
1196       gmsh->nodeStart = tagMin;
1197       gmsh->nodeEnd   = tagMax + 1;
1198     }
1199   }
1200 
1201   { /* Support for sparse node tags */
1202     PetscInt   n, t;
1203     GmshNodes *nodes = mesh->nodelist;
1204     PetscCall(PetscMalloc1(gmsh->nodeEnd - gmsh->nodeStart, &gmsh->nbuf));
1205     for (t = 0; t < gmsh->nodeEnd - gmsh->nodeStart; ++t) gmsh->nbuf[t] = PETSC_MIN_INT;
1206     gmsh->nodeMap = gmsh->nbuf - gmsh->nodeStart;
1207     for (n = 0; n < mesh->numNodes; ++n) {
1208       const PetscInt tag = nodes->id[n];
1209       PetscCheck(gmsh->nodeMap[tag] < 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Repeated node tag %" PetscInt_FMT, tag);
1210       gmsh->nodeMap[tag] = n;
1211     }
1212   }
1213   PetscFunctionReturn(PETSC_SUCCESS);
1214 }
1215 
1216 static PetscErrorCode GmshReadElements(GmshFile *gmsh, GmshMesh *mesh)
1217 {
1218   PetscFunctionBegin;
1219   switch (gmsh->fileFormat) {
1220   case 41:
1221     PetscCall(GmshReadElements_v41(gmsh, mesh));
1222     break;
1223   case 40:
1224     PetscCall(GmshReadElements_v40(gmsh, mesh));
1225     break;
1226   default:
1227     PetscCall(GmshReadElements_v22(gmsh, mesh));
1228     break;
1229   }
1230 
1231   { /* Reorder elements by codimension and polytope type */
1232     PetscInt     ne       = mesh->numElems;
1233     GmshElement *elements = mesh->elements;
1234     PetscInt     keymap[GMSH_NUM_POLYTOPES], nk = 0;
1235     PetscInt     offset[GMSH_NUM_POLYTOPES + 1], e, k;
1236 
1237     for (k = 0; k < GMSH_NUM_POLYTOPES; ++k) keymap[k] = PETSC_MIN_INT;
1238     PetscCall(PetscMemzero(offset, sizeof(offset)));
1239 
1240     keymap[GMSH_TET] = nk++;
1241     keymap[GMSH_HEX] = nk++;
1242     keymap[GMSH_PRI] = nk++;
1243     keymap[GMSH_PYR] = nk++;
1244     keymap[GMSH_TRI] = nk++;
1245     keymap[GMSH_QUA] = nk++;
1246     keymap[GMSH_SEG] = nk++;
1247     keymap[GMSH_VTX] = nk++;
1248 
1249     PetscCall(GmshElementsCreate(mesh->numElems, &mesh->elements));
1250 #define key(eid) keymap[GmshCellMap[elements[eid].cellType].polytope]
1251     for (e = 0; e < ne; ++e) offset[1 + key(e)]++;
1252     for (k = 1; k < nk; ++k) offset[k] += offset[k - 1];
1253     for (e = 0; e < ne; ++e) mesh->elements[offset[key(e)]++] = elements[e];
1254 #undef key
1255     PetscCall(GmshElementsDestroy(&elements));
1256   }
1257 
1258   { /* Mesh dimension and order */
1259     GmshElement *elem = mesh->numElems ? mesh->elements : NULL;
1260     mesh->dim         = elem ? GmshCellMap[elem->cellType].dim : 0;
1261     mesh->order       = elem ? GmshCellMap[elem->cellType].order : 0;
1262   }
1263 
1264   {
1265     PetscBT  vtx;
1266     PetscInt dim = mesh->dim, e, n, v;
1267 
1268     PetscCall(PetscBTCreate(mesh->numNodes, &vtx));
1269 
1270     /* Compute number of cells and set of vertices */
1271     mesh->numCells = 0;
1272     for (e = 0; e < mesh->numElems; ++e) {
1273       GmshElement *elem = mesh->elements + e;
1274       if (elem->dim == dim && dim > 0) mesh->numCells++;
1275       for (v = 0; v < elem->numVerts; v++) PetscCall(PetscBTSet(vtx, elem->nodes[v]));
1276     }
1277 
1278     /* Compute numbering for vertices */
1279     mesh->numVerts = 0;
1280     PetscCall(PetscMalloc1(mesh->numNodes, &mesh->vertexMap));
1281     for (n = 0; n < mesh->numNodes; ++n) mesh->vertexMap[n] = PetscBTLookup(vtx, n) ? mesh->numVerts++ : PETSC_MIN_INT;
1282 
1283     PetscCall(PetscBTDestroy(&vtx));
1284   }
1285   PetscFunctionReturn(PETSC_SUCCESS);
1286 }
1287 
1288 static PetscErrorCode GmshReadPeriodic(GmshFile *gmsh, GmshMesh *mesh)
1289 {
1290   PetscInt n;
1291 
1292   PetscFunctionBegin;
1293   PetscCall(PetscMalloc1(mesh->numNodes, &mesh->periodMap));
1294   for (n = 0; n < mesh->numNodes; ++n) mesh->periodMap[n] = n;
1295   switch (gmsh->fileFormat) {
1296   case 41:
1297     PetscCall(GmshReadPeriodic_v41(gmsh, mesh->periodMap));
1298     break;
1299   default:
1300     PetscCall(GmshReadPeriodic_v40(gmsh, mesh->periodMap));
1301     break;
1302   }
1303 
1304   /* Find canonical primary nodes */
1305   for (n = 0; n < mesh->numNodes; ++n)
1306     while (mesh->periodMap[n] != mesh->periodMap[mesh->periodMap[n]]) mesh->periodMap[n] = mesh->periodMap[mesh->periodMap[n]];
1307 
1308   /* Renumber vertices (filter out correspondings) */
1309   mesh->numVerts = 0;
1310   for (n = 0; n < mesh->numNodes; ++n)
1311     if (mesh->vertexMap[n] >= 0)   /* is vertex */
1312       if (mesh->periodMap[n] == n) /* is primary */
1313         mesh->vertexMap[n] = mesh->numVerts++;
1314   for (n = 0; n < mesh->numNodes; ++n)
1315     if (mesh->vertexMap[n] >= 0)   /* is vertex */
1316       if (mesh->periodMap[n] != n) /* is corresponding  */
1317         mesh->vertexMap[n] = mesh->vertexMap[mesh->periodMap[n]];
1318   PetscFunctionReturn(PETSC_SUCCESS);
1319 }
1320 
1321 #define DM_POLYTOPE_VERTEX DM_POLYTOPE_POINT
1322 static const DMPolytopeType DMPolytopeMap[] = {
1323   /* GMSH_VTX */ DM_POLYTOPE_VERTEX,
1324   /* GMSH_SEG */ DM_POLYTOPE_SEGMENT,
1325   /* GMSH_TRI */ DM_POLYTOPE_TRIANGLE,
1326   /* GMSH_QUA */ DM_POLYTOPE_QUADRILATERAL,
1327   /* GMSH_TET */ DM_POLYTOPE_TETRAHEDRON,
1328   /* GMSH_HEX */ DM_POLYTOPE_HEXAHEDRON,
1329   /* GMSH_PRI */ DM_POLYTOPE_TRI_PRISM,
1330   /* GMSH_PYR */ DM_POLYTOPE_PYRAMID,       DM_POLYTOPE_UNKNOWN};
1331 
1332 static inline DMPolytopeType DMPolytopeTypeFromGmsh(PetscInt cellType)
1333 {
1334   return DMPolytopeMap[GmshCellMap[cellType].polytope];
1335 }
1336 
1337 static PetscErrorCode GmshCreateFE(MPI_Comm comm, const char prefix[], PetscBool isSimplex, PetscBool continuity, PetscDTNodeType nodeType, PetscInt dim, PetscInt Nc, PetscInt k, PetscFE *fem)
1338 {
1339   DM              K;
1340   PetscSpace      P;
1341   PetscDualSpace  Q;
1342   PetscQuadrature q, fq;
1343   PetscBool       isTensor = isSimplex ? PETSC_FALSE : PETSC_TRUE;
1344   PetscBool       endpoint = PETSC_TRUE;
1345   char            name[32];
1346 
1347   PetscFunctionBegin;
1348   /* Create space */
1349   PetscCall(PetscSpaceCreate(comm, &P));
1350   PetscCall(PetscSpaceSetType(P, PETSCSPACEPOLYNOMIAL));
1351   PetscCall(PetscSpacePolynomialSetTensor(P, isTensor));
1352   PetscCall(PetscSpaceSetNumComponents(P, Nc));
1353   PetscCall(PetscSpaceSetNumVariables(P, dim));
1354   PetscCall(PetscSpaceSetDegree(P, k, PETSC_DETERMINE));
1355   if (prefix) {
1356     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)P, prefix));
1357     PetscCall(PetscSpaceSetFromOptions(P));
1358     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)P, NULL));
1359     PetscCall(PetscSpaceGetDegree(P, &k, NULL));
1360   }
1361   PetscCall(PetscSpaceSetUp(P));
1362   /* Create dual space */
1363   PetscCall(PetscDualSpaceCreate(comm, &Q));
1364   PetscCall(PetscDualSpaceSetType(Q, PETSCDUALSPACELAGRANGE));
1365   PetscCall(PetscDualSpaceLagrangeSetTensor(Q, isTensor));
1366   PetscCall(PetscDualSpaceLagrangeSetContinuity(Q, continuity));
1367   PetscCall(PetscDualSpaceLagrangeSetNodeType(Q, nodeType, endpoint, 0));
1368   PetscCall(PetscDualSpaceSetNumComponents(Q, Nc));
1369   PetscCall(PetscDualSpaceSetOrder(Q, k));
1370   PetscCall(DMPlexCreateReferenceCell(PETSC_COMM_SELF, DMPolytopeTypeSimpleShape(dim, isSimplex), &K));
1371   PetscCall(PetscDualSpaceSetDM(Q, K));
1372   PetscCall(DMDestroy(&K));
1373   if (prefix) {
1374     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)Q, prefix));
1375     PetscCall(PetscDualSpaceSetFromOptions(Q));
1376     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)Q, NULL));
1377   }
1378   PetscCall(PetscDualSpaceSetUp(Q));
1379   /* Create quadrature */
1380   if (isSimplex) {
1381     PetscCall(PetscDTStroudConicalQuadrature(dim, 1, k + 1, -1, +1, &q));
1382     PetscCall(PetscDTStroudConicalQuadrature(dim - 1, 1, k + 1, -1, +1, &fq));
1383   } else {
1384     PetscCall(PetscDTGaussTensorQuadrature(dim, 1, k + 1, -1, +1, &q));
1385     PetscCall(PetscDTGaussTensorQuadrature(dim - 1, 1, k + 1, -1, +1, &fq));
1386   }
1387   /* Create finite element */
1388   PetscCall(PetscFECreate(comm, fem));
1389   PetscCall(PetscFESetType(*fem, PETSCFEBASIC));
1390   PetscCall(PetscFESetNumComponents(*fem, Nc));
1391   PetscCall(PetscFESetBasisSpace(*fem, P));
1392   PetscCall(PetscFESetDualSpace(*fem, Q));
1393   PetscCall(PetscFESetQuadrature(*fem, q));
1394   PetscCall(PetscFESetFaceQuadrature(*fem, fq));
1395   if (prefix) {
1396     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*fem, prefix));
1397     PetscCall(PetscFESetFromOptions(*fem));
1398     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*fem, NULL));
1399   }
1400   PetscCall(PetscFESetUp(*fem));
1401   /* Cleanup */
1402   PetscCall(PetscSpaceDestroy(&P));
1403   PetscCall(PetscDualSpaceDestroy(&Q));
1404   PetscCall(PetscQuadratureDestroy(&q));
1405   PetscCall(PetscQuadratureDestroy(&fq));
1406   /* Set finite element name */
1407   PetscCall(PetscSNPrintf(name, sizeof(name), "%s%" PetscInt_FMT, isSimplex ? "P" : "Q", k));
1408   PetscCall(PetscFESetName(*fem, name));
1409   PetscFunctionReturn(PETSC_SUCCESS);
1410 }
1411 
1412 /*@
1413   DMPlexCreateGmshFromFile - Create a `DMPLEX` mesh from a Gmsh file
1414 
1415   Input Parameters:
1416 + comm        - The MPI communicator
1417 . filename    - Name of the Gmsh file
1418 - interpolate - Create faces and edges in the mesh
1419 
1420   Output Parameter:
1421 . dm - The `DM` object representing the mesh
1422 
1423   Level: beginner
1424 
1425 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromFile()`, `DMPlexCreateGmsh()`, `DMPlexCreate()`
1426 @*/
1427 PetscErrorCode DMPlexCreateGmshFromFile(MPI_Comm comm, const char filename[], PetscBool interpolate, DM *dm)
1428 {
1429   PetscViewer     viewer;
1430   PetscMPIInt     rank;
1431   int             fileType;
1432   PetscViewerType vtype;
1433 
1434   PetscFunctionBegin;
1435   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1436 
1437   /* Determine Gmsh file type (ASCII or binary) from file header */
1438   if (rank == 0) {
1439     GmshFile gmsh[1];
1440     char     line[PETSC_MAX_PATH_LEN];
1441     int      snum;
1442     float    version;
1443     int      fileFormat;
1444 
1445     PetscCall(PetscArrayzero(gmsh, 1));
1446     PetscCall(PetscViewerCreate(PETSC_COMM_SELF, &gmsh->viewer));
1447     PetscCall(PetscViewerSetType(gmsh->viewer, PETSCVIEWERASCII));
1448     PetscCall(PetscViewerFileSetMode(gmsh->viewer, FILE_MODE_READ));
1449     PetscCall(PetscViewerFileSetName(gmsh->viewer, filename));
1450     /* Read only the first two lines of the Gmsh file */
1451     PetscCall(GmshReadSection(gmsh, line));
1452     PetscCall(GmshExpect(gmsh, "$MeshFormat", line));
1453     PetscCall(GmshReadString(gmsh, line, 2));
1454     snum       = sscanf(line, "%f %d", &version, &fileType);
1455     fileFormat = (int)roundf(version * 10);
1456     PetscCheck(snum == 2, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to parse Gmsh file header: %s", line);
1457     PetscCheck(fileFormat >= 22, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at least 2.2", (double)version);
1458     PetscCheck((int)version != 3, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f not supported", (double)version);
1459     PetscCheck(fileFormat <= 41, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at most 4.1", (double)version);
1460     PetscCall(PetscViewerDestroy(&gmsh->viewer));
1461   }
1462   PetscCallMPI(MPI_Bcast(&fileType, 1, MPI_INT, 0, comm));
1463   vtype = (fileType == 0) ? PETSCVIEWERASCII : PETSCVIEWERBINARY;
1464 
1465   /* Create appropriate viewer and build plex */
1466   PetscCall(PetscViewerCreate(comm, &viewer));
1467   PetscCall(PetscViewerSetType(viewer, vtype));
1468   PetscCall(PetscViewerFileSetMode(viewer, FILE_MODE_READ));
1469   PetscCall(PetscViewerFileSetName(viewer, filename));
1470   PetscCall(DMPlexCreateGmsh(comm, viewer, interpolate, dm));
1471   PetscCall(PetscViewerDestroy(&viewer));
1472   PetscFunctionReturn(PETSC_SUCCESS);
1473 }
1474 
1475 /*@
1476   DMPlexCreateGmsh - Create a `DMPLEX` mesh from a Gmsh file viewer
1477 
1478   Collective
1479 
1480   Input Parameters:
1481 + comm        - The MPI communicator
1482 . viewer      - The `PetscViewer` associated with a Gmsh file
1483 - interpolate - Create faces and edges in the mesh
1484 
1485   Output Parameter:
1486 . dm - The `DM` object representing the mesh
1487 
1488   Options Database Keys:
1489 + -dm_plex_gmsh_hybrid        - Force triangular prisms to use tensor order
1490 . -dm_plex_gmsh_periodic      - Read Gmsh periodic section and construct a periodic Plex
1491 . -dm_plex_gmsh_highorder     - Generate high-order coordinates
1492 . -dm_plex_gmsh_project       - Project high-order coordinates to a different space, use the prefix dm_plex_gmsh_project_ to define the space
1493 . -dm_plex_gmsh_use_generic   - Generate generic labels, i.e. Cell Sets, Face Sets, etc.
1494 . -dm_plex_gmsh_use_regions   - Generate labels with region names
1495 . -dm_plex_gmsh_mark_vertices - Add vertices to generated labels
1496 . -dm_plex_gmsh_multiple_tags - Allow multiple tags for default labels
1497 - -dm_plex_gmsh_spacedim <d>  - Embedding space dimension, if different from topological dimension
1498 
1499   Level: beginner
1500 
1501   Notes:
1502   The Gmsh file format is described in <http://gmsh.info/doc/texinfo/gmsh.html#MSH-file-format>
1503 
1504   By default, the "Cell Sets", "Face Sets", and "Vertex Sets" labels are created, and only insert the first tag on a point. By using -dm_plex_gmsh_multiple_tags, all tags can be inserted. Alternatively, -dm_plex_gmsh_use_regions creates labels based on the region names from the PhysicalNames section, and all tags are used, but you can retain the generic labels using -dm_plex_gmsh_use_generic.
1505 
1506 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`
1507 @*/
1508 PetscErrorCode DMPlexCreateGmsh(MPI_Comm comm, PetscViewer viewer, PetscBool interpolate, DM *dm)
1509 {
1510   GmshMesh    *mesh          = NULL;
1511   PetscViewer  parentviewer  = NULL;
1512   PetscBT      periodicVerts = NULL;
1513   PetscBT     *periodicCells = NULL;
1514   DM           cdm, cdmCell = NULL;
1515   PetscSection cs, csCell   = NULL;
1516   Vec          coordinates, coordinatesCell;
1517   DMLabel      cellSets = NULL, faceSets = NULL, edgeSets = NULL, vertSets = NULL, marker = NULL, *regionSets;
1518   PetscInt     dim = 0, coordDim = -1, order = 0, maxHeight = 0;
1519   PetscInt     numNodes = 0, numElems = 0, numVerts = 0, numCells = 0, vStart, vEnd;
1520   PetscInt     cell, cone[8], e, n, v, d;
1521   PetscBool    usegeneric = PETSC_TRUE, useregions = PETSC_FALSE, markvertices = PETSC_FALSE, multipleTags = PETSC_FALSE;
1522   PetscBool    flg, binary, hybrid = interpolate, periodic = PETSC_TRUE;
1523   PetscBool    highOrder = PETSC_TRUE, highOrderSet, project = PETSC_FALSE;
1524   PetscBool    isSimplex = PETSC_FALSE, isHybrid = PETSC_FALSE, hasTetra = PETSC_FALSE;
1525   PetscMPIInt  rank;
1526 
1527   PetscFunctionBegin;
1528   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1529   PetscObjectOptionsBegin((PetscObject)viewer);
1530   PetscOptionsHeadBegin(PetscOptionsObject, "DMPlex Gmsh options");
1531   PetscCall(PetscOptionsBool("-dm_plex_gmsh_hybrid", "Force triangular prisms to use tensor order", "DMPlexCreateGmsh", hybrid, &hybrid, NULL));
1532   PetscCall(PetscOptionsBool("-dm_plex_gmsh_periodic", "Read Gmsh periodic section", "DMPlexCreateGmsh", periodic, &periodic, NULL));
1533   PetscCall(PetscOptionsBool("-dm_plex_gmsh_highorder", "Generate high-order coordinates", "DMPlexCreateGmsh", highOrder, &highOrder, &highOrderSet));
1534   PetscCall(PetscOptionsBool("-dm_plex_gmsh_project", "Project high-order coordinates to a different space", "DMPlexCreateGmsh", project, &project, NULL));
1535   PetscCall(PetscOptionsBool("-dm_plex_gmsh_use_regions", "Generate labels with region names", "DMPlexCreateGmsh", useregions, &useregions, NULL));
1536   PetscCall(PetscOptionsBool("-dm_plex_gmsh_use_generic", "Generate generic labels, i.e. Cell Sets, Face Sets, etc", "DMPlexCreateGmsh", usegeneric, &usegeneric, &flg));
1537   if (!flg && useregions) usegeneric = PETSC_FALSE;
1538   PetscCall(PetscOptionsBool("-dm_plex_gmsh_mark_vertices", "Add vertices to generated labels", "DMPlexCreateGmsh", markvertices, &markvertices, NULL));
1539   PetscCall(PetscOptionsBool("-dm_plex_gmsh_multiple_tags", "Allow multiple tags for default labels", "DMPlexCreateGmsh", multipleTags, &multipleTags, NULL));
1540   PetscCall(PetscOptionsBoundedInt("-dm_plex_gmsh_spacedim", "Embedding space dimension", "DMPlexCreateGmsh", coordDim, &coordDim, NULL, PETSC_DECIDE));
1541   PetscCall(PetscOptionsBoundedInt("-dm_localize_height", "Localize edges and faces in addition to cells", "", maxHeight, &maxHeight, NULL, 0));
1542   PetscOptionsHeadEnd();
1543   PetscOptionsEnd();
1544 
1545   PetscCall(GmshCellInfoSetUp());
1546 
1547   PetscCall(DMCreate(comm, dm));
1548   PetscCall(DMSetType(*dm, DMPLEX));
1549   PetscCall(PetscLogEventBegin(DMPLEX_CreateGmsh, *dm, NULL, NULL, NULL));
1550 
1551   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &binary));
1552 
1553   /* Binary viewers read on all ranks, get subviewer to read only in rank 0 */
1554   if (binary) {
1555     parentviewer = viewer;
1556     PetscCall(PetscViewerGetSubViewer(parentviewer, PETSC_COMM_SELF, &viewer));
1557   }
1558 
1559   if (rank == 0) {
1560     GmshFile  gmsh[1];
1561     char      line[PETSC_MAX_PATH_LEN];
1562     PetscBool match;
1563 
1564     PetscCall(PetscArrayzero(gmsh, 1));
1565     gmsh->viewer = viewer;
1566     gmsh->binary = binary;
1567 
1568     PetscCall(GmshMeshCreate(&mesh));
1569 
1570     /* Read mesh format */
1571     PetscCall(GmshReadSection(gmsh, line));
1572     PetscCall(GmshExpect(gmsh, "$MeshFormat", line));
1573     PetscCall(GmshReadMeshFormat(gmsh));
1574     PetscCall(GmshReadEndSection(gmsh, "$EndMeshFormat", line));
1575 
1576     /* OPTIONAL Read mesh version (Neper only) */
1577     PetscCall(GmshReadSection(gmsh, line));
1578     PetscCall(GmshMatch(gmsh, "$MeshVersion", line, &match));
1579     if (match) {
1580       PetscCall(GmshExpect(gmsh, "$MeshVersion", line));
1581       PetscCall(GmshReadMeshVersion(gmsh));
1582       PetscCall(GmshReadEndSection(gmsh, "$EndMeshVersion", line));
1583       /* Initial read for entity section */
1584       PetscCall(GmshReadSection(gmsh, line));
1585     }
1586 
1587     /* OPTIONAL Read mesh domain (Neper only) */
1588     PetscCall(GmshMatch(gmsh, "$Domain", line, &match));
1589     if (match) {
1590       PetscCall(GmshExpect(gmsh, "$Domain", line));
1591       PetscCall(GmshReadMeshDomain(gmsh));
1592       PetscCall(GmshReadEndSection(gmsh, "$EndDomain", line));
1593       /* Initial read for entity section */
1594       PetscCall(GmshReadSection(gmsh, line));
1595     }
1596 
1597     /* OPTIONAL Read physical names */
1598     PetscCall(GmshMatch(gmsh, "$PhysicalNames", line, &match));
1599     if (match) {
1600       PetscCall(GmshExpect(gmsh, "$PhysicalNames", line));
1601       PetscCall(GmshReadPhysicalNames(gmsh, mesh));
1602       PetscCall(GmshReadEndSection(gmsh, "$EndPhysicalNames", line));
1603       /* Initial read for entity section */
1604       PetscCall(GmshReadSection(gmsh, line));
1605     }
1606 
1607     /* OPTIONAL Read entities */
1608     if (gmsh->fileFormat >= 40) {
1609       PetscCall(GmshMatch(gmsh, "$Entities", line, &match));
1610       if (match) {
1611         PetscCall(GmshExpect(gmsh, "$Entities", line));
1612         PetscCall(GmshReadEntities(gmsh, mesh));
1613         PetscCall(GmshReadEndSection(gmsh, "$EndEntities", line));
1614         /* Initial read for nodes section */
1615         PetscCall(GmshReadSection(gmsh, line));
1616       }
1617     }
1618 
1619     /* Read nodes */
1620     PetscCall(GmshExpect(gmsh, "$Nodes", line));
1621     PetscCall(GmshReadNodes(gmsh, mesh));
1622     PetscCall(GmshReadEndSection(gmsh, "$EndNodes", line));
1623 
1624     /* Read elements */
1625     PetscCall(GmshReadSection(gmsh, line));
1626     PetscCall(GmshExpect(gmsh, "$Elements", line));
1627     PetscCall(GmshReadElements(gmsh, mesh));
1628     PetscCall(GmshReadEndSection(gmsh, "$EndElements", line));
1629 
1630     /* Read periodic section (OPTIONAL) */
1631     if (periodic) {
1632       PetscCall(GmshReadSection(gmsh, line));
1633       PetscCall(GmshMatch(gmsh, "$Periodic", line, &periodic));
1634     }
1635     if (periodic) {
1636       PetscCall(GmshExpect(gmsh, "$Periodic", line));
1637       PetscCall(GmshReadPeriodic(gmsh, mesh));
1638       PetscCall(GmshReadEndSection(gmsh, "$EndPeriodic", line));
1639     }
1640 
1641     PetscCall(PetscFree(gmsh->wbuf));
1642     PetscCall(PetscFree(gmsh->sbuf));
1643     PetscCall(PetscFree(gmsh->nbuf));
1644 
1645     dim      = mesh->dim;
1646     order    = mesh->order;
1647     numNodes = mesh->numNodes;
1648     numElems = mesh->numElems;
1649     numVerts = mesh->numVerts;
1650     numCells = mesh->numCells;
1651 
1652     {
1653       GmshElement *elemA = mesh->numCells > 0 ? mesh->elements : NULL;
1654       GmshElement *elemB = PetscSafePointerPlusOffset(elemA, mesh->numCells - 1);
1655       int          ptA   = elemA ? GmshCellMap[elemA->cellType].polytope : -1;
1656       int          ptB   = elemB ? GmshCellMap[elemB->cellType].polytope : -1;
1657       isSimplex          = (ptA == GMSH_QUA || ptA == GMSH_HEX) ? PETSC_FALSE : PETSC_TRUE;
1658       isHybrid           = (ptA == ptB) ? PETSC_FALSE : PETSC_TRUE;
1659       hasTetra           = (ptA == GMSH_TET) ? PETSC_TRUE : PETSC_FALSE;
1660     }
1661   }
1662 
1663   if (parentviewer) PetscCall(PetscViewerRestoreSubViewer(parentviewer, PETSC_COMM_SELF, &viewer));
1664 
1665   {
1666     int buf[6];
1667 
1668     buf[0] = (int)dim;
1669     buf[1] = (int)order;
1670     buf[2] = periodic;
1671     buf[3] = isSimplex;
1672     buf[4] = isHybrid;
1673     buf[5] = hasTetra;
1674 
1675     PetscCallMPI(MPI_Bcast(buf, 6, MPI_INT, 0, comm));
1676 
1677     dim       = buf[0];
1678     order     = buf[1];
1679     periodic  = buf[2] ? PETSC_TRUE : PETSC_FALSE;
1680     isSimplex = buf[3] ? PETSC_TRUE : PETSC_FALSE;
1681     isHybrid  = buf[4] ? PETSC_TRUE : PETSC_FALSE;
1682     hasTetra  = buf[5] ? PETSC_TRUE : PETSC_FALSE;
1683   }
1684 
1685   if (!highOrderSet) highOrder = (order > 1) ? PETSC_TRUE : PETSC_FALSE;
1686   PetscCheck(!highOrder || !isHybrid, comm, PETSC_ERR_SUP, "No support for discretization on hybrid meshes yet");
1687 
1688   /* We do not want this label automatically computed, instead we fill it here */
1689   PetscCall(DMCreateLabel(*dm, "celltype"));
1690 
1691   /* Allocate the cell-vertex mesh */
1692   PetscCall(DMPlexSetChart(*dm, 0, numCells + numVerts));
1693   for (cell = 0; cell < numCells; ++cell) {
1694     GmshElement   *elem  = mesh->elements + cell;
1695     DMPolytopeType ctype = DMPolytopeTypeFromGmsh(elem->cellType);
1696     if (hybrid && hasTetra && ctype == DM_POLYTOPE_TRI_PRISM) ctype = DM_POLYTOPE_TRI_PRISM_TENSOR;
1697     PetscCall(DMPlexSetConeSize(*dm, cell, elem->numVerts));
1698     PetscCall(DMPlexSetCellType(*dm, cell, ctype));
1699   }
1700   for (v = numCells; v < numCells + numVerts; ++v) PetscCall(DMPlexSetCellType(*dm, v, DM_POLYTOPE_POINT));
1701   PetscCall(DMSetUp(*dm));
1702 
1703   /* Add cell-vertex connections */
1704   for (cell = 0; cell < numCells; ++cell) {
1705     GmshElement *elem = mesh->elements + cell;
1706     for (v = 0; v < elem->numVerts; ++v) {
1707       const PetscInt nn = elem->nodes[v];
1708       const PetscInt vv = mesh->vertexMap[nn];
1709       cone[v]           = numCells + vv;
1710     }
1711     PetscCall(DMPlexReorderCell(*dm, cell, cone));
1712     PetscCall(DMPlexSetCone(*dm, cell, cone));
1713   }
1714 
1715   PetscCall(DMSetDimension(*dm, dim));
1716   PetscCall(DMPlexSymmetrize(*dm));
1717   PetscCall(DMPlexStratify(*dm));
1718   if (interpolate) {
1719     DM idm;
1720 
1721     PetscCall(DMPlexInterpolate(*dm, &idm));
1722     PetscCall(DMDestroy(dm));
1723     *dm = idm;
1724   }
1725   PetscCall(DMPlexGetDepthStratum(*dm, 0, &vStart, &vEnd));
1726 
1727   if (rank == 0) {
1728     const PetscInt Nr = useregions ? mesh->numRegions : 0;
1729 
1730     PetscCall(PetscCalloc1(Nr, &regionSets));
1731     for (cell = 0, e = 0; e < numElems; ++e) {
1732       GmshElement *elem = mesh->elements + e;
1733 
1734       /* Create cell sets */
1735       if (elem->dim == dim && dim > 0) {
1736         if (elem->numTags > 0) {
1737           PetscInt Nt = elem->numTags, t, r;
1738 
1739           for (t = 0; t < Nt; ++t) {
1740             const PetscInt  tag     = elem->tags[t];
1741             const PetscBool generic = usegeneric && (!t || multipleTags) ? PETSC_TRUE : PETSC_FALSE;
1742 
1743             if (generic) PetscCall(DMSetLabelValue_Fast(*dm, &cellSets, "Cell Sets", cell, tag));
1744             for (r = 0; r < Nr; ++r) {
1745               if (mesh->regionDims[r] != dim) continue;
1746               if (mesh->regionTags[r] == tag) PetscCall(DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], cell, tag));
1747             }
1748           }
1749         }
1750         cell++;
1751       }
1752 
1753       /* Create face sets */
1754       if (elem->numTags && interpolate && elem->dim == dim - 1) {
1755         PetscInt        joinSize;
1756         const PetscInt *join = NULL;
1757         PetscInt        Nt   = elem->numTags, pdepth;
1758 
1759         /* Find the relevant facet with vertex joins */
1760         for (v = 0; v < elem->numVerts; ++v) {
1761           const PetscInt nn = elem->nodes[v];
1762           const PetscInt vv = mesh->vertexMap[nn];
1763           cone[v]           = vStart + vv;
1764         }
1765         PetscCall(DMPlexGetFullJoin(*dm, elem->numVerts, cone, &joinSize, &join));
1766         PetscCheck(joinSize == 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Could not determine Plex facet for Gmsh element %" PetscInt_FMT " (Plex cell %" PetscInt_FMT ")", elem->id, e);
1767         PetscCall(DMPlexGetPointDepth(*dm, join[0], &pdepth));
1768         PetscCheck(pdepth == dim - 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Plex facet %" PetscInt_FMT " for Gmsh element %" PetscInt_FMT " had depth %" PetscInt_FMT " != %" PetscInt_FMT, join[0], elem->id, pdepth, dim - 1);
1769         for (PetscInt t = 0; t < Nt; ++t) {
1770           const PetscInt  tag     = elem->tags[t];
1771           const PetscBool generic = usegeneric && (!t || multipleTags) ? PETSC_TRUE : PETSC_FALSE;
1772 
1773           if (generic) PetscCall(DMSetLabelValue_Fast(*dm, &faceSets, "Face Sets", join[0], tag));
1774           for (PetscInt r = 0; r < Nr; ++r) {
1775             if (mesh->regionDims[r] != dim - 1) continue;
1776             if (mesh->regionTags[r] == tag) PetscCall(DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], join[0], tag));
1777           }
1778         }
1779         PetscCall(DMPlexRestoreJoin(*dm, elem->numVerts, cone, &joinSize, &join));
1780       }
1781 
1782       /* Create edge sets */
1783       if (elem->numTags && interpolate && dim > 2 && elem->dim == 1) {
1784         PetscInt        joinSize;
1785         const PetscInt *join = NULL;
1786         PetscInt        Nt   = elem->numTags, t, r;
1787 
1788         /* Find the relevant edge with vertex joins */
1789         for (v = 0; v < elem->numVerts; ++v) {
1790           const PetscInt nn = elem->nodes[v];
1791           const PetscInt vv = mesh->vertexMap[nn];
1792           cone[v]           = vStart + vv;
1793         }
1794         PetscCall(DMPlexGetJoin(*dm, elem->numVerts, cone, &joinSize, &join));
1795         PetscCheck(joinSize == 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Could not determine Plex edge for Gmsh element %" PetscInt_FMT " (Plex cell %" PetscInt_FMT ")", elem->id, e);
1796         for (t = 0; t < Nt; ++t) {
1797           const PetscInt  tag     = elem->tags[t];
1798           const PetscBool generic = usegeneric && (!t || multipleTags) ? PETSC_TRUE : PETSC_FALSE;
1799 
1800           if (generic) PetscCall(DMSetLabelValue_Fast(*dm, &edgeSets, "Edge Sets", join[0], tag));
1801           for (r = 0; r < Nr; ++r) {
1802             if (mesh->regionDims[r] != 1) continue;
1803             if (mesh->regionTags[r] == tag) PetscCall(DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], join[0], tag));
1804           }
1805         }
1806         PetscCall(DMPlexRestoreJoin(*dm, elem->numVerts, cone, &joinSize, &join));
1807       }
1808 
1809       /* Create vertex sets */
1810       if (elem->numTags && elem->dim == 0 && markvertices) {
1811         const PetscInt nn  = elem->nodes[0];
1812         const PetscInt vv  = mesh->vertexMap[nn];
1813         const PetscInt tag = elem->tags[0];
1814         PetscInt       r;
1815 
1816         if (vv < 0) continue;
1817         if (usegeneric) PetscCall(DMSetLabelValue_Fast(*dm, &vertSets, "Vertex Sets", vStart + vv, tag));
1818         for (r = 0; r < Nr; ++r) {
1819           if (mesh->regionDims[r] != 0) continue;
1820           if (mesh->regionTags[r] == tag) PetscCall(DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], vStart + vv, tag));
1821         }
1822       }
1823     }
1824     if (markvertices) {
1825       for (v = 0; v < numNodes; ++v) {
1826         const PetscInt  vv   = mesh->vertexMap[v];
1827         const PetscInt *tags = &mesh->nodelist->tag[v * GMSH_MAX_TAGS];
1828         PetscInt        r, t;
1829 
1830         if (vv < 0) continue;
1831         for (t = 0; t < GMSH_MAX_TAGS; ++t) {
1832           const PetscInt  tag     = tags[t];
1833           const PetscBool generic = usegeneric && (!t || multipleTags) ? PETSC_TRUE : PETSC_FALSE;
1834 
1835           if (tag == -1) continue;
1836           if (generic) PetscCall(DMSetLabelValue_Fast(*dm, &vertSets, "Vertex Sets", vStart + vv, tag));
1837           for (r = 0; r < Nr; ++r) {
1838             if (mesh->regionTags[r] == tag) PetscCall(DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], vStart + vv, tag));
1839           }
1840         }
1841       }
1842     }
1843     PetscCall(PetscFree(regionSets));
1844   }
1845 
1846   { /* Create Cell/Face/Edge/Vertex Sets labels at all processes */
1847     enum {
1848       n = 5
1849     };
1850     PetscBool flag[n];
1851 
1852     flag[0] = cellSets ? PETSC_TRUE : PETSC_FALSE;
1853     flag[1] = faceSets ? PETSC_TRUE : PETSC_FALSE;
1854     flag[2] = edgeSets ? PETSC_TRUE : PETSC_FALSE;
1855     flag[3] = vertSets ? PETSC_TRUE : PETSC_FALSE;
1856     flag[4] = marker ? PETSC_TRUE : PETSC_FALSE;
1857     PetscCallMPI(MPI_Bcast(flag, n, MPIU_BOOL, 0, comm));
1858     if (flag[0]) PetscCall(DMCreateLabel(*dm, "Cell Sets"));
1859     if (flag[1]) PetscCall(DMCreateLabel(*dm, "Face Sets"));
1860     if (flag[2]) PetscCall(DMCreateLabel(*dm, "Edge Sets"));
1861     if (flag[3]) PetscCall(DMCreateLabel(*dm, "Vertex Sets"));
1862     if (flag[4]) PetscCall(DMCreateLabel(*dm, "marker"));
1863   }
1864 
1865   if (periodic) {
1866     PetscCall(PetscBTCreate(numVerts, &periodicVerts));
1867     for (n = 0; n < numNodes; ++n) {
1868       if (mesh->vertexMap[n] >= 0) {
1869         if (PetscUnlikely(mesh->periodMap[n] != n)) {
1870           PetscInt m = mesh->periodMap[n];
1871           PetscCall(PetscBTSet(periodicVerts, mesh->vertexMap[n]));
1872           PetscCall(PetscBTSet(periodicVerts, mesh->vertexMap[m]));
1873         }
1874       }
1875     }
1876     PetscCall(DMGetCoordinateDM(*dm, &cdm));
1877     PetscCall(PetscMalloc1(maxHeight + 1, &periodicCells));
1878     for (PetscInt h = 0; h <= maxHeight; ++h) {
1879       PetscInt pStart, pEnd;
1880 
1881       PetscCall(DMPlexGetHeightStratum(*dm, h, &pStart, &pEnd));
1882       PetscCall(PetscBTCreate(pEnd - pStart, &periodicCells[h]));
1883       for (PetscInt p = pStart; p < pEnd; ++p) {
1884         PetscInt *closure = NULL;
1885         PetscInt  Ncl;
1886 
1887         PetscCall(DMPlexGetTransitiveClosure(*dm, p, PETSC_TRUE, &Ncl, &closure));
1888         for (PetscInt cl = 0; cl < Ncl * 2; cl += 2) {
1889           if (closure[cl] >= vStart && closure[cl] < vEnd) {
1890             if (PetscUnlikely(PetscBTLookup(periodicVerts, closure[cl] - vStart))) {
1891               PetscCall(PetscBTSet(periodicCells[h], p - pStart));
1892               break;
1893             }
1894           }
1895         }
1896         PetscCall(DMPlexRestoreTransitiveClosure(*dm, p, PETSC_TRUE, &Ncl, &closure));
1897       }
1898     }
1899   }
1900 
1901   /* Setup coordinate DM */
1902   if (coordDim < 0) coordDim = dim;
1903   PetscCall(DMSetCoordinateDim(*dm, coordDim));
1904   PetscCall(DMGetCoordinateDM(*dm, &cdm));
1905   if (highOrder) {
1906     PetscFE         fe;
1907     PetscBool       continuity = periodic ? PETSC_FALSE : PETSC_TRUE;
1908     PetscDTNodeType nodeType   = PETSCDTNODES_EQUISPACED;
1909 
1910     if (isSimplex) continuity = PETSC_FALSE; /* XXX FIXME Requires DMPlexSetClosurePermutationLexicographic() */
1911 
1912     PetscCall(GmshCreateFE(comm, NULL, isSimplex, continuity, nodeType, dim, coordDim, order, &fe));
1913     PetscCall(PetscFEViewFromOptions(fe, NULL, "-dm_plex_gmsh_fe_view"));
1914     PetscCall(DMSetField(cdm, 0, NULL, (PetscObject)fe));
1915     PetscCall(PetscFEDestroy(&fe));
1916     PetscCall(DMCreateDS(cdm));
1917   }
1918   if (periodic) {
1919     PetscCall(DMClone(cdm, &cdmCell));
1920     PetscCall(DMSetCellCoordinateDM(*dm, cdmCell));
1921   }
1922 
1923   /* Create coordinates */
1924   if (highOrder) {
1925     PetscInt     maxDof = GmshNumNodes_HEX(order) * coordDim;
1926     double      *coords = mesh ? mesh->nodelist->xyz : NULL;
1927     PetscSection section;
1928     PetscScalar *cellCoords;
1929 
1930     PetscCall(DMSetLocalSection(cdm, NULL));
1931     PetscCall(DMGetLocalSection(cdm, &cs));
1932     PetscCall(PetscSectionClone(cs, &section));
1933     PetscCall(DMPlexSetClosurePermutationTensor(cdm, 0, section)); /* XXX Implement DMPlexSetClosurePermutationLexicographic() */
1934 
1935     PetscCall(DMCreateLocalVector(cdm, &coordinates));
1936     PetscCall(PetscMalloc1(maxDof, &cellCoords));
1937     for (cell = 0; cell < numCells; ++cell) {
1938       GmshElement *elem     = mesh->elements + cell;
1939       const int   *lexorder = GmshCellMap[elem->cellType].lexorder();
1940       int          s        = 0;
1941       for (n = 0; n < elem->numNodes; ++n) {
1942         while (lexorder[n + s] < 0) ++s;
1943         const PetscInt node = elem->nodes[lexorder[n + s]];
1944         for (d = 0; d < coordDim; ++d) cellCoords[(n + s) * coordDim + d] = (PetscReal)coords[node * 3 + d];
1945       }
1946       if (s) {
1947         /* For the coordinate mapping we weight vertices by -1/4 and edges by 1/2, which we get from Q_2 interpolation */
1948         PetscReal quaCenterWeights[9] = {-0.25, 0.5, -0.25, 0.5, 0.0, 0.5, -0.25, 0.5, -0.25};
1949         /* For the coordinate mapping we weight vertices by -1/4 and edges by 1/2, which we get from Q_2 interpolation */
1950         PetscReal   hexBottomWeights[27] = {-0.25, 0.5, -0.25, 0.5, 0.0, 0.5, -0.25, 0.5, -0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
1951         PetscReal   hexFrontWeights[27]  = {-0.25, 0.5, -0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.25, 0.5, -0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
1952         PetscReal   hexLeftWeights[27]   = {-0.25, 0.0, 0.0, 0.5, 0.0, 0.0, -0.25, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, -0.25, 0.0, 0.0, 0.5, 0.0, 0.0, -0.25, 0.0, 0.0};
1953         PetscReal   hexRightWeights[27]  = {0.0, 0.0, -0.25, 0.0, 0.0, 0.5, 0.0, 0.0, -0.25, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, -0.25, 0.0, 0.0, 0.5, 0.0, 0.0, -0.25};
1954         PetscReal   hexBackWeights[27]   = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.25, 0.5, -0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.25, 0.5, -0.25};
1955         PetscReal   hexTopWeights[27]    = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.25, 0.5, -0.25, 0.5, 0.0, 0.5, -0.25, 0.5, -0.25};
1956         PetscReal   hexCenterWeights[27] = {-0.25, 0.25, -0.25, 0.25, 0.0, 0.25, -0.25, 0.25, -0.25, 0.25, 0.0, 0.25, 0.0, 0.0, 0.0, 0.25, 0.0, 0.25, -0.25, 0.25, -0.25, 0.25, 0.0, 0.25, -0.25, 0.25, -0.25};
1957         PetscReal  *sdWeights2[9]        = {NULL, NULL, NULL, NULL, quaCenterWeights, NULL, NULL, NULL, NULL};
1958         PetscReal  *sdWeights3[27]       = {NULL, NULL, NULL, NULL, hexBottomWeights, NULL, NULL, NULL, NULL, NULL, hexFrontWeights, NULL, hexLeftWeights, hexCenterWeights, hexRightWeights, NULL, hexBackWeights, NULL,
1959                                             NULL, NULL, NULL, NULL, hexTopWeights,    NULL, NULL, NULL, NULL};
1960         PetscReal **sdWeights[4]         = {NULL, NULL, sdWeights2, sdWeights3};
1961 
1962         /* Missing entries in serendipity cell, only works for 8-node quad and 20-node hex */
1963         for (n = 0; n < elem->numNodes + s; ++n) {
1964           if (lexorder[n] >= 0) continue;
1965           for (d = 0; d < coordDim; ++d) cellCoords[n * coordDim + d] = 0.0;
1966           for (int bn = 0; bn < elem->numNodes + s; ++bn) {
1967             if (lexorder[bn] < 0) continue;
1968             const PetscReal *weights = sdWeights[coordDim][n];
1969             const PetscInt   bnode   = elem->nodes[lexorder[bn]];
1970             for (d = 0; d < coordDim; ++d) cellCoords[n * coordDim + d] += weights[bn] * (PetscReal)coords[bnode * 3 + d];
1971           }
1972         }
1973       }
1974       PetscCall(DMPlexVecSetClosure(cdm, section, coordinates, cell, cellCoords, INSERT_VALUES));
1975     }
1976     PetscCall(PetscSectionDestroy(&section));
1977     PetscCall(PetscFree(cellCoords));
1978   } else {
1979     PetscInt    *nodeMap;
1980     double      *coords = mesh ? mesh->nodelist->xyz : NULL;
1981     PetscScalar *pointCoords;
1982 
1983     PetscCall(DMGetCoordinateSection(*dm, &cs));
1984     PetscCall(PetscSectionSetNumFields(cs, 1));
1985     PetscCall(PetscSectionSetFieldComponents(cs, 0, coordDim));
1986     PetscCall(PetscSectionSetChart(cs, numCells, numCells + numVerts));
1987     for (v = numCells; v < numCells + numVerts; ++v) {
1988       PetscCall(PetscSectionSetDof(cs, v, coordDim));
1989       PetscCall(PetscSectionSetFieldDof(cs, v, 0, coordDim));
1990     }
1991     PetscCall(PetscSectionSetUp(cs));
1992 
1993     /* We need to localize coordinates on cells */
1994     if (periodic) {
1995       PetscInt newStart = PETSC_MAX_INT, newEnd = -1, pStart, pEnd;
1996 
1997       PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)cdmCell), &csCell));
1998       PetscCall(PetscSectionSetNumFields(csCell, 1));
1999       PetscCall(PetscSectionSetFieldComponents(csCell, 0, coordDim));
2000       for (PetscInt h = 0; h <= maxHeight; h++) {
2001         PetscCall(DMPlexGetHeightStratum(cdmCell, h, &pStart, &pEnd));
2002         newStart = PetscMin(newStart, pStart);
2003         newEnd   = PetscMax(newEnd, pEnd);
2004       }
2005       PetscCall(PetscSectionSetChart(csCell, newStart, newEnd));
2006       for (PetscInt h = 0; h <= maxHeight; h++) {
2007         PetscCall(DMPlexGetHeightStratum(cdmCell, h, &pStart, &pEnd));
2008         for (PetscInt p = pStart; p < pEnd; ++p) {
2009           PetscInt *closure = NULL;
2010           PetscInt  Ncl, Nv = 0;
2011 
2012           if (PetscUnlikely(PetscBTLookup(periodicCells[h], p - pStart))) {
2013             PetscCall(DMPlexGetTransitiveClosure(*dm, p, PETSC_TRUE, &Ncl, &closure));
2014             for (PetscInt cl = 0; cl < Ncl * 2; cl += 2) {
2015               if (closure[cl] >= vStart && closure[cl] < vEnd) ++Nv;
2016             }
2017             PetscCall(DMPlexRestoreTransitiveClosure(*dm, p, PETSC_TRUE, &Ncl, &closure));
2018             PetscCall(PetscSectionSetDof(csCell, p, Nv * coordDim));
2019             PetscCall(PetscSectionSetFieldDof(csCell, p, 0, Nv * coordDim));
2020           }
2021         }
2022       }
2023       PetscCall(PetscSectionSetUp(csCell));
2024       PetscCall(DMSetCellCoordinateSection(*dm, PETSC_DETERMINE, csCell));
2025     }
2026 
2027     PetscCall(DMCreateLocalVector(cdm, &coordinates));
2028     PetscCall(VecGetArray(coordinates, &pointCoords));
2029     PetscCall(PetscMalloc1(numVerts, &nodeMap));
2030     for (n = 0; n < numNodes; n++)
2031       if (mesh->vertexMap[n] >= 0) nodeMap[mesh->vertexMap[n]] = n;
2032     for (v = 0; v < numVerts; ++v) {
2033       PetscInt off, node = nodeMap[v];
2034 
2035       PetscCall(PetscSectionGetOffset(cs, numCells + v, &off));
2036       for (d = 0; d < coordDim; ++d) pointCoords[off + d] = (PetscReal)coords[node * 3 + d];
2037     }
2038     PetscCall(VecRestoreArray(coordinates, &pointCoords));
2039 
2040     if (periodic) {
2041       PetscInt cStart, cEnd;
2042 
2043       PetscCall(DMPlexGetHeightStratum(cdmCell, 0, &cStart, &cEnd));
2044       PetscCall(DMCreateLocalVector(cdmCell, &coordinatesCell));
2045       PetscCall(VecGetArray(coordinatesCell, &pointCoords));
2046       for (PetscInt c = cStart; c < cEnd; ++c) {
2047         GmshElement *elem    = mesh->elements + c - cStart;
2048         PetscInt    *closure = NULL;
2049         PetscInt     verts[8];
2050         PetscInt     Ncl, Nv = 0;
2051 
2052         for (PetscInt v = 0; v < elem->numVerts; ++v) cone[v] = elem->nodes[v];
2053         PetscCall(DMPlexReorderCell(cdmCell, c, cone));
2054         PetscCall(DMPlexGetTransitiveClosure(cdmCell, c, PETSC_TRUE, &Ncl, &closure));
2055         for (PetscInt cl = 0; cl < Ncl * 2; cl += 2) {
2056           if (closure[cl] >= vStart && closure[cl] < vEnd) verts[Nv++] = closure[cl];
2057         }
2058         PetscCheck(Nv == elem->numVerts, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of vertices %" PetscInt_FMT " in closure does not match number of vertices %" PetscInt_FMT " in Gmsh cell", Nv, elem->numVerts);
2059         for (PetscInt cl = 0; cl < Ncl * 2; cl += 2) {
2060           const PetscInt point = closure[cl];
2061           PetscInt       hStart, h;
2062 
2063           PetscCall(DMPlexGetPointHeight(cdmCell, point, &h));
2064           if (h > maxHeight) continue;
2065           PetscCall(DMPlexGetHeightStratum(cdmCell, h, &hStart, NULL));
2066           if (PetscUnlikely(PetscBTLookup(periodicCells[h], point - hStart))) {
2067             PetscInt *pclosure = NULL;
2068             PetscInt  Npcl, off, v;
2069 
2070             PetscCall(PetscSectionGetOffset(csCell, point, &off));
2071             PetscCall(DMPlexGetTransitiveClosure(cdmCell, point, PETSC_TRUE, &Npcl, &pclosure));
2072             for (PetscInt pcl = 0; pcl < Npcl * 2; pcl += 2) {
2073               if (pclosure[pcl] >= vStart && pclosure[pcl] < vEnd) {
2074                 for (v = 0; v < Nv; ++v)
2075                   if (verts[v] == pclosure[pcl]) break;
2076                 PetscCheck(v < Nv, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find vertex %" PetscInt_FMT " in closure of cell %" PetscInt_FMT, pclosure[pcl], c);
2077                 for (PetscInt d = 0; d < coordDim; ++d) pointCoords[off++] = (PetscReal)coords[cone[v] * 3 + d];
2078                 ++v;
2079               }
2080             }
2081             PetscCall(DMPlexRestoreTransitiveClosure(cdmCell, point, PETSC_TRUE, &Npcl, &pclosure));
2082           }
2083         }
2084         PetscCall(DMPlexRestoreTransitiveClosure(cdmCell, c, PETSC_TRUE, &Ncl, &closure));
2085       }
2086       PetscCall(VecSetBlockSize(coordinatesCell, coordDim));
2087       PetscCall(VecRestoreArray(coordinatesCell, &pointCoords));
2088       PetscCall(DMSetCellCoordinatesLocal(*dm, coordinatesCell));
2089       PetscCall(VecDestroy(&coordinatesCell));
2090     }
2091     PetscCall(PetscFree(nodeMap));
2092     PetscCall(PetscSectionDestroy(&csCell));
2093     PetscCall(DMDestroy(&cdmCell));
2094   }
2095 
2096   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
2097   PetscCall(VecSetBlockSize(coordinates, coordDim));
2098   PetscCall(DMSetCoordinatesLocal(*dm, coordinates));
2099   PetscCall(VecDestroy(&coordinates));
2100 
2101   PetscCall(GmshMeshDestroy(&mesh));
2102   PetscCall(PetscBTDestroy(&periodicVerts));
2103   if (periodic) {
2104     for (PetscInt h = 0; h <= maxHeight; ++h) PetscCall(PetscBTDestroy(periodicCells + h));
2105     PetscCall(PetscFree(periodicCells));
2106   }
2107 
2108   if (highOrder && project) {
2109     PetscFE         fe;
2110     const char      prefix[]   = "dm_plex_gmsh_project_";
2111     PetscBool       continuity = periodic ? PETSC_FALSE : PETSC_TRUE;
2112     PetscDTNodeType nodeType   = PETSCDTNODES_GAUSSJACOBI;
2113 
2114     if (isSimplex) continuity = PETSC_FALSE; /* XXX FIXME Requires DMPlexSetClosurePermutationLexicographic() */
2115     PetscCall(GmshCreateFE(comm, prefix, isSimplex, continuity, nodeType, dim, coordDim, order, &fe));
2116     PetscCall(PetscFEViewFromOptions(fe, NULL, "-dm_plex_gmsh_project_fe_view"));
2117     PetscCall(DMSetCoordinateDisc(*dm, fe, PETSC_TRUE));
2118     PetscCall(PetscFEDestroy(&fe));
2119   }
2120 
2121   PetscCall(PetscLogEventEnd(DMPLEX_CreateGmsh, *dm, NULL, NULL, NULL));
2122   PetscFunctionReturn(PETSC_SUCCESS);
2123 }
2124