xref: /petsc/src/dm/impls/plex/plexgmsh.c (revision 53134ebed6238e4143779c3e5c7db66beceae3ba)
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 #define DM_POLYTOPE_PYRAMID DM_POLYTOPE_UNKNOWN
1279 static const DMPolytopeType DMPolytopeMap[] = {
1280   /* GMSH_VTX */ DM_POLYTOPE_VERTEX,
1281   /* GMSH_SEG */ DM_POLYTOPE_SEGMENT,
1282   /* GMSH_TRI */ DM_POLYTOPE_TRIANGLE,
1283   /* GMSH_QUA */ DM_POLYTOPE_QUADRILATERAL,
1284   /* GMSH_TET */ DM_POLYTOPE_TETRAHEDRON,
1285   /* GMSH_HEX */ DM_POLYTOPE_HEXAHEDRON,
1286   /* GMSH_PRI */ DM_POLYTOPE_TRI_PRISM,
1287   /* GMSH_PYR */ DM_POLYTOPE_PYRAMID,
1288   DM_POLYTOPE_UNKNOWN
1289 };
1290 
1291 static inline DMPolytopeType DMPolytopeTypeFromGmsh(PetscInt cellType)
1292 {
1293   return DMPolytopeMap[GmshCellMap[cellType].polytope];
1294 }
1295 
1296 static PetscErrorCode GmshCreateFE(MPI_Comm comm, const char prefix[], PetscBool isSimplex, PetscBool continuity, PetscDTNodeType nodeType, PetscInt dim, PetscInt Nc, PetscInt k, PetscFE *fem)
1297 {
1298   DM              K;
1299   PetscSpace      P;
1300   PetscDualSpace  Q;
1301   PetscQuadrature q, fq;
1302   PetscBool       isTensor = isSimplex ? PETSC_FALSE : PETSC_TRUE;
1303   PetscBool       endpoint = PETSC_TRUE;
1304   char            name[32];
1305 
1306   PetscFunctionBegin;
1307   /* Create space */
1308   PetscCall(PetscSpaceCreate(comm, &P));
1309   PetscCall(PetscSpaceSetType(P, PETSCSPACEPOLYNOMIAL));
1310   PetscCall(PetscSpacePolynomialSetTensor(P, isTensor));
1311   PetscCall(PetscSpaceSetNumComponents(P, Nc));
1312   PetscCall(PetscSpaceSetNumVariables(P, dim));
1313   PetscCall(PetscSpaceSetDegree(P, k, PETSC_DETERMINE));
1314   if (prefix) {
1315     PetscCall(PetscObjectSetOptionsPrefix((PetscObject) P, prefix));
1316     PetscCall(PetscSpaceSetFromOptions(P));
1317     PetscCall(PetscObjectSetOptionsPrefix((PetscObject) P, NULL));
1318     PetscCall(PetscSpaceGetDegree(P, &k, NULL));
1319   }
1320   PetscCall(PetscSpaceSetUp(P));
1321   /* Create dual space */
1322   PetscCall(PetscDualSpaceCreate(comm, &Q));
1323   PetscCall(PetscDualSpaceSetType(Q, PETSCDUALSPACELAGRANGE));
1324   PetscCall(PetscDualSpaceLagrangeSetTensor(Q, isTensor));
1325   PetscCall(PetscDualSpaceLagrangeSetContinuity(Q, continuity));
1326   PetscCall(PetscDualSpaceLagrangeSetNodeType(Q, nodeType, endpoint, 0));
1327   PetscCall(PetscDualSpaceSetNumComponents(Q, Nc));
1328   PetscCall(PetscDualSpaceSetOrder(Q, k));
1329   PetscCall(DMPlexCreateReferenceCell(PETSC_COMM_SELF, DMPolytopeTypeSimpleShape(dim, isSimplex), &K));
1330   PetscCall(PetscDualSpaceSetDM(Q, K));
1331   PetscCall(DMDestroy(&K));
1332   if (prefix) {
1333     PetscCall(PetscObjectSetOptionsPrefix((PetscObject) Q, prefix));
1334     PetscCall(PetscDualSpaceSetFromOptions(Q));
1335     PetscCall(PetscObjectSetOptionsPrefix((PetscObject) Q, NULL));
1336   }
1337   PetscCall(PetscDualSpaceSetUp(Q));
1338   /* Create quadrature */
1339   if (isSimplex) {
1340     PetscCall(PetscDTStroudConicalQuadrature(dim,   1, k+1, -1, +1, &q));
1341     PetscCall(PetscDTStroudConicalQuadrature(dim-1, 1, k+1, -1, +1, &fq));
1342   } else {
1343     PetscCall(PetscDTGaussTensorQuadrature(dim,   1, k+1, -1, +1, &q));
1344     PetscCall(PetscDTGaussTensorQuadrature(dim-1, 1, k+1, -1, +1, &fq));
1345   }
1346   /* Create finite element */
1347   PetscCall(PetscFECreate(comm, fem));
1348   PetscCall(PetscFESetType(*fem, PETSCFEBASIC));
1349   PetscCall(PetscFESetNumComponents(*fem, Nc));
1350   PetscCall(PetscFESetBasisSpace(*fem, P));
1351   PetscCall(PetscFESetDualSpace(*fem, Q));
1352   PetscCall(PetscFESetQuadrature(*fem, q));
1353   PetscCall(PetscFESetFaceQuadrature(*fem, fq));
1354   if (prefix) {
1355     PetscCall(PetscObjectSetOptionsPrefix((PetscObject) *fem, prefix));
1356     PetscCall(PetscFESetFromOptions(*fem));
1357     PetscCall(PetscObjectSetOptionsPrefix((PetscObject) *fem, NULL));
1358   }
1359   PetscCall(PetscFESetUp(*fem));
1360   /* Cleanup */
1361   PetscCall(PetscSpaceDestroy(&P));
1362   PetscCall(PetscDualSpaceDestroy(&Q));
1363   PetscCall(PetscQuadratureDestroy(&q));
1364   PetscCall(PetscQuadratureDestroy(&fq));
1365   /* Set finite element name */
1366   PetscCall(PetscSNPrintf(name, sizeof(name), "%s%" PetscInt_FMT, isSimplex? "P" : "Q", k));
1367   PetscCall(PetscFESetName(*fem, name));
1368   PetscFunctionReturn(0);
1369 }
1370 
1371 /*@C
1372   DMPlexCreateGmshFromFile - Create a DMPlex mesh from a Gmsh file
1373 
1374 + comm        - The MPI communicator
1375 . filename    - Name of the Gmsh file
1376 - interpolate - Create faces and edges in the mesh
1377 
1378   Output Parameter:
1379 . dm  - The DM object representing the mesh
1380 
1381   Level: beginner
1382 
1383 .seealso: `DMPlexCreateFromFile()`, `DMPlexCreateGmsh()`, `DMPlexCreate()`
1384 @*/
1385 PetscErrorCode DMPlexCreateGmshFromFile(MPI_Comm comm, const char filename[], PetscBool interpolate, DM *dm)
1386 {
1387   PetscViewer     viewer;
1388   PetscMPIInt     rank;
1389   int             fileType;
1390   PetscViewerType vtype;
1391 
1392   PetscFunctionBegin;
1393   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1394 
1395   /* Determine Gmsh file type (ASCII or binary) from file header */
1396   if (rank == 0) {
1397     GmshFile    gmsh[1];
1398     char        line[PETSC_MAX_PATH_LEN];
1399     int         snum;
1400     float       version;
1401     int         fileFormat;
1402 
1403     PetscCall(PetscArrayzero(gmsh,1));
1404     PetscCall(PetscViewerCreate(PETSC_COMM_SELF, &gmsh->viewer));
1405     PetscCall(PetscViewerSetType(gmsh->viewer, PETSCVIEWERASCII));
1406     PetscCall(PetscViewerFileSetMode(gmsh->viewer, FILE_MODE_READ));
1407     PetscCall(PetscViewerFileSetName(gmsh->viewer, filename));
1408     /* Read only the first two lines of the Gmsh file */
1409     PetscCall(GmshReadSection(gmsh, line));
1410     PetscCall(GmshExpect(gmsh, "$MeshFormat", line));
1411     PetscCall(GmshReadString(gmsh, line, 2));
1412     snum = sscanf(line, "%f %d", &version, &fileType);
1413     fileFormat = (int)roundf(version*10);
1414     PetscCheck(snum == 2,PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to parse Gmsh file header: %s", line);
1415     PetscCheck(fileFormat >= 22,PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at least 2.2", (double)version);
1416     PetscCheck((int)version != 3,PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f not supported", (double)version);
1417     PetscCheck(fileFormat <= 41,PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at most 4.1", (double)version);
1418     PetscCall(PetscViewerDestroy(&gmsh->viewer));
1419   }
1420   PetscCallMPI(MPI_Bcast(&fileType, 1, MPI_INT, 0, comm));
1421   vtype = (fileType == 0) ? PETSCVIEWERASCII : PETSCVIEWERBINARY;
1422 
1423   /* Create appropriate viewer and build plex */
1424   PetscCall(PetscViewerCreate(comm, &viewer));
1425   PetscCall(PetscViewerSetType(viewer, vtype));
1426   PetscCall(PetscViewerFileSetMode(viewer, FILE_MODE_READ));
1427   PetscCall(PetscViewerFileSetName(viewer, filename));
1428   PetscCall(DMPlexCreateGmsh(comm, viewer, interpolate, dm));
1429   PetscCall(PetscViewerDestroy(&viewer));
1430   PetscFunctionReturn(0);
1431 }
1432 
1433 /*@
1434   DMPlexCreateGmsh - Create a DMPlex mesh from a Gmsh file viewer
1435 
1436   Collective
1437 
1438   Input Parameters:
1439 + comm  - The MPI communicator
1440 . viewer - The Viewer associated with a Gmsh file
1441 - interpolate - Create faces and edges in the mesh
1442 
1443   Output Parameter:
1444 . dm  - The DM object representing the mesh
1445 
1446   Note: http://gmsh.info/doc/texinfo/gmsh.html#MSH-file-format
1447 
1448   Level: beginner
1449 
1450 .seealso: `DMPLEX`, `DMCreate()`
1451 @*/
1452 PetscErrorCode DMPlexCreateGmsh(MPI_Comm comm, PetscViewer viewer, PetscBool interpolate, DM *dm)
1453 {
1454   GmshMesh      *mesh = NULL;
1455   PetscViewer    parentviewer = NULL;
1456   PetscBT        periodicVerts = NULL;
1457   PetscBT        periodicCells = NULL;
1458   DM             cdm, cdmCell = NULL;
1459   PetscSection   cs, csCell = NULL;
1460   Vec            coordinates, coordinatesCell;
1461   DMLabel        cellSets = NULL, faceSets = NULL, vertSets = NULL, marker = NULL, *regionSets;
1462   PetscInt       dim = 0, coordDim = -1, order = 0;
1463   PetscInt       numNodes = 0, numElems = 0, numVerts = 0, numCells = 0;
1464   PetscInt       cell, cone[8], e, n, v, d;
1465   PetscBool      binary, usemarker = PETSC_FALSE, useregions = PETSC_FALSE, markvertices = PETSC_FALSE;
1466   PetscBool      hybrid = interpolate, periodic = PETSC_TRUE;
1467   PetscBool      highOrder = PETSC_TRUE, highOrderSet, project = PETSC_FALSE;
1468   PetscBool      isSimplex = PETSC_FALSE, isHybrid = PETSC_FALSE, hasTetra = PETSC_FALSE;
1469   PetscMPIInt    rank;
1470 
1471   PetscFunctionBegin;
1472   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1473   PetscObjectOptionsBegin((PetscObject)viewer);
1474   PetscOptionsHeadBegin(PetscOptionsObject,"DMPlex Gmsh options");
1475   PetscCall(PetscOptionsBool("-dm_plex_gmsh_hybrid", "Generate hybrid cell bounds", "DMPlexCreateGmsh", hybrid, &hybrid, NULL));
1476   PetscCall(PetscOptionsBool("-dm_plex_gmsh_periodic","Read Gmsh periodic section", "DMPlexCreateGmsh", periodic, &periodic, NULL));
1477   PetscCall(PetscOptionsBool("-dm_plex_gmsh_highorder","Generate high-order coordinates", "DMPlexCreateGmsh", highOrder, &highOrder, &highOrderSet));
1478   PetscCall(PetscOptionsBool("-dm_plex_gmsh_project", "Project high-order coordinates to a different space", "DMPlexCreateGmsh", project, &project, NULL));
1479   PetscCall(PetscOptionsBool("-dm_plex_gmsh_use_marker", "Generate marker label", "DMPlexCreateGmsh", usemarker, &usemarker, NULL));
1480   PetscCall(PetscOptionsBool("-dm_plex_gmsh_use_regions", "Generate labels with region names", "DMPlexCreateGmsh", useregions, &useregions, NULL));
1481   PetscCall(PetscOptionsBool("-dm_plex_gmsh_mark_vertices", "Add vertices to generated labels", "DMPlexCreateGmsh", markvertices, &markvertices, NULL));
1482   PetscCall(PetscOptionsBoundedInt("-dm_plex_gmsh_spacedim", "Embedding space dimension", "DMPlexCreateGmsh", coordDim, &coordDim, NULL, PETSC_DECIDE));
1483   PetscOptionsHeadEnd();
1484   PetscOptionsEnd();
1485 
1486   PetscCall(GmshCellInfoSetUp());
1487 
1488   PetscCall(DMCreate(comm, dm));
1489   PetscCall(DMSetType(*dm, DMPLEX));
1490   PetscCall(PetscLogEventBegin(DMPLEX_CreateGmsh,*dm,NULL,NULL,NULL));
1491 
1492   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &binary));
1493 
1494   /* Binary viewers read on all ranks, get subviewer to read only in rank 0 */
1495   if (binary) {
1496     parentviewer = viewer;
1497     PetscCall(PetscViewerGetSubViewer(parentviewer, PETSC_COMM_SELF, &viewer));
1498   }
1499 
1500   if (rank == 0) {
1501     GmshFile  gmsh[1];
1502     char      line[PETSC_MAX_PATH_LEN];
1503     PetscBool match;
1504 
1505     PetscCall(PetscArrayzero(gmsh,1));
1506     gmsh->viewer = viewer;
1507     gmsh->binary = binary;
1508 
1509     PetscCall(GmshMeshCreate(&mesh));
1510 
1511     /* Read mesh format */
1512     PetscCall(GmshReadSection(gmsh, line));
1513     PetscCall(GmshExpect(gmsh, "$MeshFormat", line));
1514     PetscCall(GmshReadMeshFormat(gmsh));
1515     PetscCall(GmshReadEndSection(gmsh, "$EndMeshFormat", line));
1516 
1517     /* OPTIONAL Read physical names */
1518     PetscCall(GmshReadSection(gmsh, line));
1519     PetscCall(GmshMatch(gmsh, "$PhysicalNames", line, &match));
1520     if (match) {
1521       PetscCall(GmshExpect(gmsh, "$PhysicalNames", line));
1522       PetscCall(GmshReadPhysicalNames(gmsh, mesh));
1523       PetscCall(GmshReadEndSection(gmsh, "$EndPhysicalNames", line));
1524       /* Initial read for entity section */
1525       PetscCall(GmshReadSection(gmsh, line));
1526     }
1527 
1528     /* Read entities */
1529     if (gmsh->fileFormat >= 40) {
1530       PetscCall(GmshExpect(gmsh, "$Entities", line));
1531       PetscCall(GmshReadEntities(gmsh, mesh));
1532       PetscCall(GmshReadEndSection(gmsh, "$EndEntities", line));
1533       /* Initial read for nodes section */
1534       PetscCall(GmshReadSection(gmsh, line));
1535     }
1536 
1537     /* Read nodes */
1538     PetscCall(GmshExpect(gmsh, "$Nodes", line));
1539     PetscCall(GmshReadNodes(gmsh, mesh));
1540     PetscCall(GmshReadEndSection(gmsh, "$EndNodes", line));
1541 
1542     /* Read elements */
1543     PetscCall(GmshReadSection(gmsh, line));
1544     PetscCall(GmshExpect(gmsh, "$Elements", line));
1545     PetscCall(GmshReadElements(gmsh, mesh));
1546     PetscCall(GmshReadEndSection(gmsh, "$EndElements", line));
1547 
1548     /* Read periodic section (OPTIONAL) */
1549     if (periodic) {
1550       PetscCall(GmshReadSection(gmsh, line));
1551       PetscCall(GmshMatch(gmsh, "$Periodic", line, &periodic));
1552     }
1553     if (periodic) {
1554       PetscCall(GmshExpect(gmsh, "$Periodic", line));
1555       PetscCall(GmshReadPeriodic(gmsh, mesh));
1556       PetscCall(GmshReadEndSection(gmsh, "$EndPeriodic", line));
1557     }
1558 
1559     PetscCall(PetscFree(gmsh->wbuf));
1560     PetscCall(PetscFree(gmsh->sbuf));
1561     PetscCall(PetscFree(gmsh->nbuf));
1562 
1563     dim       = mesh->dim;
1564     order     = mesh->order;
1565     numNodes  = mesh->numNodes;
1566     numElems  = mesh->numElems;
1567     numVerts  = mesh->numVerts;
1568     numCells  = mesh->numCells;
1569 
1570     {
1571       GmshElement *elemA = mesh->numCells > 0 ? mesh->elements : NULL;
1572       GmshElement *elemB = elemA ? elemA + mesh->numCells - 1  : NULL;
1573       int ptA = elemA ? GmshCellMap[elemA->cellType].polytope : -1;
1574       int ptB = elemB ? GmshCellMap[elemB->cellType].polytope : -1;
1575       isSimplex = (ptA == GMSH_QUA || ptA == GMSH_HEX) ? PETSC_FALSE : PETSC_TRUE;
1576       isHybrid  = (ptA == ptB) ? PETSC_FALSE : PETSC_TRUE;
1577       hasTetra  = (ptA == GMSH_TET) ? PETSC_TRUE : PETSC_FALSE;
1578     }
1579   }
1580 
1581   if (parentviewer) {
1582     PetscCall(PetscViewerRestoreSubViewer(parentviewer, PETSC_COMM_SELF, &viewer));
1583   }
1584 
1585   {
1586     int buf[6];
1587 
1588     buf[0] = (int)dim;
1589     buf[1] = (int)order;
1590     buf[2] = periodic;
1591     buf[3] = isSimplex;
1592     buf[4] = isHybrid;
1593     buf[5] = hasTetra;
1594 
1595     PetscCallMPI(MPI_Bcast(buf, 6, MPI_INT, 0, comm));
1596 
1597     dim       = buf[0];
1598     order     = buf[1];
1599     periodic  = buf[2] ? PETSC_TRUE : PETSC_FALSE;
1600     isSimplex = buf[3] ? PETSC_TRUE : PETSC_FALSE;
1601     isHybrid  = buf[4] ? PETSC_TRUE : PETSC_FALSE;
1602     hasTetra  = buf[5] ? PETSC_TRUE : PETSC_FALSE;
1603   }
1604 
1605   if (!highOrderSet) highOrder = (order > 1) ? PETSC_TRUE : PETSC_FALSE;
1606   PetscCheck(!highOrder || !isHybrid,comm, PETSC_ERR_SUP, "No support for discretization on hybrid meshes yet");
1607 
1608   /* We do not want this label automatically computed, instead we fill it here */
1609   PetscCall(DMCreateLabel(*dm, "celltype"));
1610 
1611   /* Allocate the cell-vertex mesh */
1612   PetscCall(DMPlexSetChart(*dm, 0, numCells+numVerts));
1613   for (cell = 0; cell < numCells; ++cell) {
1614     GmshElement *elem = mesh->elements + cell;
1615     DMPolytopeType ctype = DMPolytopeTypeFromGmsh(elem->cellType);
1616     if (hybrid && hasTetra && ctype == DM_POLYTOPE_TRI_PRISM) ctype = DM_POLYTOPE_TRI_PRISM_TENSOR;
1617     PetscCall(DMPlexSetConeSize(*dm, cell, elem->numVerts));
1618     PetscCall(DMPlexSetCellType(*dm, cell, ctype));
1619   }
1620   for (v = numCells; v < numCells+numVerts; ++v) {
1621     PetscCall(DMPlexSetCellType(*dm, v, DM_POLYTOPE_POINT));
1622   }
1623   PetscCall(DMSetUp(*dm));
1624 
1625   /* Add cell-vertex connections */
1626   for (cell = 0; cell < numCells; ++cell) {
1627     GmshElement *elem = mesh->elements + cell;
1628     for (v = 0; v < elem->numVerts; ++v) {
1629       const PetscInt nn = elem->nodes[v];
1630       const PetscInt vv = mesh->vertexMap[nn];
1631       cone[v] = numCells + vv;
1632     }
1633     PetscCall(DMPlexReorderCell(*dm, cell, cone));
1634     PetscCall(DMPlexSetCone(*dm, cell, cone));
1635   }
1636 
1637   PetscCall(DMSetDimension(*dm, dim));
1638   PetscCall(DMPlexSymmetrize(*dm));
1639   PetscCall(DMPlexStratify(*dm));
1640   if (interpolate) {
1641     DM idm;
1642 
1643     PetscCall(DMPlexInterpolate(*dm, &idm));
1644     PetscCall(DMDestroy(dm));
1645     *dm  = idm;
1646   }
1647 
1648   /* Create the label "marker" over the whole boundary */
1649   PetscCheck(!usemarker || interpolate || dim <= 1,comm,PETSC_ERR_SUP,"Cannot create marker label without interpolation");
1650   if (rank == 0 && usemarker) {
1651     PetscInt f, fStart, fEnd;
1652 
1653     PetscCall(DMCreateLabel(*dm, "marker"));
1654     PetscCall(DMPlexGetHeightStratum(*dm, 1, &fStart, &fEnd));
1655     for (f = fStart; f < fEnd; ++f) {
1656       PetscInt suppSize;
1657 
1658       PetscCall(DMPlexGetSupportSize(*dm, f, &suppSize));
1659       if (suppSize == 1) {
1660         PetscInt *cone = NULL, coneSize, p;
1661 
1662         PetscCall(DMPlexGetTransitiveClosure(*dm, f, PETSC_TRUE, &coneSize, &cone));
1663         for (p = 0; p < coneSize; p += 2) {
1664           PetscCall(DMSetLabelValue_Fast(*dm, &marker, "marker", cone[p], 1));
1665         }
1666         PetscCall(DMPlexRestoreTransitiveClosure(*dm, f, PETSC_TRUE, &coneSize, &cone));
1667       }
1668     }
1669   }
1670 
1671   if (rank == 0) {
1672     const PetscInt Nr = useregions ? mesh->numRegions : 0;
1673     PetscInt       vStart, vEnd;
1674 
1675     PetscCall(PetscCalloc1(Nr, &regionSets));
1676     PetscCall(DMPlexGetDepthStratum(*dm, 0, &vStart, &vEnd));
1677     for (cell = 0, e = 0; e < numElems; ++e) {
1678       GmshElement *elem = mesh->elements + e;
1679 
1680       /* Create cell sets */
1681       if (elem->dim == dim && dim > 0) {
1682         if (elem->numTags > 0) {
1683           const PetscInt tag = elem->tags[0];
1684           PetscInt       r;
1685 
1686           if (!Nr) PetscCall(DMSetLabelValue_Fast(*dm, &cellSets, "Cell Sets", cell, tag));
1687           for (r = 0; r < Nr; ++r) {
1688             if (mesh->regionTags[r] == tag) PetscCall(DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], cell, tag));
1689           }
1690         }
1691         cell++;
1692       }
1693 
1694       /* Create face sets */
1695       if (interpolate && elem->dim == dim-1) {
1696         PetscInt        joinSize;
1697         const PetscInt *join = NULL;
1698         const PetscInt  tag = elem->tags[0];
1699         PetscInt        r;
1700 
1701         /* Find the relevant facet with vertex joins */
1702         for (v = 0; v < elem->numVerts; ++v) {
1703           const PetscInt nn = elem->nodes[v];
1704           const PetscInt vv = mesh->vertexMap[nn];
1705           cone[v] = vStart + vv;
1706         }
1707         PetscCall(DMPlexGetFullJoin(*dm, elem->numVerts, cone, &joinSize, &join));
1708         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);
1709         if (!Nr) PetscCall(DMSetLabelValue_Fast(*dm, &faceSets, "Face Sets", join[0], tag));
1710         for (r = 0; r < Nr; ++r) {
1711           if (mesh->regionTags[r] == tag) PetscCall(DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], join[0], tag));
1712         }
1713         PetscCall(DMPlexRestoreJoin(*dm, elem->numVerts, cone, &joinSize, &join));
1714       }
1715 
1716       /* Create vertex sets */
1717       if (elem->dim == 0) {
1718         if (elem->numTags > 0) {
1719           const PetscInt nn = elem->nodes[0];
1720           const PetscInt vv = mesh->vertexMap[nn];
1721           const PetscInt tag = elem->tags[0];
1722           PetscInt       r;
1723 
1724           if (!Nr) PetscCall(DMSetLabelValue_Fast(*dm, &vertSets, "Vertex Sets", vStart + vv, tag));
1725           for (r = 0; r < Nr; ++r) {
1726             if (mesh->regionTags[r] == tag) PetscCall(DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], vStart + vv, tag));
1727           }
1728         }
1729       }
1730     }
1731     if (markvertices) {
1732       for (v = 0; v < numNodes; ++v) {
1733         const PetscInt  vv   = mesh->vertexMap[v];
1734         const PetscInt *tags = &mesh->nodelist->tag[v*GMSH_MAX_TAGS];
1735         PetscInt        r, t;
1736 
1737         for (t = 0; t < GMSH_MAX_TAGS; ++t) {
1738           const PetscInt tag = tags[t];
1739 
1740           if (tag == -1) continue;
1741           if (!Nr) PetscCall(DMSetLabelValue_Fast(*dm, &vertSets, "Vertex Sets", vStart + vv, tag));
1742           for (r = 0; r < Nr; ++r) {
1743             if (mesh->regionTags[r] == tag) PetscCall(DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], vStart + vv, tag));
1744           }
1745         }
1746       }
1747     }
1748     PetscCall(PetscFree(regionSets));
1749   }
1750 
1751   { /* Create Cell/Face/Vertex Sets labels at all processes */
1752     enum {n = 4};
1753     PetscBool flag[n];
1754 
1755     flag[0] = cellSets ? PETSC_TRUE : PETSC_FALSE;
1756     flag[1] = faceSets ? PETSC_TRUE : PETSC_FALSE;
1757     flag[2] = vertSets ? PETSC_TRUE : PETSC_FALSE;
1758     flag[3] = marker   ? PETSC_TRUE : PETSC_FALSE;
1759     PetscCallMPI(MPI_Bcast(flag, n, MPIU_BOOL, 0, comm));
1760     if (flag[0]) PetscCall(DMCreateLabel(*dm, "Cell Sets"));
1761     if (flag[1]) PetscCall(DMCreateLabel(*dm, "Face Sets"));
1762     if (flag[2]) PetscCall(DMCreateLabel(*dm, "Vertex Sets"));
1763     if (flag[3]) PetscCall(DMCreateLabel(*dm, "marker"));
1764   }
1765 
1766   if (periodic) {
1767     PetscCall(PetscBTCreate(numVerts, &periodicVerts));
1768     for (n = 0; n < numNodes; ++n) {
1769       if (mesh->vertexMap[n] >= 0) {
1770         if (PetscUnlikely(mesh->periodMap[n] != n)) {
1771           PetscInt m = mesh->periodMap[n];
1772           PetscCall(PetscBTSet(periodicVerts, mesh->vertexMap[n]));
1773           PetscCall(PetscBTSet(periodicVerts, mesh->vertexMap[m]));
1774         }
1775       }
1776     }
1777     PetscCall(PetscBTCreate(numCells, &periodicCells));
1778     for (cell = 0; cell < numCells; ++cell) {
1779       GmshElement *elem = mesh->elements + cell;
1780       for (v = 0; v < elem->numVerts; ++v) {
1781         PetscInt nn = elem->nodes[v];
1782         PetscInt vv = mesh->vertexMap[nn];
1783         if (PetscUnlikely(PetscBTLookup(periodicVerts, vv))) {
1784           PetscCall(PetscBTSet(periodicCells, cell)); break;
1785         }
1786       }
1787     }
1788   }
1789 
1790   /* Setup coordinate DM */
1791   if (coordDim < 0) coordDim = dim;
1792   PetscCall(DMSetCoordinateDim(*dm, coordDim));
1793   PetscCall(DMGetCoordinateDM(*dm, &cdm));
1794   if (highOrder) {
1795     PetscFE         fe;
1796     PetscBool       continuity = periodic ? PETSC_FALSE : PETSC_TRUE;
1797     PetscDTNodeType nodeType   = PETSCDTNODES_EQUISPACED;
1798 
1799     if (isSimplex) continuity = PETSC_FALSE; /* XXX FIXME Requires DMPlexSetClosurePermutationLexicographic() */
1800 
1801     PetscCall(GmshCreateFE(comm, NULL, isSimplex, continuity, nodeType, dim, coordDim, order, &fe));
1802     PetscCall(PetscFEViewFromOptions(fe, NULL, "-dm_plex_gmsh_fe_view"));
1803     PetscCall(DMSetField(cdm, 0, NULL, (PetscObject) fe));
1804     PetscCall(PetscFEDestroy(&fe));
1805     PetscCall(DMCreateDS(cdm));
1806   }
1807   if (periodic) {
1808     PetscCall(DMClone(cdm, &cdmCell));
1809     PetscCall(DMSetCellCoordinateDM(*dm, cdmCell));
1810   }
1811 
1812   /* Create coordinates */
1813   if (highOrder) {
1814     PetscInt     maxDof = GmshNumNodes_HEX(order)*coordDim;
1815     double       *coords = mesh ? mesh->nodelist->xyz : NULL;
1816     PetscSection section;
1817     PetscScalar  *cellCoords;
1818 
1819     PetscCall(DMSetLocalSection(cdm, NULL));
1820     PetscCall(DMGetLocalSection(cdm, &cs));
1821     PetscCall(PetscSectionClone(cs, &section));
1822     PetscCall(DMPlexSetClosurePermutationTensor(cdm, 0, section)); /* XXX Implement DMPlexSetClosurePermutationLexicographic() */
1823 
1824     PetscCall(DMCreateLocalVector(cdm, &coordinates));
1825     PetscCall(PetscMalloc1(maxDof, &cellCoords));
1826     for (cell = 0; cell < numCells; ++cell) {
1827       GmshElement *elem = mesh->elements + cell;
1828       const int *lexorder = GmshCellMap[elem->cellType].lexorder();
1829       int s = 0;
1830       for (n = 0; n < elem->numNodes; ++n) {
1831         while (lexorder[n+s] < 0) ++s;
1832         const PetscInt node = elem->nodes[lexorder[n+s]];
1833         for (d = 0; d < coordDim; ++d) cellCoords[(n+s)*coordDim+d] = (PetscReal) coords[node*3+d];
1834       }
1835       if (s) {
1836         /* For the coordinate mapping we weight vertices by -1/4 and edges by 1/2, which we get from Q_2 interpolation */
1837         PetscReal quaCenterWeights[9]  = {-0.25, 0.5, -0.25, 0.5, 0.0, 0.5, -0.25, 0.5, -0.25};
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 hexBottomWeights[27] = {-0.25, 0.5,  -0.25, 0.5,  0.0, 0.5,  -0.25, 0.5,  -0.25,
1840                                            0.0,  0.0,   0.0,  0.0,  0.0, 0.0,   0.0,  0.0,   0.0,
1841                                            0.0,  0.0,   0.0,  0.0,  0.0, 0.0,   0.0,  0.0,   0.0};
1842         PetscReal hexFrontWeights[27]  = {-0.25, 0.5,  -0.25, 0.0,  0.0, 0.0,   0.0,  0.0,   0.0,
1843                                            0.5,  0.0,   0.5,  0.0,  0.0, 0.0,   0.0,  0.0,   0.0,
1844                                           -0.25, 0.5,  -0.25, 0.0,  0.0, 0.0,   0.0,  0.0,   0.0};
1845         PetscReal hexLeftWeights[27]   = {-0.25, 0.0,   0.0,  0.5,  0.0, 0.0,  -0.25, 0.0,   0.0,
1846                                            0.5,  0.0,   0.0,  0.0,  0.0, 0.0,   0.5,  0.0,   0.0,
1847                                           -0.25, 0.0,   0.0,  0.5,  0.0, 0.0,  -0.25, 0.0,   0.0};
1848         PetscReal hexRightWeights[27]  = { 0.0,  0.0,  -0.25, 0.0,  0.0, 0.5,   0.0,  0.0,  -0.25,
1849                                            0.0,  0.0,   0.5,  0.0,  0.0, 0.0,   0.0,  0.0,   0.5,
1850                                            0.0,  0.0,  -0.25, 0.0,  0.0, 0.5,   0.0,  0.0,  -0.25};
1851         PetscReal hexBackWeights[27]   = { 0.0,  0.0,   0.0,  0.0,  0.0, 0.0,  -0.25, 0.5,  -0.25,
1852                                            0.0,  0.0,   0.0,  0.0,  0.0, 0.0,   0.5,  0.0,   0.5,
1853                                            0.0,  0.0,   0.0,  0.0,  0.0, 0.0,  -0.25, 0.5,  -0.25};
1854         PetscReal hexTopWeights[27]    = { 0.0,  0.0,   0.0,  0.0,  0.0, 0.0,   0.0,  0.0,   0.0,
1855                                            0.0,  0.0,   0.0,  0.0,  0.0, 0.0,   0.0,  0.0,   0.0,
1856                                           -0.25, 0.5,  -0.25, 0.5,  0.0, 0.5,  -0.25, 0.5,  -0.25};
1857         PetscReal hexCenterWeights[27] = {-0.25, 0.25, -0.25, 0.25, 0.0, 0.25, -0.25, 0.25, -0.25,
1858                                            0.25, 0.0,   0.25, 0.0,  0.0, 0.0,   0.25, 0.0,   0.25,
1859                                           -0.25, 0.25, -0.25, 0.25, 0.0, 0.25, -0.25, 0.25, -0.25};
1860         PetscReal  *sdWeights2[9]      = {NULL, NULL, NULL, NULL, quaCenterWeights, NULL, NULL, NULL, NULL};
1861         PetscReal  *sdWeights3[27]     = {NULL, NULL, NULL, NULL, hexBottomWeights, NULL, NULL, NULL, NULL,
1862                                           NULL, hexFrontWeights, NULL, hexLeftWeights, hexCenterWeights, hexRightWeights, NULL, hexBackWeights, NULL,
1863                                           NULL, NULL, NULL, NULL, hexTopWeights,    NULL, NULL, NULL, NULL};
1864         PetscReal **sdWeights[4]       = {NULL, NULL, sdWeights2, sdWeights3};
1865 
1866         /* Missing entries in serendipity cell, only works for 8-node quad and 20-node hex */
1867         for (n = 0; n < elem->numNodes+s; ++n) {
1868           if (lexorder[n] >= 0) continue;
1869           for (d = 0; d < coordDim; ++d) cellCoords[n*coordDim+d] = 0.0;
1870           for (int bn = 0; bn < elem->numNodes+s; ++bn) {
1871             if (lexorder[bn] < 0) continue;
1872             const PetscReal *weights = sdWeights[coordDim][n];
1873             const PetscInt   bnode   = elem->nodes[lexorder[bn]];
1874             for (d = 0; d < coordDim; ++d) cellCoords[n*coordDim+d] += weights[bn] * (PetscReal) coords[bnode*3+d];
1875           }
1876         }
1877       }
1878       PetscCall(DMPlexVecSetClosure(cdm, section, coordinates, cell, cellCoords, INSERT_VALUES));
1879     }
1880     PetscCall(PetscSectionDestroy(&section));
1881     PetscCall(PetscFree(cellCoords));
1882   } else {
1883     PetscInt    *nodeMap;
1884     double      *coords = mesh ? mesh->nodelist->xyz : NULL;
1885     PetscScalar *pointCoords;
1886 
1887     PetscCall(DMGetCoordinateSection(*dm, &cs));
1888     PetscCall(PetscSectionSetNumFields(cs, 1));
1889     PetscCall(PetscSectionSetFieldComponents(cs, 0, coordDim));
1890     PetscCall(PetscSectionSetChart(cs, numCells, numCells+numVerts));
1891     for (v = numCells; v < numCells+numVerts; ++v) {
1892       PetscCall(PetscSectionSetDof(cs, v, coordDim));
1893       PetscCall(PetscSectionSetFieldDof(cs, v, 0, coordDim));
1894     }
1895     PetscCall(PetscSectionSetUp(cs));
1896 
1897     /* We need to localize coordinates on cells */
1898     if (periodic) {
1899       PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) cdmCell), &csCell));
1900       PetscCall(PetscSectionSetNumFields(csCell, 1));
1901       PetscCall(PetscSectionSetFieldComponents(csCell, 0, coordDim));
1902       PetscCall(PetscSectionSetChart(csCell, 0, numCells));
1903       for (cell = 0; cell < numCells; ++cell) {
1904         if (PetscUnlikely(PetscBTLookup(periodicCells, cell))) {
1905           GmshElement *elem = mesh->elements + cell;
1906           PetscInt     dof  = elem->numVerts * coordDim;
1907 
1908           PetscCall(PetscSectionSetDof(csCell, cell, dof));
1909           PetscCall(PetscSectionSetFieldDof(csCell, cell, 0, dof));
1910         }
1911       }
1912       PetscCall(PetscSectionSetUp(csCell));
1913       PetscCall(DMSetCellCoordinateSection(*dm, PETSC_DETERMINE, csCell));
1914     }
1915 
1916     PetscCall(DMCreateLocalVector(cdm, &coordinates));
1917     PetscCall(VecGetArray(coordinates, &pointCoords));
1918     PetscCall(PetscMalloc1(numVerts, &nodeMap));
1919     for (n = 0; n < numNodes; n++)
1920       if (mesh->vertexMap[n] >= 0) nodeMap[mesh->vertexMap[n]] = n;
1921     for (v = 0; v < numVerts; ++v) {
1922       PetscInt off, node = nodeMap[v];
1923 
1924       PetscCall(PetscSectionGetOffset(cs, numCells + v, &off));
1925       for (d = 0; d < coordDim; ++d) pointCoords[off+d] = (PetscReal) coords[node*3+d];
1926     }
1927     PetscCall(VecRestoreArray(coordinates, &pointCoords));
1928     PetscCall(PetscFree(nodeMap));
1929 
1930     if (periodic) {
1931       PetscCall(DMCreateLocalVector(cdmCell, &coordinatesCell));
1932       PetscCall(VecGetArray(coordinatesCell, &pointCoords));
1933       for (cell = 0; cell < numCells; ++cell) {
1934         if (PetscUnlikely(PetscBTLookup(periodicCells, cell))) {
1935           GmshElement *elem = mesh->elements + cell;
1936           PetscInt     off, node;
1937           for (v = 0; v < elem->numVerts; ++v) cone[v] = elem->nodes[v];
1938           PetscCall(DMPlexReorderCell(cdmCell, cell, cone));
1939           PetscCall(PetscSectionGetOffset(csCell, cell, &off));
1940           for (v = 0; v < elem->numVerts; ++v)
1941             for (node = cone[v], d = 0; d < coordDim; ++d)
1942               pointCoords[off++] = (PetscReal) coords[node*3+d];
1943         }
1944       }
1945       PetscCall(VecSetBlockSize(coordinatesCell, coordDim));
1946       PetscCall(VecRestoreArray(coordinatesCell, &pointCoords));
1947       PetscCall(DMSetCellCoordinatesLocal(*dm, coordinatesCell));
1948       PetscCall(VecDestroy(&coordinatesCell));
1949     }
1950     PetscCall(PetscSectionDestroy(&csCell));
1951     PetscCall(DMDestroy(&cdmCell));
1952   }
1953 
1954   PetscCall(PetscObjectSetName((PetscObject) coordinates, "coordinates"));
1955   PetscCall(VecSetBlockSize(coordinates, coordDim));
1956   PetscCall(DMSetCoordinatesLocal(*dm, coordinates));
1957   PetscCall(VecDestroy(&coordinates));
1958 
1959   PetscCall(GmshMeshDestroy(&mesh));
1960   PetscCall(PetscBTDestroy(&periodicVerts));
1961   PetscCall(PetscBTDestroy(&periodicCells));
1962 
1963   if (highOrder && project)  {
1964     PetscFE         fe;
1965     const char      prefix[]   = "dm_plex_gmsh_project_";
1966     PetscBool       continuity = periodic ? PETSC_FALSE : PETSC_TRUE;
1967     PetscDTNodeType nodeType   = PETSCDTNODES_GAUSSJACOBI;
1968 
1969     if (isSimplex) continuity = PETSC_FALSE; /* XXX FIXME Requires DMPlexSetClosurePermutationLexicographic() */
1970 
1971     PetscCall(GmshCreateFE(comm, prefix, isSimplex, continuity, nodeType, dim, coordDim, order, &fe));
1972     PetscCall(PetscFEViewFromOptions(fe, NULL, "-dm_plex_gmsh_project_fe_view"));
1973     PetscCall(DMProjectCoordinates(*dm, fe));
1974     PetscCall(PetscFEDestroy(&fe));
1975   }
1976 
1977   PetscCall(PetscLogEventEnd(DMPLEX_CreateGmsh,*dm,NULL,NULL,NULL));
1978   PetscFunctionReturn(0);
1979 }
1980