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