xref: /petsc/src/dm/impls/plex/plexgmsh.c (revision f13dfd9ea68e0ddeee984e65c377a1819eab8a8a)
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   for (block = 0, node = 0; block < numEntityBlocks; ++block, node += numNodesBlock) {
931     PetscCall(GmshReadInt(gmsh, info, 3));
932     dim        = info[0];
933     eid        = info[1];
934     parametric = info[2];
935     PetscCall(GmshEntitiesGet(mesh->entities, dim, eid, &entity));
936     numTags = entity->numTags;
937     PetscCheck(!parametric, PETSC_COMM_SELF, PETSC_ERR_SUP, "Parametric coordinates not supported");
938     PetscCall(GmshReadSize(gmsh, &numNodesBlock, 1));
939     PetscCall(GmshReadSize(gmsh, nodes->id + node, numNodesBlock));
940     PetscCall(GmshReadDouble(gmsh, nodes->xyz + node * 3, numNodesBlock * 3));
941     for (n = 0; n < numNodesBlock; ++n) {
942       PetscInt *tags = &nodes->tag[node * GMSH_MAX_TAGS];
943 
944       for (t = 0; t < numTags; ++t) tags[n * GMSH_MAX_TAGS + t] = entity->tags[t];
945       for (t = numTags; t < GMSH_MAX_TAGS; ++t) tags[n * GMSH_MAX_TAGS + t] = -1;
946     }
947   }
948   gmsh->nodeStart = sizes[2];
949   gmsh->nodeEnd   = sizes[3] + 1;
950   PetscFunctionReturn(PETSC_SUCCESS);
951 }
952 
953 /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
954 $Elements
955   numEntityBlocks(size_t) numElements(size_t)
956     minElementTag(size_t) maxElementTag(size_t)
957   entityDim(int) entityTag(int) elementType(int; see below) numElementsBlock(size_t)
958     elementTag(size_t) nodeTag(size_t) ...
959     ...
960   ...
961 $EndElements
962 */
963 static PetscErrorCode GmshReadElements_v41(GmshFile *gmsh, GmshMesh *mesh)
964 {
965   int          info[3], eid, dim, cellType;
966   PetscInt     sizes[4], *ibuf = NULL, numEntityBlocks, numElements, numBlockElements, numVerts, numNodes, numTags, block, elem, c, p;
967   GmshEntity  *entity = NULL;
968   GmshElement *elements;
969   PetscInt    *nodeMap = gmsh->nodeMap;
970 
971   PetscFunctionBegin;
972   PetscCall(GmshReadSize(gmsh, sizes, 4));
973   numEntityBlocks = sizes[0];
974   numElements     = sizes[1];
975   PetscCall(GmshElementsCreate(numElements, &elements));
976   mesh->numElems = numElements;
977   mesh->elements = elements;
978   for (c = 0, block = 0; block < numEntityBlocks; ++block) {
979     PetscCall(GmshReadInt(gmsh, info, 3));
980     dim      = info[0];
981     eid      = info[1];
982     cellType = info[2];
983     PetscCall(GmshEntitiesGet(mesh->entities, dim, eid, &entity));
984     PetscCall(GmshCellTypeCheck(cellType));
985     numVerts = GmshCellMap[cellType].numVerts;
986     numNodes = GmshCellMap[cellType].numNodes;
987     numTags  = entity->numTags;
988     PetscCall(GmshReadSize(gmsh, &numBlockElements, 1));
989     PetscCall(GmshBufferGet(gmsh, (1 + numNodes) * numBlockElements, sizeof(PetscInt), &ibuf));
990     PetscCall(GmshReadSize(gmsh, ibuf, (1 + numNodes) * numBlockElements));
991     for (elem = 0; elem < numBlockElements; ++elem, ++c) {
992       GmshElement    *element = elements + c;
993       const PetscInt *id = ibuf + elem * (1 + numNodes), *nodes = id + 1;
994       element->id       = id[0];
995       element->dim      = dim;
996       element->cellType = cellType;
997       element->numVerts = numVerts;
998       element->numNodes = numNodes;
999       element->numTags  = numTags;
1000       PetscCall(PetscSegBufferGet(mesh->segbuf, (size_t)element->numNodes, &element->nodes));
1001       for (p = 0; p < element->numNodes; p++) element->nodes[p] = nodeMap[nodes[p]];
1002       for (p = 0; p < element->numTags; p++) element->tags[p] = entity->tags[p];
1003     }
1004   }
1005   PetscFunctionReturn(PETSC_SUCCESS);
1006 }
1007 
1008 /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
1009 $Periodic
1010   numPeriodicLinks(size_t)
1011   entityDim(int) entityTag(int) entityTagPrimary(int)
1012   numAffine(size_t) value(double) ...
1013   numCorrespondingNodes(size_t)
1014     nodeTag(size_t) nodeTagPrimary(size_t)
1015     ...
1016   ...
1017 $EndPeriodic
1018 */
1019 static PetscErrorCode GmshReadPeriodic_v41(GmshFile *gmsh, PetscInt periodicMap[])
1020 {
1021   int       info[3];
1022   double    dbuf[16];
1023   PetscInt  numPeriodicLinks, numAffine, numCorrespondingNodes, *nodeTags = NULL, link, node;
1024   PetscInt *nodeMap = gmsh->nodeMap;
1025 
1026   PetscFunctionBegin;
1027   PetscCall(GmshReadSize(gmsh, &numPeriodicLinks, 1));
1028   for (link = 0; link < numPeriodicLinks; ++link) {
1029     PetscCall(GmshReadInt(gmsh, info, 3));
1030     PetscCall(GmshReadSize(gmsh, &numAffine, 1));
1031     PetscCall(GmshReadDouble(gmsh, dbuf, numAffine));
1032     PetscCall(GmshReadSize(gmsh, &numCorrespondingNodes, 1));
1033     PetscCall(GmshBufferGet(gmsh, numCorrespondingNodes, sizeof(PetscInt), &nodeTags));
1034     PetscCall(GmshReadSize(gmsh, nodeTags, numCorrespondingNodes * 2));
1035     for (node = 0; node < numCorrespondingNodes; ++node) {
1036       PetscInt correspondingNode     = nodeMap[nodeTags[node * 2 + 0]];
1037       PetscInt primaryNode           = nodeMap[nodeTags[node * 2 + 1]];
1038       periodicMap[correspondingNode] = primaryNode;
1039     }
1040   }
1041   PetscFunctionReturn(PETSC_SUCCESS);
1042 }
1043 
1044 /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
1045 $MeshFormat // same as MSH version 2
1046   version(ASCII double; currently 4.1)
1047   file-type(ASCII int; 0 for ASCII mode, 1 for binary mode)
1048   data-size(ASCII int; sizeof(size_t))
1049   < int with value one; only in binary mode, to detect endianness >
1050 $EndMeshFormat
1051 */
1052 static PetscErrorCode GmshReadMeshFormat(GmshFile *gmsh)
1053 {
1054   char  line[PETSC_MAX_PATH_LEN];
1055   int   snum, fileType, fileFormat, dataSize, checkEndian;
1056   float version;
1057 
1058   PetscFunctionBegin;
1059   PetscCall(GmshReadString(gmsh, line, 3));
1060   snum       = sscanf(line, "%f %d %d", &version, &fileType, &dataSize);
1061   fileFormat = (int)roundf(version * 10);
1062   PetscCheck(snum == 3, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to parse Gmsh file header: %s", line);
1063   PetscCheck(fileFormat >= 22, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at least 2.2", (double)version);
1064   PetscCheck((int)version != 3, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f not supported", (double)version);
1065   PetscCheck(fileFormat <= 41, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at most 4.1", (double)version);
1066   PetscCheck(!gmsh->binary || fileType, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Viewer is binary but Gmsh file is ASCII");
1067   PetscCheck(gmsh->binary || !fileType, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Viewer is ASCII but Gmsh file is binary");
1068   PetscCheck(fileFormat > 40 || dataSize == sizeof(double), PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Data size %d is not valid for a Gmsh file", dataSize);
1069   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);
1070   gmsh->fileFormat = fileFormat;
1071   gmsh->dataSize   = dataSize;
1072   gmsh->byteSwap   = PETSC_FALSE;
1073   if (gmsh->binary) {
1074     PetscCall(GmshReadInt(gmsh, &checkEndian, 1));
1075     if (checkEndian != 1) {
1076       PetscCall(PetscByteSwap(&checkEndian, PETSC_ENUM, 1));
1077       PetscCheck(checkEndian == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to detect endianness in Gmsh file header: %s", line);
1078       gmsh->byteSwap = PETSC_TRUE;
1079     }
1080   }
1081   PetscFunctionReturn(PETSC_SUCCESS);
1082 }
1083 
1084 /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
1085 Neper: https://neper.info/ adds this section
1086 
1087 $MeshVersion
1088   <major>.<minor>,<patch>
1089 $EndMeshVersion
1090 */
1091 static PetscErrorCode GmshReadMeshVersion(GmshFile *gmsh)
1092 {
1093   char line[PETSC_MAX_PATH_LEN];
1094   int  snum, major, minor, patch;
1095 
1096   PetscFunctionBegin;
1097   PetscCall(GmshReadString(gmsh, line, 1));
1098   snum = sscanf(line, "%d.%d.%d", &major, &minor, &patch);
1099   PetscCheck(snum == 3, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to parse Gmsh file header: %s", line);
1100   PetscFunctionReturn(PETSC_SUCCESS);
1101 }
1102 
1103 /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
1104 Neper: https://neper.info/ adds this section
1105 
1106 $Domain
1107   <shape>
1108 $EndDomain
1109 */
1110 static PetscErrorCode GmshReadMeshDomain(GmshFile *gmsh)
1111 {
1112   char line[PETSC_MAX_PATH_LEN];
1113 
1114   PetscFunctionBegin;
1115   PetscCall(GmshReadString(gmsh, line, 1));
1116   PetscFunctionReturn(PETSC_SUCCESS);
1117 }
1118 
1119 /*
1120 PhysicalNames
1121   numPhysicalNames(ASCII int)
1122   dimension(ASCII int) physicalTag(ASCII int) "name"(127 characters max)
1123   ...
1124 $EndPhysicalNames
1125 */
1126 static PetscErrorCode GmshReadPhysicalNames(GmshFile *gmsh, GmshMesh *mesh)
1127 {
1128   char line[PETSC_MAX_PATH_LEN], name[128 + 2], *p = NULL, *q = NULL, *r = NULL;
1129   int  snum, region, dim, tag;
1130 
1131   PetscFunctionBegin;
1132   PetscCall(GmshReadString(gmsh, line, 1));
1133   snum             = sscanf(line, "%d", &region);
1134   mesh->numRegions = region;
1135   PetscCheck(snum == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
1136   PetscCall(PetscMalloc3(mesh->numRegions, &mesh->regionDims, mesh->numRegions, &mesh->regionTags, mesh->numRegions, &mesh->regionNames));
1137   for (region = 0; region < mesh->numRegions; ++region) {
1138     PetscCall(GmshReadString(gmsh, line, 2));
1139     snum = sscanf(line, "%d %d", &dim, &tag);
1140     PetscCheck(snum == 2, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
1141     PetscCall(GmshReadString(gmsh, line, -(PetscInt)sizeof(line)));
1142     PetscCall(PetscStrchr(line, '"', &p));
1143     PetscCheck(p, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
1144     PetscCall(PetscStrrchr(line, '"', &q));
1145     PetscCheck(q != p, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
1146     PetscCall(PetscStrrchr(line, ':', &r));
1147     if (p != r) q = r;
1148     PetscCall(PetscStrncpy(name, p + 1, (size_t)(q - p - 1)));
1149     mesh->regionDims[region] = dim;
1150     mesh->regionTags[region] = tag;
1151     PetscCall(PetscStrallocpy(name, &mesh->regionNames[region]));
1152   }
1153   PetscFunctionReturn(PETSC_SUCCESS);
1154 }
1155 
1156 static PetscErrorCode GmshReadEntities(GmshFile *gmsh, GmshMesh *mesh)
1157 {
1158   PetscFunctionBegin;
1159   switch (gmsh->fileFormat) {
1160   case 41:
1161     PetscCall(GmshReadEntities_v41(gmsh, mesh));
1162     break;
1163   default:
1164     PetscCall(GmshReadEntities_v40(gmsh, mesh));
1165     break;
1166   }
1167   PetscFunctionReturn(PETSC_SUCCESS);
1168 }
1169 
1170 static PetscErrorCode GmshReadNodes(GmshFile *gmsh, GmshMesh *mesh)
1171 {
1172   PetscFunctionBegin;
1173   switch (gmsh->fileFormat) {
1174   case 41:
1175     PetscCall(GmshReadNodes_v41(gmsh, mesh));
1176     break;
1177   case 40:
1178     PetscCall(GmshReadNodes_v40(gmsh, mesh));
1179     break;
1180   default:
1181     PetscCall(GmshReadNodes_v22(gmsh, mesh));
1182     break;
1183   }
1184 
1185   { /* Gmsh v2.2/v4.0 does not provide min/max node tags */
1186     if (mesh->numNodes > 0 && gmsh->nodeEnd >= gmsh->nodeStart) {
1187       PetscInt   tagMin = PETSC_MAX_INT, tagMax = PETSC_MIN_INT, n;
1188       GmshNodes *nodes = mesh->nodelist;
1189       for (n = 0; n < mesh->numNodes; ++n) {
1190         const PetscInt tag = nodes->id[n];
1191         tagMin             = PetscMin(tag, tagMin);
1192         tagMax             = PetscMax(tag, tagMax);
1193       }
1194       gmsh->nodeStart = tagMin;
1195       gmsh->nodeEnd   = tagMax + 1;
1196     }
1197   }
1198 
1199   { /* Support for sparse node tags */
1200     PetscInt   n, t;
1201     GmshNodes *nodes = mesh->nodelist;
1202     PetscCall(PetscMalloc1(gmsh->nodeEnd - gmsh->nodeStart, &gmsh->nbuf));
1203     for (t = 0; t < gmsh->nodeEnd - gmsh->nodeStart; ++t) gmsh->nbuf[t] = PETSC_MIN_INT;
1204     gmsh->nodeMap = gmsh->nbuf - gmsh->nodeStart;
1205     for (n = 0; n < mesh->numNodes; ++n) {
1206       const PetscInt tag = nodes->id[n];
1207       PetscCheck(gmsh->nodeMap[tag] < 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Repeated node tag %" PetscInt_FMT, tag);
1208       gmsh->nodeMap[tag] = n;
1209     }
1210   }
1211   PetscFunctionReturn(PETSC_SUCCESS);
1212 }
1213 
1214 static PetscErrorCode GmshReadElements(GmshFile *gmsh, GmshMesh *mesh)
1215 {
1216   PetscFunctionBegin;
1217   switch (gmsh->fileFormat) {
1218   case 41:
1219     PetscCall(GmshReadElements_v41(gmsh, mesh));
1220     break;
1221   case 40:
1222     PetscCall(GmshReadElements_v40(gmsh, mesh));
1223     break;
1224   default:
1225     PetscCall(GmshReadElements_v22(gmsh, mesh));
1226     break;
1227   }
1228 
1229   { /* Reorder elements by codimension and polytope type */
1230     PetscInt     ne       = mesh->numElems;
1231     GmshElement *elements = mesh->elements;
1232     PetscInt     keymap[GMSH_NUM_POLYTOPES], nk = 0;
1233     PetscInt     offset[GMSH_NUM_POLYTOPES + 1], e, k;
1234 
1235     for (k = 0; k < GMSH_NUM_POLYTOPES; ++k) keymap[k] = PETSC_MIN_INT;
1236     PetscCall(PetscMemzero(offset, sizeof(offset)));
1237 
1238     keymap[GMSH_TET] = nk++;
1239     keymap[GMSH_HEX] = nk++;
1240     keymap[GMSH_PRI] = nk++;
1241     keymap[GMSH_PYR] = nk++;
1242     keymap[GMSH_TRI] = nk++;
1243     keymap[GMSH_QUA] = nk++;
1244     keymap[GMSH_SEG] = nk++;
1245     keymap[GMSH_VTX] = nk++;
1246 
1247     PetscCall(GmshElementsCreate(mesh->numElems, &mesh->elements));
1248 #define key(eid) keymap[GmshCellMap[elements[eid].cellType].polytope]
1249     for (e = 0; e < ne; ++e) offset[1 + key(e)]++;
1250     for (k = 1; k < nk; ++k) offset[k] += offset[k - 1];
1251     for (e = 0; e < ne; ++e) mesh->elements[offset[key(e)]++] = elements[e];
1252 #undef key
1253     PetscCall(GmshElementsDestroy(&elements));
1254   }
1255 
1256   { /* Mesh dimension and order */
1257     GmshElement *elem = mesh->numElems ? mesh->elements : NULL;
1258     mesh->dim         = elem ? GmshCellMap[elem->cellType].dim : 0;
1259     mesh->order       = elem ? GmshCellMap[elem->cellType].order : 0;
1260   }
1261 
1262   {
1263     PetscBT  vtx;
1264     PetscInt dim = mesh->dim, e, n, v;
1265 
1266     PetscCall(PetscBTCreate(mesh->numNodes, &vtx));
1267 
1268     /* Compute number of cells and set of vertices */
1269     mesh->numCells = 0;
1270     for (e = 0; e < mesh->numElems; ++e) {
1271       GmshElement *elem = mesh->elements + e;
1272       if (elem->dim == dim && dim > 0) mesh->numCells++;
1273       for (v = 0; v < elem->numVerts; v++) PetscCall(PetscBTSet(vtx, elem->nodes[v]));
1274     }
1275 
1276     /* Compute numbering for vertices */
1277     mesh->numVerts = 0;
1278     PetscCall(PetscMalloc1(mesh->numNodes, &mesh->vertexMap));
1279     for (n = 0; n < mesh->numNodes; ++n) mesh->vertexMap[n] = PetscBTLookup(vtx, n) ? mesh->numVerts++ : PETSC_MIN_INT;
1280 
1281     PetscCall(PetscBTDestroy(&vtx));
1282   }
1283   PetscFunctionReturn(PETSC_SUCCESS);
1284 }
1285 
1286 static PetscErrorCode GmshReadPeriodic(GmshFile *gmsh, GmshMesh *mesh)
1287 {
1288   PetscInt n;
1289 
1290   PetscFunctionBegin;
1291   PetscCall(PetscMalloc1(mesh->numNodes, &mesh->periodMap));
1292   for (n = 0; n < mesh->numNodes; ++n) mesh->periodMap[n] = n;
1293   switch (gmsh->fileFormat) {
1294   case 41:
1295     PetscCall(GmshReadPeriodic_v41(gmsh, mesh->periodMap));
1296     break;
1297   default:
1298     PetscCall(GmshReadPeriodic_v40(gmsh, mesh->periodMap));
1299     break;
1300   }
1301 
1302   /* Find canonical primary nodes */
1303   for (n = 0; n < mesh->numNodes; ++n)
1304     while (mesh->periodMap[n] != mesh->periodMap[mesh->periodMap[n]]) mesh->periodMap[n] = mesh->periodMap[mesh->periodMap[n]];
1305 
1306   /* Renumber vertices (filter out correspondings) */
1307   mesh->numVerts = 0;
1308   for (n = 0; n < mesh->numNodes; ++n)
1309     if (mesh->vertexMap[n] >= 0)   /* is vertex */
1310       if (mesh->periodMap[n] == n) /* is primary */
1311         mesh->vertexMap[n] = mesh->numVerts++;
1312   for (n = 0; n < mesh->numNodes; ++n)
1313     if (mesh->vertexMap[n] >= 0)   /* is vertex */
1314       if (mesh->periodMap[n] != n) /* is corresponding  */
1315         mesh->vertexMap[n] = mesh->vertexMap[mesh->periodMap[n]];
1316   PetscFunctionReturn(PETSC_SUCCESS);
1317 }
1318 
1319 #define DM_POLYTOPE_VERTEX DM_POLYTOPE_POINT
1320 static const DMPolytopeType DMPolytopeMap[] = {
1321   /* GMSH_VTX */ DM_POLYTOPE_VERTEX,
1322   /* GMSH_SEG */ DM_POLYTOPE_SEGMENT,
1323   /* GMSH_TRI */ DM_POLYTOPE_TRIANGLE,
1324   /* GMSH_QUA */ DM_POLYTOPE_QUADRILATERAL,
1325   /* GMSH_TET */ DM_POLYTOPE_TETRAHEDRON,
1326   /* GMSH_HEX */ DM_POLYTOPE_HEXAHEDRON,
1327   /* GMSH_PRI */ DM_POLYTOPE_TRI_PRISM,
1328   /* GMSH_PYR */ DM_POLYTOPE_PYRAMID,       DM_POLYTOPE_UNKNOWN};
1329 
1330 static inline DMPolytopeType DMPolytopeTypeFromGmsh(PetscInt cellType)
1331 {
1332   return DMPolytopeMap[GmshCellMap[cellType].polytope];
1333 }
1334 
1335 static PetscErrorCode GmshCreateFE(MPI_Comm comm, const char prefix[], PetscBool isSimplex, PetscBool continuity, PetscDTNodeType nodeType, PetscInt dim, PetscInt Nc, PetscInt k, PetscFE *fem)
1336 {
1337   DM              K;
1338   PetscSpace      P;
1339   PetscDualSpace  Q;
1340   PetscQuadrature q, fq;
1341   PetscBool       isTensor = isSimplex ? PETSC_FALSE : PETSC_TRUE;
1342   PetscBool       endpoint = PETSC_TRUE;
1343   char            name[32];
1344 
1345   PetscFunctionBegin;
1346   /* Create space */
1347   PetscCall(PetscSpaceCreate(comm, &P));
1348   PetscCall(PetscSpaceSetType(P, PETSCSPACEPOLYNOMIAL));
1349   PetscCall(PetscSpacePolynomialSetTensor(P, isTensor));
1350   PetscCall(PetscSpaceSetNumComponents(P, Nc));
1351   PetscCall(PetscSpaceSetNumVariables(P, dim));
1352   PetscCall(PetscSpaceSetDegree(P, k, PETSC_DETERMINE));
1353   if (prefix) {
1354     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)P, prefix));
1355     PetscCall(PetscSpaceSetFromOptions(P));
1356     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)P, NULL));
1357     PetscCall(PetscSpaceGetDegree(P, &k, NULL));
1358   }
1359   PetscCall(PetscSpaceSetUp(P));
1360   /* Create dual space */
1361   PetscCall(PetscDualSpaceCreate(comm, &Q));
1362   PetscCall(PetscDualSpaceSetType(Q, PETSCDUALSPACELAGRANGE));
1363   PetscCall(PetscDualSpaceLagrangeSetTensor(Q, isTensor));
1364   PetscCall(PetscDualSpaceLagrangeSetContinuity(Q, continuity));
1365   PetscCall(PetscDualSpaceLagrangeSetNodeType(Q, nodeType, endpoint, 0));
1366   PetscCall(PetscDualSpaceSetNumComponents(Q, Nc));
1367   PetscCall(PetscDualSpaceSetOrder(Q, k));
1368   PetscCall(DMPlexCreateReferenceCell(PETSC_COMM_SELF, DMPolytopeTypeSimpleShape(dim, isSimplex), &K));
1369   PetscCall(PetscDualSpaceSetDM(Q, K));
1370   PetscCall(DMDestroy(&K));
1371   if (prefix) {
1372     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)Q, prefix));
1373     PetscCall(PetscDualSpaceSetFromOptions(Q));
1374     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)Q, NULL));
1375   }
1376   PetscCall(PetscDualSpaceSetUp(Q));
1377   /* Create quadrature */
1378   if (isSimplex) {
1379     PetscCall(PetscDTStroudConicalQuadrature(dim, 1, k + 1, -1, +1, &q));
1380     PetscCall(PetscDTStroudConicalQuadrature(dim - 1, 1, k + 1, -1, +1, &fq));
1381   } else {
1382     PetscCall(PetscDTGaussTensorQuadrature(dim, 1, k + 1, -1, +1, &q));
1383     PetscCall(PetscDTGaussTensorQuadrature(dim - 1, 1, k + 1, -1, +1, &fq));
1384   }
1385   /* Create finite element */
1386   PetscCall(PetscFECreate(comm, fem));
1387   PetscCall(PetscFESetType(*fem, PETSCFEBASIC));
1388   PetscCall(PetscFESetNumComponents(*fem, Nc));
1389   PetscCall(PetscFESetBasisSpace(*fem, P));
1390   PetscCall(PetscFESetDualSpace(*fem, Q));
1391   PetscCall(PetscFESetQuadrature(*fem, q));
1392   PetscCall(PetscFESetFaceQuadrature(*fem, fq));
1393   if (prefix) {
1394     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*fem, prefix));
1395     PetscCall(PetscFESetFromOptions(*fem));
1396     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*fem, NULL));
1397   }
1398   PetscCall(PetscFESetUp(*fem));
1399   /* Cleanup */
1400   PetscCall(PetscSpaceDestroy(&P));
1401   PetscCall(PetscDualSpaceDestroy(&Q));
1402   PetscCall(PetscQuadratureDestroy(&q));
1403   PetscCall(PetscQuadratureDestroy(&fq));
1404   /* Set finite element name */
1405   PetscCall(PetscSNPrintf(name, sizeof(name), "%s%" PetscInt_FMT, isSimplex ? "P" : "Q", k));
1406   PetscCall(PetscFESetName(*fem, name));
1407   PetscFunctionReturn(PETSC_SUCCESS);
1408 }
1409 
1410 /*@C
1411   DMPlexCreateGmshFromFile - Create a `DMPLEX` mesh from a Gmsh file
1412 
1413   Input Parameters:
1414 + comm        - The MPI communicator
1415 . filename    - Name of the Gmsh file
1416 - interpolate - Create faces and edges in the mesh
1417 
1418   Output Parameter:
1419 . dm - The `DM` object representing the mesh
1420 
1421   Level: beginner
1422 
1423 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromFile()`, `DMPlexCreateGmsh()`, `DMPlexCreate()`
1424 @*/
1425 PetscErrorCode DMPlexCreateGmshFromFile(MPI_Comm comm, const char filename[], PetscBool interpolate, DM *dm)
1426 {
1427   PetscViewer     viewer;
1428   PetscMPIInt     rank;
1429   int             fileType;
1430   PetscViewerType vtype;
1431 
1432   PetscFunctionBegin;
1433   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1434 
1435   /* Determine Gmsh file type (ASCII or binary) from file header */
1436   if (rank == 0) {
1437     GmshFile gmsh[1];
1438     char     line[PETSC_MAX_PATH_LEN];
1439     int      snum;
1440     float    version;
1441     int      fileFormat;
1442 
1443     PetscCall(PetscArrayzero(gmsh, 1));
1444     PetscCall(PetscViewerCreate(PETSC_COMM_SELF, &gmsh->viewer));
1445     PetscCall(PetscViewerSetType(gmsh->viewer, PETSCVIEWERASCII));
1446     PetscCall(PetscViewerFileSetMode(gmsh->viewer, FILE_MODE_READ));
1447     PetscCall(PetscViewerFileSetName(gmsh->viewer, filename));
1448     /* Read only the first two lines of the Gmsh file */
1449     PetscCall(GmshReadSection(gmsh, line));
1450     PetscCall(GmshExpect(gmsh, "$MeshFormat", line));
1451     PetscCall(GmshReadString(gmsh, line, 2));
1452     snum       = sscanf(line, "%f %d", &version, &fileType);
1453     fileFormat = (int)roundf(version * 10);
1454     PetscCheck(snum == 2, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to parse Gmsh file header: %s", line);
1455     PetscCheck(fileFormat >= 22, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at least 2.2", (double)version);
1456     PetscCheck((int)version != 3, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f not supported", (double)version);
1457     PetscCheck(fileFormat <= 41, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at most 4.1", (double)version);
1458     PetscCall(PetscViewerDestroy(&gmsh->viewer));
1459   }
1460   PetscCallMPI(MPI_Bcast(&fileType, 1, MPI_INT, 0, comm));
1461   vtype = (fileType == 0) ? PETSCVIEWERASCII : PETSCVIEWERBINARY;
1462 
1463   /* Create appropriate viewer and build plex */
1464   PetscCall(PetscViewerCreate(comm, &viewer));
1465   PetscCall(PetscViewerSetType(viewer, vtype));
1466   PetscCall(PetscViewerFileSetMode(viewer, FILE_MODE_READ));
1467   PetscCall(PetscViewerFileSetName(viewer, filename));
1468   PetscCall(DMPlexCreateGmsh(comm, viewer, interpolate, dm));
1469   PetscCall(PetscViewerDestroy(&viewer));
1470   PetscFunctionReturn(PETSC_SUCCESS);
1471 }
1472 
1473 /*@
1474   DMPlexCreateGmsh - Create a `DMPLEX` mesh from a Gmsh file viewer
1475 
1476   Collective
1477 
1478   Input Parameters:
1479 + comm        - The MPI communicator
1480 . viewer      - The `PetscViewer` associated with a Gmsh file
1481 - interpolate - Create faces and edges in the mesh
1482 
1483   Output Parameter:
1484 . dm - The `DM` object representing the mesh
1485 
1486   Options Database Keys:
1487 + -dm_plex_gmsh_hybrid        - Force triangular prisms to use tensor order
1488 . -dm_plex_gmsh_periodic      - Read Gmsh periodic section and construct a periodic Plex
1489 . -dm_plex_gmsh_highorder     - Generate high-order coordinates
1490 . -dm_plex_gmsh_project       - Project high-order coordinates to a different space, use the prefix dm_plex_gmsh_project_ to define the space
1491 . -dm_plex_gmsh_use_generic   - Generate generic labels, i.e. Cell Sets, Face Sets, etc.
1492 . -dm_plex_gmsh_use_regions   - Generate labels with region names
1493 . -dm_plex_gmsh_mark_vertices - Add vertices to generated labels
1494 . -dm_plex_gmsh_multiple_tags - Allow multiple tags for default labels
1495 - -dm_plex_gmsh_spacedim <d>  - Embedding space dimension, if different from topological dimension
1496 
1497   Level: beginner
1498 
1499   Notes:
1500   The Gmsh file format is described in <http://gmsh.info/doc/texinfo/gmsh.html#MSH-file-format>
1501 
1502   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.
1503 
1504 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`
1505 @*/
1506 PetscErrorCode DMPlexCreateGmsh(MPI_Comm comm, PetscViewer viewer, PetscBool interpolate, DM *dm)
1507 {
1508   GmshMesh    *mesh          = NULL;
1509   PetscViewer  parentviewer  = NULL;
1510   PetscBT      periodicVerts = NULL;
1511   PetscBT     *periodicCells = NULL;
1512   DM           cdm, cdmCell = NULL;
1513   PetscSection cs, csCell   = NULL;
1514   Vec          coordinates, coordinatesCell;
1515   DMLabel      cellSets = NULL, faceSets = NULL, edgeSets = NULL, vertSets = NULL, marker = NULL, *regionSets;
1516   PetscInt     dim = 0, coordDim = -1, order = 0, maxHeight = 0;
1517   PetscInt     numNodes = 0, numElems = 0, numVerts = 0, numCells = 0, vStart, vEnd;
1518   PetscInt     cell, cone[8], e, n, v, d;
1519   PetscBool    usegeneric = PETSC_TRUE, useregions = PETSC_FALSE, markvertices = PETSC_FALSE, multipleTags = PETSC_FALSE;
1520   PetscBool    flg, binary, hybrid = interpolate, periodic = PETSC_TRUE;
1521   PetscBool    highOrder = PETSC_TRUE, highOrderSet, project = PETSC_FALSE;
1522   PetscBool    isSimplex = PETSC_FALSE, isHybrid = PETSC_FALSE, hasTetra = PETSC_FALSE;
1523   PetscMPIInt  rank;
1524 
1525   PetscFunctionBegin;
1526   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1527   PetscObjectOptionsBegin((PetscObject)viewer);
1528   PetscOptionsHeadBegin(PetscOptionsObject, "DMPlex Gmsh options");
1529   PetscCall(PetscOptionsBool("-dm_plex_gmsh_hybrid", "Force triangular prisms to use tensor order", "DMPlexCreateGmsh", hybrid, &hybrid, NULL));
1530   PetscCall(PetscOptionsBool("-dm_plex_gmsh_periodic", "Read Gmsh periodic section", "DMPlexCreateGmsh", periodic, &periodic, NULL));
1531   PetscCall(PetscOptionsBool("-dm_plex_gmsh_highorder", "Generate high-order coordinates", "DMPlexCreateGmsh", highOrder, &highOrder, &highOrderSet));
1532   PetscCall(PetscOptionsBool("-dm_plex_gmsh_project", "Project high-order coordinates to a different space", "DMPlexCreateGmsh", project, &project, NULL));
1533   PetscCall(PetscOptionsBool("-dm_plex_gmsh_use_regions", "Generate labels with region names", "DMPlexCreateGmsh", useregions, &useregions, NULL));
1534   PetscCall(PetscOptionsBool("-dm_plex_gmsh_use_generic", "Generate generic labels, i.e. Cell Sets, Face Sets, etc", "DMPlexCreateGmsh", usegeneric, &usegeneric, &flg));
1535   if (!flg && useregions) usegeneric = PETSC_FALSE;
1536   PetscCall(PetscOptionsBool("-dm_plex_gmsh_mark_vertices", "Add vertices to generated labels", "DMPlexCreateGmsh", markvertices, &markvertices, NULL));
1537   PetscCall(PetscOptionsBool("-dm_plex_gmsh_multiple_tags", "Allow multiple tags for default labels", "DMPlexCreateGmsh", multipleTags, &multipleTags, NULL));
1538   PetscCall(PetscOptionsBoundedInt("-dm_plex_gmsh_spacedim", "Embedding space dimension", "DMPlexCreateGmsh", coordDim, &coordDim, NULL, PETSC_DECIDE));
1539   PetscCall(PetscOptionsBoundedInt("-dm_localize_height", "Localize edges and faces in addition to cells", "", maxHeight, &maxHeight, NULL, 0));
1540   PetscOptionsHeadEnd();
1541   PetscOptionsEnd();
1542 
1543   PetscCall(GmshCellInfoSetUp());
1544 
1545   PetscCall(DMCreate(comm, dm));
1546   PetscCall(DMSetType(*dm, DMPLEX));
1547   PetscCall(PetscLogEventBegin(DMPLEX_CreateGmsh, *dm, NULL, NULL, NULL));
1548 
1549   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &binary));
1550 
1551   /* Binary viewers read on all ranks, get subviewer to read only in rank 0 */
1552   if (binary) {
1553     parentviewer = viewer;
1554     PetscCall(PetscViewerGetSubViewer(parentviewer, PETSC_COMM_SELF, &viewer));
1555   }
1556 
1557   if (rank == 0) {
1558     GmshFile  gmsh[1];
1559     char      line[PETSC_MAX_PATH_LEN];
1560     PetscBool match;
1561 
1562     PetscCall(PetscArrayzero(gmsh, 1));
1563     gmsh->viewer = viewer;
1564     gmsh->binary = binary;
1565 
1566     PetscCall(GmshMeshCreate(&mesh));
1567 
1568     /* Read mesh format */
1569     PetscCall(GmshReadSection(gmsh, line));
1570     PetscCall(GmshExpect(gmsh, "$MeshFormat", line));
1571     PetscCall(GmshReadMeshFormat(gmsh));
1572     PetscCall(GmshReadEndSection(gmsh, "$EndMeshFormat", line));
1573 
1574     /* OPTIONAL Read mesh version (Neper only) */
1575     PetscCall(GmshReadSection(gmsh, line));
1576     PetscCall(GmshMatch(gmsh, "$MeshVersion", line, &match));
1577     if (match) {
1578       PetscCall(GmshExpect(gmsh, "$MeshVersion", line));
1579       PetscCall(GmshReadMeshVersion(gmsh));
1580       PetscCall(GmshReadEndSection(gmsh, "$EndMeshVersion", line));
1581       /* Initial read for entity section */
1582       PetscCall(GmshReadSection(gmsh, line));
1583     }
1584 
1585     /* OPTIONAL Read mesh domain (Neper only) */
1586     PetscCall(GmshMatch(gmsh, "$Domain", line, &match));
1587     if (match) {
1588       PetscCall(GmshExpect(gmsh, "$Domain", line));
1589       PetscCall(GmshReadMeshDomain(gmsh));
1590       PetscCall(GmshReadEndSection(gmsh, "$EndDomain", line));
1591       /* Initial read for entity section */
1592       PetscCall(GmshReadSection(gmsh, line));
1593     }
1594 
1595     /* OPTIONAL Read physical names */
1596     PetscCall(GmshMatch(gmsh, "$PhysicalNames", line, &match));
1597     if (match) {
1598       PetscCall(GmshExpect(gmsh, "$PhysicalNames", line));
1599       PetscCall(GmshReadPhysicalNames(gmsh, mesh));
1600       PetscCall(GmshReadEndSection(gmsh, "$EndPhysicalNames", line));
1601       /* Initial read for entity section */
1602       PetscCall(GmshReadSection(gmsh, line));
1603     }
1604 
1605     /* Read entities */
1606     if (gmsh->fileFormat >= 40) {
1607       PetscCall(GmshExpect(gmsh, "$Entities", line));
1608       PetscCall(GmshReadEntities(gmsh, mesh));
1609       PetscCall(GmshReadEndSection(gmsh, "$EndEntities", line));
1610       /* Initial read for nodes section */
1611       PetscCall(GmshReadSection(gmsh, line));
1612     }
1613 
1614     /* Read nodes */
1615     PetscCall(GmshExpect(gmsh, "$Nodes", line));
1616     PetscCall(GmshReadNodes(gmsh, mesh));
1617     PetscCall(GmshReadEndSection(gmsh, "$EndNodes", line));
1618 
1619     /* Read elements */
1620     PetscCall(GmshReadSection(gmsh, line));
1621     PetscCall(GmshExpect(gmsh, "$Elements", line));
1622     PetscCall(GmshReadElements(gmsh, mesh));
1623     PetscCall(GmshReadEndSection(gmsh, "$EndElements", line));
1624 
1625     /* Read periodic section (OPTIONAL) */
1626     if (periodic) {
1627       PetscCall(GmshReadSection(gmsh, line));
1628       PetscCall(GmshMatch(gmsh, "$Periodic", line, &periodic));
1629     }
1630     if (periodic) {
1631       PetscCall(GmshExpect(gmsh, "$Periodic", line));
1632       PetscCall(GmshReadPeriodic(gmsh, mesh));
1633       PetscCall(GmshReadEndSection(gmsh, "$EndPeriodic", line));
1634     }
1635 
1636     PetscCall(PetscFree(gmsh->wbuf));
1637     PetscCall(PetscFree(gmsh->sbuf));
1638     PetscCall(PetscFree(gmsh->nbuf));
1639 
1640     dim      = mesh->dim;
1641     order    = mesh->order;
1642     numNodes = mesh->numNodes;
1643     numElems = mesh->numElems;
1644     numVerts = mesh->numVerts;
1645     numCells = mesh->numCells;
1646 
1647     {
1648       GmshElement *elemA = mesh->numCells > 0 ? mesh->elements : NULL;
1649       GmshElement *elemB = PetscSafePointerPlusOffset(elemA, mesh->numCells - 1);
1650       int          ptA   = elemA ? GmshCellMap[elemA->cellType].polytope : -1;
1651       int          ptB   = elemB ? GmshCellMap[elemB->cellType].polytope : -1;
1652       isSimplex          = (ptA == GMSH_QUA || ptA == GMSH_HEX) ? PETSC_FALSE : PETSC_TRUE;
1653       isHybrid           = (ptA == ptB) ? PETSC_FALSE : PETSC_TRUE;
1654       hasTetra           = (ptA == GMSH_TET) ? PETSC_TRUE : PETSC_FALSE;
1655     }
1656   }
1657 
1658   if (parentviewer) PetscCall(PetscViewerRestoreSubViewer(parentviewer, PETSC_COMM_SELF, &viewer));
1659 
1660   {
1661     int buf[6];
1662 
1663     buf[0] = (int)dim;
1664     buf[1] = (int)order;
1665     buf[2] = periodic;
1666     buf[3] = isSimplex;
1667     buf[4] = isHybrid;
1668     buf[5] = hasTetra;
1669 
1670     PetscCallMPI(MPI_Bcast(buf, 6, MPI_INT, 0, comm));
1671 
1672     dim       = buf[0];
1673     order     = buf[1];
1674     periodic  = buf[2] ? PETSC_TRUE : PETSC_FALSE;
1675     isSimplex = buf[3] ? PETSC_TRUE : PETSC_FALSE;
1676     isHybrid  = buf[4] ? PETSC_TRUE : PETSC_FALSE;
1677     hasTetra  = buf[5] ? PETSC_TRUE : PETSC_FALSE;
1678   }
1679 
1680   if (!highOrderSet) highOrder = (order > 1) ? PETSC_TRUE : PETSC_FALSE;
1681   PetscCheck(!highOrder || !isHybrid, comm, PETSC_ERR_SUP, "No support for discretization on hybrid meshes yet");
1682 
1683   /* We do not want this label automatically computed, instead we fill it here */
1684   PetscCall(DMCreateLabel(*dm, "celltype"));
1685 
1686   /* Allocate the cell-vertex mesh */
1687   PetscCall(DMPlexSetChart(*dm, 0, numCells + numVerts));
1688   for (cell = 0; cell < numCells; ++cell) {
1689     GmshElement   *elem  = mesh->elements + cell;
1690     DMPolytopeType ctype = DMPolytopeTypeFromGmsh(elem->cellType);
1691     if (hybrid && hasTetra && ctype == DM_POLYTOPE_TRI_PRISM) ctype = DM_POLYTOPE_TRI_PRISM_TENSOR;
1692     PetscCall(DMPlexSetConeSize(*dm, cell, elem->numVerts));
1693     PetscCall(DMPlexSetCellType(*dm, cell, ctype));
1694   }
1695   for (v = numCells; v < numCells + numVerts; ++v) PetscCall(DMPlexSetCellType(*dm, v, DM_POLYTOPE_POINT));
1696   PetscCall(DMSetUp(*dm));
1697 
1698   /* Add cell-vertex connections */
1699   for (cell = 0; cell < numCells; ++cell) {
1700     GmshElement *elem = mesh->elements + cell;
1701     for (v = 0; v < elem->numVerts; ++v) {
1702       const PetscInt nn = elem->nodes[v];
1703       const PetscInt vv = mesh->vertexMap[nn];
1704       cone[v]           = numCells + vv;
1705     }
1706     PetscCall(DMPlexReorderCell(*dm, cell, cone));
1707     PetscCall(DMPlexSetCone(*dm, cell, cone));
1708   }
1709 
1710   PetscCall(DMSetDimension(*dm, dim));
1711   PetscCall(DMPlexSymmetrize(*dm));
1712   PetscCall(DMPlexStratify(*dm));
1713   if (interpolate) {
1714     DM idm;
1715 
1716     PetscCall(DMPlexInterpolate(*dm, &idm));
1717     PetscCall(DMDestroy(dm));
1718     *dm = idm;
1719   }
1720   PetscCall(DMPlexGetDepthStratum(*dm, 0, &vStart, &vEnd));
1721 
1722   if (rank == 0) {
1723     const PetscInt Nr = useregions ? mesh->numRegions : 0;
1724 
1725     PetscCall(PetscCalloc1(Nr, &regionSets));
1726     for (cell = 0, e = 0; e < numElems; ++e) {
1727       GmshElement *elem = mesh->elements + e;
1728 
1729       /* Create cell sets */
1730       if (elem->dim == dim && dim > 0) {
1731         if (elem->numTags > 0) {
1732           PetscInt Nt = elem->numTags, t, r;
1733 
1734           for (t = 0; t < Nt; ++t) {
1735             const PetscInt  tag     = elem->tags[t];
1736             const PetscBool generic = usegeneric && (!t || multipleTags) ? PETSC_TRUE : PETSC_FALSE;
1737 
1738             if (generic) PetscCall(DMSetLabelValue_Fast(*dm, &cellSets, "Cell Sets", cell, tag));
1739             for (r = 0; r < Nr; ++r) {
1740               if (mesh->regionDims[r] != dim) continue;
1741               if (mesh->regionTags[r] == tag) PetscCall(DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], cell, tag));
1742             }
1743           }
1744         }
1745         cell++;
1746       }
1747 
1748       /* Create face sets */
1749       if (elem->numTags && interpolate && elem->dim == dim - 1) {
1750         PetscInt        joinSize;
1751         const PetscInt *join = NULL;
1752         PetscInt        Nt   = elem->numTags, pdepth;
1753 
1754         /* Find the relevant facet with vertex joins */
1755         for (v = 0; v < elem->numVerts; ++v) {
1756           const PetscInt nn = elem->nodes[v];
1757           const PetscInt vv = mesh->vertexMap[nn];
1758           cone[v]           = vStart + vv;
1759         }
1760         PetscCall(DMPlexGetFullJoin(*dm, elem->numVerts, cone, &joinSize, &join));
1761         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);
1762         PetscCall(DMPlexGetPointDepth(*dm, join[0], &pdepth));
1763         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);
1764         for (PetscInt t = 0; t < Nt; ++t) {
1765           const PetscInt  tag     = elem->tags[t];
1766           const PetscBool generic = usegeneric && (!t || multipleTags) ? PETSC_TRUE : PETSC_FALSE;
1767 
1768           if (generic) PetscCall(DMSetLabelValue_Fast(*dm, &faceSets, "Face Sets", join[0], tag));
1769           for (PetscInt r = 0; r < Nr; ++r) {
1770             if (mesh->regionDims[r] != dim - 1) continue;
1771             if (mesh->regionTags[r] == tag) PetscCall(DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], join[0], tag));
1772           }
1773         }
1774         PetscCall(DMPlexRestoreJoin(*dm, elem->numVerts, cone, &joinSize, &join));
1775       }
1776 
1777       /* Create edge sets */
1778       if (elem->numTags && interpolate && dim > 2 && elem->dim == 1) {
1779         PetscInt        joinSize;
1780         const PetscInt *join = NULL;
1781         PetscInt        Nt   = elem->numTags, t, r;
1782 
1783         /* Find the relevant edge with vertex joins */
1784         for (v = 0; v < elem->numVerts; ++v) {
1785           const PetscInt nn = elem->nodes[v];
1786           const PetscInt vv = mesh->vertexMap[nn];
1787           cone[v]           = vStart + vv;
1788         }
1789         PetscCall(DMPlexGetJoin(*dm, elem->numVerts, cone, &joinSize, &join));
1790         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);
1791         for (t = 0; t < Nt; ++t) {
1792           const PetscInt  tag     = elem->tags[t];
1793           const PetscBool generic = usegeneric && (!t || multipleTags) ? PETSC_TRUE : PETSC_FALSE;
1794 
1795           if (generic) PetscCall(DMSetLabelValue_Fast(*dm, &edgeSets, "Edge Sets", join[0], tag));
1796           for (r = 0; r < Nr; ++r) {
1797             if (mesh->regionDims[r] != 1) continue;
1798             if (mesh->regionTags[r] == tag) PetscCall(DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], join[0], tag));
1799           }
1800         }
1801         PetscCall(DMPlexRestoreJoin(*dm, elem->numVerts, cone, &joinSize, &join));
1802       }
1803 
1804       /* Create vertex sets */
1805       if (elem->numTags && elem->dim == 0 && markvertices) {
1806         const PetscInt nn  = elem->nodes[0];
1807         const PetscInt vv  = mesh->vertexMap[nn];
1808         const PetscInt tag = elem->tags[0];
1809         PetscInt       r;
1810 
1811         if (vv < 0) continue;
1812         if (usegeneric) PetscCall(DMSetLabelValue_Fast(*dm, &vertSets, "Vertex Sets", vStart + vv, tag));
1813         for (r = 0; r < Nr; ++r) {
1814           if (mesh->regionDims[r] != 0) continue;
1815           if (mesh->regionTags[r] == tag) PetscCall(DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], vStart + vv, tag));
1816         }
1817       }
1818     }
1819     if (markvertices) {
1820       for (v = 0; v < numNodes; ++v) {
1821         const PetscInt  vv   = mesh->vertexMap[v];
1822         const PetscInt *tags = &mesh->nodelist->tag[v * GMSH_MAX_TAGS];
1823         PetscInt        r, t;
1824 
1825         if (vv < 0) continue;
1826         for (t = 0; t < GMSH_MAX_TAGS; ++t) {
1827           const PetscInt  tag     = tags[t];
1828           const PetscBool generic = usegeneric && (!t || multipleTags) ? PETSC_TRUE : PETSC_FALSE;
1829 
1830           if (tag == -1) continue;
1831           if (generic) PetscCall(DMSetLabelValue_Fast(*dm, &vertSets, "Vertex Sets", vStart + vv, tag));
1832           for (r = 0; r < Nr; ++r) {
1833             if (mesh->regionTags[r] == tag) PetscCall(DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], vStart + vv, tag));
1834           }
1835         }
1836       }
1837     }
1838     PetscCall(PetscFree(regionSets));
1839   }
1840 
1841   { /* Create Cell/Face/Edge/Vertex Sets labels at all processes */
1842     enum {
1843       n = 5
1844     };
1845     PetscBool flag[n];
1846 
1847     flag[0] = cellSets ? PETSC_TRUE : PETSC_FALSE;
1848     flag[1] = faceSets ? PETSC_TRUE : PETSC_FALSE;
1849     flag[2] = edgeSets ? PETSC_TRUE : PETSC_FALSE;
1850     flag[3] = vertSets ? PETSC_TRUE : PETSC_FALSE;
1851     flag[4] = marker ? PETSC_TRUE : PETSC_FALSE;
1852     PetscCallMPI(MPI_Bcast(flag, n, MPIU_BOOL, 0, comm));
1853     if (flag[0]) PetscCall(DMCreateLabel(*dm, "Cell Sets"));
1854     if (flag[1]) PetscCall(DMCreateLabel(*dm, "Face Sets"));
1855     if (flag[2]) PetscCall(DMCreateLabel(*dm, "Edge Sets"));
1856     if (flag[3]) PetscCall(DMCreateLabel(*dm, "Vertex Sets"));
1857     if (flag[4]) PetscCall(DMCreateLabel(*dm, "marker"));
1858   }
1859 
1860   if (periodic) {
1861     PetscCall(PetscBTCreate(numVerts, &periodicVerts));
1862     for (n = 0; n < numNodes; ++n) {
1863       if (mesh->vertexMap[n] >= 0) {
1864         if (PetscUnlikely(mesh->periodMap[n] != n)) {
1865           PetscInt m = mesh->periodMap[n];
1866           PetscCall(PetscBTSet(periodicVerts, mesh->vertexMap[n]));
1867           PetscCall(PetscBTSet(periodicVerts, mesh->vertexMap[m]));
1868         }
1869       }
1870     }
1871     PetscCall(DMGetCoordinateDM(*dm, &cdm));
1872     PetscCall(PetscMalloc1(maxHeight + 1, &periodicCells));
1873     for (PetscInt h = 0; h <= maxHeight; ++h) {
1874       PetscInt pStart, pEnd;
1875 
1876       PetscCall(DMPlexGetHeightStratum(*dm, h, &pStart, &pEnd));
1877       PetscCall(PetscBTCreate(pEnd - pStart, &periodicCells[h]));
1878       for (PetscInt p = pStart; p < pEnd; ++p) {
1879         PetscInt *closure = NULL;
1880         PetscInt  Ncl;
1881 
1882         PetscCall(DMPlexGetTransitiveClosure(*dm, p, PETSC_TRUE, &Ncl, &closure));
1883         for (PetscInt cl = 0; cl < Ncl * 2; cl += 2) {
1884           if (closure[cl] >= vStart && closure[cl] < vEnd) {
1885             if (PetscUnlikely(PetscBTLookup(periodicVerts, closure[cl] - vStart))) {
1886               PetscCall(PetscBTSet(periodicCells[h], p - pStart));
1887               break;
1888             }
1889           }
1890         }
1891         PetscCall(DMPlexRestoreTransitiveClosure(*dm, p, PETSC_TRUE, &Ncl, &closure));
1892       }
1893     }
1894   }
1895 
1896   /* Setup coordinate DM */
1897   if (coordDim < 0) coordDim = dim;
1898   PetscCall(DMSetCoordinateDim(*dm, coordDim));
1899   PetscCall(DMGetCoordinateDM(*dm, &cdm));
1900   if (highOrder) {
1901     PetscFE         fe;
1902     PetscBool       continuity = periodic ? PETSC_FALSE : PETSC_TRUE;
1903     PetscDTNodeType nodeType   = PETSCDTNODES_EQUISPACED;
1904 
1905     if (isSimplex) continuity = PETSC_FALSE; /* XXX FIXME Requires DMPlexSetClosurePermutationLexicographic() */
1906 
1907     PetscCall(GmshCreateFE(comm, NULL, isSimplex, continuity, nodeType, dim, coordDim, order, &fe));
1908     PetscCall(PetscFEViewFromOptions(fe, NULL, "-dm_plex_gmsh_fe_view"));
1909     PetscCall(DMSetField(cdm, 0, NULL, (PetscObject)fe));
1910     PetscCall(PetscFEDestroy(&fe));
1911     PetscCall(DMCreateDS(cdm));
1912   }
1913   if (periodic) {
1914     PetscCall(DMClone(cdm, &cdmCell));
1915     PetscCall(DMSetCellCoordinateDM(*dm, cdmCell));
1916   }
1917 
1918   /* Create coordinates */
1919   if (highOrder) {
1920     PetscInt     maxDof = GmshNumNodes_HEX(order) * coordDim;
1921     double      *coords = mesh ? mesh->nodelist->xyz : NULL;
1922     PetscSection section;
1923     PetscScalar *cellCoords;
1924 
1925     PetscCall(DMSetLocalSection(cdm, NULL));
1926     PetscCall(DMGetLocalSection(cdm, &cs));
1927     PetscCall(PetscSectionClone(cs, &section));
1928     PetscCall(DMPlexSetClosurePermutationTensor(cdm, 0, section)); /* XXX Implement DMPlexSetClosurePermutationLexicographic() */
1929 
1930     PetscCall(DMCreateLocalVector(cdm, &coordinates));
1931     PetscCall(PetscMalloc1(maxDof, &cellCoords));
1932     for (cell = 0; cell < numCells; ++cell) {
1933       GmshElement *elem     = mesh->elements + cell;
1934       const int   *lexorder = GmshCellMap[elem->cellType].lexorder();
1935       int          s        = 0;
1936       for (n = 0; n < elem->numNodes; ++n) {
1937         while (lexorder[n + s] < 0) ++s;
1938         const PetscInt node = elem->nodes[lexorder[n + s]];
1939         for (d = 0; d < coordDim; ++d) cellCoords[(n + s) * coordDim + d] = (PetscReal)coords[node * 3 + d];
1940       }
1941       if (s) {
1942         /* For the coordinate mapping we weight vertices by -1/4 and edges by 1/2, which we get from Q_2 interpolation */
1943         PetscReal quaCenterWeights[9] = {-0.25, 0.5, -0.25, 0.5, 0.0, 0.5, -0.25, 0.5, -0.25};
1944         /* For the coordinate mapping we weight vertices by -1/4 and edges by 1/2, which we get from Q_2 interpolation */
1945         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};
1946         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};
1947         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};
1948         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};
1949         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};
1950         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};
1951         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};
1952         PetscReal  *sdWeights2[9]        = {NULL, NULL, NULL, NULL, quaCenterWeights, NULL, NULL, NULL, NULL};
1953         PetscReal  *sdWeights3[27]       = {NULL, NULL, NULL, NULL, hexBottomWeights, NULL, NULL, NULL, NULL, NULL, hexFrontWeights, NULL, hexLeftWeights, hexCenterWeights, hexRightWeights, NULL, hexBackWeights, NULL,
1954                                             NULL, NULL, NULL, NULL, hexTopWeights,    NULL, NULL, NULL, NULL};
1955         PetscReal **sdWeights[4]         = {NULL, NULL, sdWeights2, sdWeights3};
1956 
1957         /* Missing entries in serendipity cell, only works for 8-node quad and 20-node hex */
1958         for (n = 0; n < elem->numNodes + s; ++n) {
1959           if (lexorder[n] >= 0) continue;
1960           for (d = 0; d < coordDim; ++d) cellCoords[n * coordDim + d] = 0.0;
1961           for (int bn = 0; bn < elem->numNodes + s; ++bn) {
1962             if (lexorder[bn] < 0) continue;
1963             const PetscReal *weights = sdWeights[coordDim][n];
1964             const PetscInt   bnode   = elem->nodes[lexorder[bn]];
1965             for (d = 0; d < coordDim; ++d) cellCoords[n * coordDim + d] += weights[bn] * (PetscReal)coords[bnode * 3 + d];
1966           }
1967         }
1968       }
1969       PetscCall(DMPlexVecSetClosure(cdm, section, coordinates, cell, cellCoords, INSERT_VALUES));
1970     }
1971     PetscCall(PetscSectionDestroy(&section));
1972     PetscCall(PetscFree(cellCoords));
1973   } else {
1974     PetscInt    *nodeMap;
1975     double      *coords = mesh ? mesh->nodelist->xyz : NULL;
1976     PetscScalar *pointCoords;
1977 
1978     PetscCall(DMGetCoordinateSection(*dm, &cs));
1979     PetscCall(PetscSectionSetNumFields(cs, 1));
1980     PetscCall(PetscSectionSetFieldComponents(cs, 0, coordDim));
1981     PetscCall(PetscSectionSetChart(cs, numCells, numCells + numVerts));
1982     for (v = numCells; v < numCells + numVerts; ++v) {
1983       PetscCall(PetscSectionSetDof(cs, v, coordDim));
1984       PetscCall(PetscSectionSetFieldDof(cs, v, 0, coordDim));
1985     }
1986     PetscCall(PetscSectionSetUp(cs));
1987 
1988     /* We need to localize coordinates on cells */
1989     if (periodic) {
1990       PetscInt newStart = PETSC_MAX_INT, newEnd = -1, pStart, pEnd;
1991 
1992       PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)cdmCell), &csCell));
1993       PetscCall(PetscSectionSetNumFields(csCell, 1));
1994       PetscCall(PetscSectionSetFieldComponents(csCell, 0, coordDim));
1995       for (PetscInt h = 0; h <= maxHeight; h++) {
1996         PetscCall(DMPlexGetHeightStratum(cdmCell, h, &pStart, &pEnd));
1997         newStart = PetscMin(newStart, pStart);
1998         newEnd   = PetscMax(newEnd, pEnd);
1999       }
2000       PetscCall(PetscSectionSetChart(csCell, newStart, newEnd));
2001       for (PetscInt h = 0; h <= maxHeight; h++) {
2002         PetscCall(DMPlexGetHeightStratum(cdmCell, h, &pStart, &pEnd));
2003         for (PetscInt p = pStart; p < pEnd; ++p) {
2004           PetscInt *closure = NULL;
2005           PetscInt  Ncl, Nv = 0;
2006 
2007           if (PetscUnlikely(PetscBTLookup(periodicCells[h], p - pStart))) {
2008             PetscCall(DMPlexGetTransitiveClosure(*dm, p, PETSC_TRUE, &Ncl, &closure));
2009             for (PetscInt cl = 0; cl < Ncl * 2; cl += 2) {
2010               if (closure[cl] >= vStart && closure[cl] < vEnd) ++Nv;
2011             }
2012             PetscCall(DMPlexRestoreTransitiveClosure(*dm, p, PETSC_TRUE, &Ncl, &closure));
2013             PetscCall(PetscSectionSetDof(csCell, p, Nv * coordDim));
2014             PetscCall(PetscSectionSetFieldDof(csCell, p, 0, Nv * coordDim));
2015           }
2016         }
2017       }
2018       PetscCall(PetscSectionSetUp(csCell));
2019       PetscCall(DMSetCellCoordinateSection(*dm, PETSC_DETERMINE, csCell));
2020     }
2021 
2022     PetscCall(DMCreateLocalVector(cdm, &coordinates));
2023     PetscCall(VecGetArray(coordinates, &pointCoords));
2024     PetscCall(PetscMalloc1(numVerts, &nodeMap));
2025     for (n = 0; n < numNodes; n++)
2026       if (mesh->vertexMap[n] >= 0) nodeMap[mesh->vertexMap[n]] = n;
2027     for (v = 0; v < numVerts; ++v) {
2028       PetscInt off, node = nodeMap[v];
2029 
2030       PetscCall(PetscSectionGetOffset(cs, numCells + v, &off));
2031       for (d = 0; d < coordDim; ++d) pointCoords[off + d] = (PetscReal)coords[node * 3 + d];
2032     }
2033     PetscCall(VecRestoreArray(coordinates, &pointCoords));
2034 
2035     if (periodic) {
2036       PetscInt cStart, cEnd;
2037 
2038       PetscCall(DMPlexGetHeightStratum(cdmCell, 0, &cStart, &cEnd));
2039       PetscCall(DMCreateLocalVector(cdmCell, &coordinatesCell));
2040       PetscCall(VecGetArray(coordinatesCell, &pointCoords));
2041       for (PetscInt c = cStart; c < cEnd; ++c) {
2042         GmshElement *elem    = mesh->elements + c - cStart;
2043         PetscInt    *closure = NULL;
2044         PetscInt     verts[8];
2045         PetscInt     Ncl, Nv = 0;
2046 
2047         for (PetscInt v = 0; v < elem->numVerts; ++v) cone[v] = elem->nodes[v];
2048         PetscCall(DMPlexReorderCell(cdmCell, c, cone));
2049         PetscCall(DMPlexGetTransitiveClosure(cdmCell, c, PETSC_TRUE, &Ncl, &closure));
2050         for (PetscInt cl = 0; cl < Ncl * 2; cl += 2) {
2051           if (closure[cl] >= vStart && closure[cl] < vEnd) verts[Nv++] = closure[cl];
2052         }
2053         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);
2054         for (PetscInt cl = 0; cl < Ncl * 2; cl += 2) {
2055           const PetscInt point = closure[cl];
2056           PetscInt       hStart, h;
2057 
2058           PetscCall(DMPlexGetPointHeight(cdmCell, point, &h));
2059           if (h > maxHeight) continue;
2060           PetscCall(DMPlexGetHeightStratum(cdmCell, h, &hStart, NULL));
2061           if (PetscUnlikely(PetscBTLookup(periodicCells[h], point - hStart))) {
2062             PetscInt *pclosure = NULL;
2063             PetscInt  Npcl, off, v;
2064 
2065             PetscCall(PetscSectionGetOffset(csCell, point, &off));
2066             PetscCall(DMPlexGetTransitiveClosure(cdmCell, point, PETSC_TRUE, &Npcl, &pclosure));
2067             for (PetscInt pcl = 0; pcl < Npcl * 2; pcl += 2) {
2068               if (pclosure[pcl] >= vStart && pclosure[pcl] < vEnd) {
2069                 for (v = 0; v < Nv; ++v)
2070                   if (verts[v] == pclosure[pcl]) break;
2071                 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);
2072                 for (PetscInt d = 0; d < coordDim; ++d) pointCoords[off++] = (PetscReal)coords[cone[v] * 3 + d];
2073                 ++v;
2074               }
2075             }
2076             PetscCall(DMPlexRestoreTransitiveClosure(cdmCell, point, PETSC_TRUE, &Npcl, &pclosure));
2077           }
2078         }
2079         PetscCall(DMPlexRestoreTransitiveClosure(cdmCell, c, PETSC_TRUE, &Ncl, &closure));
2080       }
2081       PetscCall(VecSetBlockSize(coordinatesCell, coordDim));
2082       PetscCall(VecRestoreArray(coordinatesCell, &pointCoords));
2083       PetscCall(DMSetCellCoordinatesLocal(*dm, coordinatesCell));
2084       PetscCall(VecDestroy(&coordinatesCell));
2085     }
2086     PetscCall(PetscFree(nodeMap));
2087     PetscCall(PetscSectionDestroy(&csCell));
2088     PetscCall(DMDestroy(&cdmCell));
2089   }
2090 
2091   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
2092   PetscCall(VecSetBlockSize(coordinates, coordDim));
2093   PetscCall(DMSetCoordinatesLocal(*dm, coordinates));
2094   PetscCall(VecDestroy(&coordinates));
2095 
2096   PetscCall(GmshMeshDestroy(&mesh));
2097   PetscCall(PetscBTDestroy(&periodicVerts));
2098   if (periodic) {
2099     for (PetscInt h = 0; h <= maxHeight; ++h) PetscCall(PetscBTDestroy(periodicCells + h));
2100     PetscCall(PetscFree(periodicCells));
2101   }
2102 
2103   if (highOrder && project) {
2104     PetscFE         fe;
2105     const char      prefix[]   = "dm_plex_gmsh_project_";
2106     PetscBool       continuity = periodic ? PETSC_FALSE : PETSC_TRUE;
2107     PetscDTNodeType nodeType   = PETSCDTNODES_GAUSSJACOBI;
2108 
2109     if (isSimplex) continuity = PETSC_FALSE; /* XXX FIXME Requires DMPlexSetClosurePermutationLexicographic() */
2110     PetscCall(GmshCreateFE(comm, prefix, isSimplex, continuity, nodeType, dim, coordDim, order, &fe));
2111     PetscCall(PetscFEViewFromOptions(fe, NULL, "-dm_plex_gmsh_project_fe_view"));
2112     PetscCall(DMSetCoordinateDisc(*dm, fe, PETSC_TRUE));
2113     PetscCall(PetscFEDestroy(&fe));
2114   }
2115 
2116   PetscCall(PetscLogEventEnd(DMPLEX_CreateGmsh, *dm, NULL, NULL, NULL));
2117   PetscFunctionReturn(PETSC_SUCCESS);
2118 }
2119