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