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