xref: /petsc/src/dm/impls/plex/plexgmsh.c (revision 70a7d78aacfbd24b2e31399a3d8e056944bb7de3)
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) {
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   PetscInt       dim = 0, coordDim = -1, order = 0;
1442   PetscInt       numNodes = 0, numElems = 0, numVerts = 0, numCells = 0;
1443   PetscInt       cell, cone[8], e, n, v, d;
1444   PetscBool      binary, usemarker = PETSC_FALSE;
1445   PetscBool      hybrid = interpolate, periodic = PETSC_TRUE;
1446   PetscBool      highOrder = PETSC_TRUE, highOrderSet, project = PETSC_FALSE;
1447   PetscBool      isSimplex = PETSC_FALSE, isHybrid = PETSC_FALSE, hasTetra = PETSC_FALSE;
1448   PetscMPIInt    rank;
1449   PetscErrorCode ierr;
1450 
1451   PetscFunctionBegin;
1452   ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr);
1453   ierr = PetscObjectOptionsBegin((PetscObject)viewer);CHKERRQ(ierr);
1454   ierr = PetscOptionsHead(PetscOptionsObject,"DMPlex Gmsh options");CHKERRQ(ierr);
1455   ierr = PetscOptionsBool("-dm_plex_gmsh_hybrid", "Generate hybrid cell bounds", "DMPlexCreateGmsh", hybrid, &hybrid, NULL);CHKERRQ(ierr);
1456   ierr = PetscOptionsBool("-dm_plex_gmsh_periodic","Read Gmsh periodic section", "DMPlexCreateGmsh", periodic, &periodic, NULL);CHKERRQ(ierr);
1457   ierr = PetscOptionsBool("-dm_plex_gmsh_highorder","Generate high-order coordinates", "DMPlexCreateGmsh", highOrder, &highOrder, &highOrderSet);CHKERRQ(ierr);
1458   ierr = PetscOptionsBool("-dm_plex_gmsh_project", "Project high-order coordinates to a different space", "DMPlexCreateGmsh", project, &project, NULL);CHKERRQ(ierr);
1459   ierr = PetscOptionsBool("-dm_plex_gmsh_use_marker", "Generate marker label", "DMPlexCreateGmsh", usemarker, &usemarker, NULL);CHKERRQ(ierr);
1460   ierr = PetscOptionsBoundedInt("-dm_plex_gmsh_spacedim", "Embedding space dimension", "DMPlexCreateGmsh", coordDim, &coordDim, NULL, PETSC_DECIDE);CHKERRQ(ierr);
1461   ierr = PetscOptionsTail();CHKERRQ(ierr);
1462   ierr = PetscOptionsEnd();CHKERRQ(ierr);
1463 
1464   ierr = GmshCellInfoSetUp();CHKERRQ(ierr);
1465 
1466   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
1467   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
1468   ierr = PetscLogEventBegin(DMPLEX_CreateGmsh,*dm,NULL,NULL,NULL);CHKERRQ(ierr);
1469 
1470   ierr = PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &binary);CHKERRQ(ierr);
1471 
1472   /* Binary viewers read on all ranks, get subviewer to read only in rank 0 */
1473   if (binary) {
1474     parentviewer = viewer;
1475     ierr = PetscViewerGetSubViewer(parentviewer, PETSC_COMM_SELF, &viewer);CHKERRQ(ierr);
1476   }
1477 
1478   if (!rank) {
1479     GmshFile  gmsh[1];
1480     char      line[PETSC_MAX_PATH_LEN];
1481     PetscBool match;
1482 
1483     ierr = PetscArrayzero(gmsh,1);CHKERRQ(ierr);
1484     gmsh->viewer = viewer;
1485     gmsh->binary = binary;
1486 
1487     ierr = GmshMeshCreate(&mesh);CHKERRQ(ierr);
1488 
1489     /* Read mesh format */
1490     ierr = GmshReadSection(gmsh, line);CHKERRQ(ierr);
1491     ierr = GmshExpect(gmsh, "$MeshFormat", line);CHKERRQ(ierr);
1492     ierr = GmshReadMeshFormat(gmsh);CHKERRQ(ierr);
1493     ierr = GmshReadEndSection(gmsh, "$EndMeshFormat", line);CHKERRQ(ierr);
1494 
1495     /* OPTIONAL Read physical names */
1496     ierr = GmshReadSection(gmsh, line);CHKERRQ(ierr);
1497     ierr = GmshMatch(gmsh, "$PhysicalNames", line, &match);CHKERRQ(ierr);
1498     if (match) {
1499       ierr = GmshExpect(gmsh, "$PhysicalNames", line);CHKERRQ(ierr);
1500       ierr = GmshReadPhysicalNames(gmsh);CHKERRQ(ierr);
1501       ierr = GmshReadEndSection(gmsh, "$EndPhysicalNames", line);CHKERRQ(ierr);
1502       /* Initial read for entity section */
1503       ierr = GmshReadSection(gmsh, line);CHKERRQ(ierr);
1504     }
1505 
1506     /* Read entities */
1507     if (gmsh->fileFormat >= 40) {
1508       ierr = GmshExpect(gmsh, "$Entities", line);CHKERRQ(ierr);
1509       ierr = GmshReadEntities(gmsh, mesh);CHKERRQ(ierr);
1510       ierr = GmshReadEndSection(gmsh, "$EndEntities", line);CHKERRQ(ierr);
1511       /* Initial read for nodes section */
1512       ierr = GmshReadSection(gmsh, line);CHKERRQ(ierr);
1513     }
1514 
1515     /* Read nodes */
1516     ierr = GmshExpect(gmsh, "$Nodes", line);CHKERRQ(ierr);
1517     ierr = GmshReadNodes(gmsh, mesh);CHKERRQ(ierr);
1518     ierr = GmshReadEndSection(gmsh, "$EndNodes", line);CHKERRQ(ierr);
1519 
1520     /* Read elements */
1521     ierr = GmshReadSection(gmsh, line);CHKERRQ(ierr);
1522     ierr = GmshExpect(gmsh, "$Elements", line);CHKERRQ(ierr);
1523     ierr = GmshReadElements(gmsh, mesh);CHKERRQ(ierr);
1524     ierr = GmshReadEndSection(gmsh, "$EndElements", line);CHKERRQ(ierr);
1525 
1526     /* Read periodic section (OPTIONAL) */
1527     if (periodic) {
1528       ierr = GmshReadSection(gmsh, line);CHKERRQ(ierr);
1529       ierr = GmshMatch(gmsh, "$Periodic", line, &periodic);CHKERRQ(ierr);
1530     }
1531     if (periodic) {
1532       ierr = GmshExpect(gmsh, "$Periodic", line);CHKERRQ(ierr);
1533       ierr = GmshReadPeriodic(gmsh, mesh);CHKERRQ(ierr);
1534       ierr = GmshReadEndSection(gmsh, "$EndPeriodic", line);CHKERRQ(ierr);
1535     }
1536 
1537     ierr = PetscFree(gmsh->wbuf);CHKERRQ(ierr);
1538     ierr = PetscFree(gmsh->sbuf);CHKERRQ(ierr);
1539     ierr = PetscFree(gmsh->nbuf);CHKERRQ(ierr);
1540 
1541     dim       = mesh->dim;
1542     order     = mesh->order;
1543     numNodes  = mesh->numNodes;
1544     numElems  = mesh->numElems;
1545     numVerts  = mesh->numVerts;
1546     numCells  = mesh->numCells;
1547 
1548     {
1549       GmshElement *elemA = mesh->numCells > 0 ? mesh->elements : NULL;
1550       GmshElement *elemB = elemA ? elemA + mesh->numCells - 1  : NULL;
1551       int ptA = elemA ? GmshCellMap[elemA->cellType].polytope : -1;
1552       int ptB = elemB ? GmshCellMap[elemB->cellType].polytope : -1;
1553       isSimplex = (ptA == GMSH_QUA || ptA == GMSH_HEX) ? PETSC_FALSE : PETSC_TRUE;
1554       isHybrid  = (ptA == ptB) ? PETSC_FALSE : PETSC_TRUE;
1555       hasTetra  = (ptA == GMSH_TET) ? PETSC_TRUE : PETSC_FALSE;
1556     }
1557   }
1558 
1559   if (parentviewer) {
1560     ierr = PetscViewerRestoreSubViewer(parentviewer, PETSC_COMM_SELF, &viewer);CHKERRQ(ierr);
1561   }
1562 
1563   {
1564     int buf[6];
1565 
1566     buf[0] = (int)dim;
1567     buf[1] = (int)order;
1568     buf[2] = periodic;
1569     buf[3] = isSimplex;
1570     buf[4] = isHybrid;
1571     buf[5] = hasTetra;
1572 
1573     ierr = MPI_Bcast(buf, 6, MPI_INT, 0, comm);CHKERRMPI(ierr);
1574 
1575     dim       = buf[0];
1576     order     = buf[1];
1577     periodic  = buf[2] ? PETSC_TRUE : PETSC_FALSE;
1578     isSimplex = buf[3] ? PETSC_TRUE : PETSC_FALSE;
1579     isHybrid  = buf[4] ? PETSC_TRUE : PETSC_FALSE;
1580     hasTetra  = buf[5] ? PETSC_TRUE : PETSC_FALSE;
1581   }
1582 
1583   if (!highOrderSet) highOrder = (order > 1) ? PETSC_TRUE : PETSC_FALSE;
1584   if (highOrder && isHybrid) SETERRQ(comm, PETSC_ERR_SUP, "No support for discretization on hybrid meshes yet");
1585 
1586   /* We do not want this label automatically computed, instead we fill it here */
1587   ierr = DMCreateLabel(*dm, "celltype");CHKERRQ(ierr);
1588 
1589   /* Allocate the cell-vertex mesh */
1590   ierr = DMPlexSetChart(*dm, 0, numCells+numVerts);CHKERRQ(ierr);
1591   for (cell = 0; cell < numCells; ++cell) {
1592     GmshElement *elem = mesh->elements + cell;
1593     DMPolytopeType ctype = DMPolytopeTypeFromGmsh(elem->cellType);
1594     if (hybrid && hasTetra && ctype == DM_POLYTOPE_TRI_PRISM) ctype = DM_POLYTOPE_TRI_PRISM_TENSOR;
1595     ierr = DMPlexSetConeSize(*dm, cell, elem->numVerts);CHKERRQ(ierr);
1596     ierr = DMPlexSetCellType(*dm, cell, ctype);CHKERRQ(ierr);
1597   }
1598   for (v = numCells; v < numCells+numVerts; ++v) {
1599     ierr = DMPlexSetCellType(*dm, v, DM_POLYTOPE_POINT);CHKERRQ(ierr);
1600   }
1601   ierr = DMSetUp(*dm);CHKERRQ(ierr);
1602 
1603   /* Add cell-vertex connections */
1604   for (cell = 0; cell < numCells; ++cell) {
1605     GmshElement *elem = mesh->elements + cell;
1606     for (v = 0; v < elem->numVerts; ++v) {
1607       const PetscInt nn = elem->nodes[v];
1608       const PetscInt vv = mesh->vertexMap[nn];
1609       cone[v] = numCells + vv;
1610     }
1611     ierr = DMPlexReorderCell(*dm, cell, cone);CHKERRQ(ierr);
1612     ierr = DMPlexSetCone(*dm, cell, cone);CHKERRQ(ierr);
1613   }
1614 
1615   ierr = DMSetDimension(*dm, dim);CHKERRQ(ierr);
1616   ierr = DMPlexSymmetrize(*dm);CHKERRQ(ierr);
1617   ierr = DMPlexStratify(*dm);CHKERRQ(ierr);
1618   if (interpolate) {
1619     DM idm;
1620 
1621     ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr);
1622     ierr = DMDestroy(dm);CHKERRQ(ierr);
1623     *dm  = idm;
1624   }
1625 
1626   if (usemarker && !interpolate && dim > 1) SETERRQ(comm,PETSC_ERR_SUP,"Cannot create marker label without interpolation");
1627   if (!rank && usemarker) {
1628     PetscInt f, fStart, fEnd;
1629 
1630     ierr = DMCreateLabel(*dm, "marker");CHKERRQ(ierr);
1631     ierr = DMPlexGetHeightStratum(*dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
1632     for (f = fStart; f < fEnd; ++f) {
1633       PetscInt suppSize;
1634 
1635       ierr = DMPlexGetSupportSize(*dm, f, &suppSize);CHKERRQ(ierr);
1636       if (suppSize == 1) {
1637         PetscInt *cone = NULL, coneSize, p;
1638 
1639         ierr = DMPlexGetTransitiveClosure(*dm, f, PETSC_TRUE, &coneSize, &cone);CHKERRQ(ierr);
1640         for (p = 0; p < coneSize; p += 2) {
1641           ierr = DMSetLabelValue(*dm, "marker", cone[p], 1);CHKERRQ(ierr);
1642         }
1643         ierr = DMPlexRestoreTransitiveClosure(*dm, f, PETSC_TRUE, &coneSize, &cone);CHKERRQ(ierr);
1644       }
1645     }
1646   }
1647 
1648   if (!rank) {
1649     PetscInt vStart, vEnd;
1650 
1651     ierr = DMPlexGetDepthStratum(*dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
1652     for (cell = 0, e = 0; e < numElems; ++e) {
1653       GmshElement *elem = mesh->elements + e;
1654 
1655       /* Create cell sets */
1656       if (elem->dim == dim && dim > 0) {
1657         if (elem->numTags > 0) {
1658           ierr = DMSetLabelValue(*dm, "Cell Sets", cell, elem->tags[0]);CHKERRQ(ierr);
1659         }
1660         cell++;
1661       }
1662 
1663       /* Create face sets */
1664       if (interpolate && elem->dim == dim-1) {
1665         PetscInt        joinSize;
1666         const PetscInt *join = NULL;
1667         /* Find the relevant facet with vertex joins */
1668         for (v = 0; v < elem->numVerts; ++v) {
1669           const PetscInt nn = elem->nodes[v];
1670           const PetscInt vv = mesh->vertexMap[nn];
1671           cone[v] = vStart + vv;
1672         }
1673         ierr = DMPlexGetFullJoin(*dm, elem->numVerts, cone, &joinSize, &join);CHKERRQ(ierr);
1674         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);
1675         ierr = DMSetLabelValue(*dm, "Face Sets", join[0], elem->tags[0]);CHKERRQ(ierr);
1676         ierr = DMPlexRestoreJoin(*dm, elem->numVerts, cone, &joinSize, &join);CHKERRQ(ierr);
1677       }
1678 
1679       /* Create vertex sets */
1680       if (elem->dim == 0) {
1681         if (elem->numTags > 0) {
1682           const PetscInt nn = elem->nodes[0];
1683           const PetscInt vv = mesh->vertexMap[nn];
1684           ierr = DMSetLabelValue(*dm, "Vertex Sets", vStart + vv, elem->tags[0]);CHKERRQ(ierr);
1685         }
1686       }
1687     }
1688   }
1689 
1690   if (periodic) {
1691     ierr = PetscBTCreate(numVerts, &periodicVerts);CHKERRQ(ierr);
1692     for (n = 0; n < numNodes; ++n) {
1693       if (mesh->vertexMap[n] >= 0) {
1694         if (PetscUnlikely(mesh->periodMap[n] != n)) {
1695           PetscInt m = mesh->periodMap[n];
1696           ierr= PetscBTSet(periodicVerts, mesh->vertexMap[n]);CHKERRQ(ierr);
1697           ierr= PetscBTSet(periodicVerts, mesh->vertexMap[m]);CHKERRQ(ierr);
1698         }
1699       }
1700     }
1701     ierr = PetscBTCreate(numCells, &periodicCells);CHKERRQ(ierr);
1702     for (cell = 0; cell < numCells; ++cell) {
1703       GmshElement *elem = mesh->elements + cell;
1704       for (v = 0; v < elem->numVerts; ++v) {
1705         PetscInt nn = elem->nodes[v];
1706         PetscInt vv = mesh->vertexMap[nn];
1707         if (PetscUnlikely(PetscBTLookup(periodicVerts, vv))) {
1708           ierr = PetscBTSet(periodicCells, cell);CHKERRQ(ierr); break;
1709         }
1710       }
1711     }
1712   }
1713 
1714   /* Setup coordinate DM */
1715   if (coordDim < 0) coordDim = dim;
1716   ierr = DMSetCoordinateDim(*dm, coordDim);CHKERRQ(ierr);
1717   ierr = DMGetCoordinateDM(*dm, &cdm);CHKERRQ(ierr);
1718   if (highOrder) {
1719     PetscFE         fe;
1720     PetscBool       continuity = periodic ? PETSC_FALSE : PETSC_TRUE;
1721     PetscDTNodeType nodeType   = PETSCDTNODES_EQUISPACED;
1722 
1723     if (isSimplex) continuity = PETSC_FALSE; /* XXX FIXME Requires DMPlexSetClosurePermutationLexicographic() */
1724 
1725     ierr = GmshCreateFE(comm, NULL, isSimplex, continuity, nodeType, dim, coordDim, order, &fe);CHKERRQ(ierr);
1726     ierr = PetscFEViewFromOptions(fe, NULL, "-dm_plex_gmsh_fe_view");CHKERRQ(ierr);
1727     ierr = DMSetField(cdm, 0, NULL, (PetscObject) fe);CHKERRQ(ierr);
1728     ierr = PetscFEDestroy(&fe);CHKERRQ(ierr);
1729     ierr = DMCreateDS(cdm);CHKERRQ(ierr);
1730   }
1731 
1732   /* Create coordinates */
1733   if (highOrder) {
1734 
1735     PetscInt     maxDof = GmshNumNodes_HEX(order)*coordDim;
1736     double       *coords = mesh ? mesh->nodelist->xyz : NULL;
1737     PetscSection section;
1738     PetscScalar  *cellCoords;
1739 
1740     ierr = DMSetLocalSection(cdm, NULL);CHKERRQ(ierr);
1741     ierr = DMGetLocalSection(cdm, &coordSection);CHKERRQ(ierr);
1742     ierr = PetscSectionClone(coordSection, &section);CHKERRQ(ierr);
1743     ierr = DMPlexSetClosurePermutationTensor(cdm, 0, section);CHKERRQ(ierr); /* XXX Implement DMPlexSetClosurePermutationLexicographic() */
1744 
1745     ierr = DMCreateLocalVector(cdm, &coordinates);CHKERRQ(ierr);
1746     ierr = PetscMalloc1(maxDof, &cellCoords);CHKERRQ(ierr);
1747     for (cell = 0; cell < numCells; ++cell) {
1748       GmshElement *elem = mesh->elements + cell;
1749       const int *lexorder = GmshCellMap[elem->cellType].lexorder();
1750       for (n = 0; n < elem->numNodes; ++n) {
1751         const PetscInt node = elem->nodes[lexorder[n]];
1752         for (d = 0; d < coordDim; ++d)
1753           cellCoords[n*coordDim+d] = (PetscReal) coords[node*3+d];
1754       }
1755       ierr = DMPlexVecSetClosure(cdm, section, coordinates, cell, cellCoords, INSERT_VALUES);CHKERRQ(ierr);
1756     }
1757     ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
1758     ierr = PetscFree(cellCoords);CHKERRQ(ierr);
1759 
1760   } else {
1761 
1762     PetscInt    *nodeMap;
1763     double      *coords = mesh ? mesh->nodelist->xyz : NULL;
1764     PetscScalar *pointCoords;
1765 
1766     ierr = DMGetLocalSection(cdm, &coordSection);CHKERRQ(ierr);
1767     ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
1768     ierr = PetscSectionSetFieldComponents(coordSection, 0, coordDim);CHKERRQ(ierr);
1769     if (periodic) { /* we need to localize coordinates on cells */
1770       ierr = PetscSectionSetChart(coordSection, 0, numCells+numVerts);CHKERRQ(ierr);
1771     } else {
1772       ierr = PetscSectionSetChart(coordSection, numCells, numCells+numVerts);CHKERRQ(ierr);
1773     }
1774     if (periodic) {
1775       for (cell = 0; cell < numCells; ++cell) {
1776         if (PetscUnlikely(PetscBTLookup(periodicCells, cell))) {
1777           GmshElement *elem = mesh->elements + cell;
1778           PetscInt dof = elem->numVerts * coordDim;
1779           ierr = PetscSectionSetDof(coordSection, cell, dof);CHKERRQ(ierr);
1780           ierr = PetscSectionSetFieldDof(coordSection, cell, 0, dof);CHKERRQ(ierr);
1781         }
1782       }
1783     }
1784     for (v = numCells; v < numCells+numVerts; ++v) {
1785       ierr = PetscSectionSetDof(coordSection, v, coordDim);CHKERRQ(ierr);
1786       ierr = PetscSectionSetFieldDof(coordSection, v, 0, coordDim);CHKERRQ(ierr);
1787     }
1788     ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
1789 
1790     ierr = DMCreateLocalVector(cdm, &coordinates);CHKERRQ(ierr);
1791     ierr = VecGetArray(coordinates, &pointCoords);CHKERRQ(ierr);
1792     if (periodic) {
1793       for (cell = 0; cell < numCells; ++cell) {
1794         if (PetscUnlikely(PetscBTLookup(periodicCells, cell))) {
1795           GmshElement *elem = mesh->elements + cell;
1796           PetscInt off, node;
1797           for (v = 0; v < elem->numVerts; ++v)
1798             cone[v] = elem->nodes[v];
1799           ierr = DMPlexReorderCell(cdm, cell, cone);CHKERRQ(ierr);
1800           ierr = PetscSectionGetOffset(coordSection, cell, &off);CHKERRQ(ierr);
1801           for (v = 0; v < elem->numVerts; ++v)
1802             for (node = cone[v], d = 0; d < coordDim; ++d)
1803               pointCoords[off++] = (PetscReal) coords[node*3+d];
1804         }
1805       }
1806     }
1807     ierr = PetscMalloc1(numVerts, &nodeMap);CHKERRQ(ierr);
1808     for (n = 0; n < numNodes; n++)
1809       if (mesh->vertexMap[n] >= 0)
1810         nodeMap[mesh->vertexMap[n]] = n;
1811     for (v = 0; v < numVerts; ++v) {
1812       PetscInt off, node = nodeMap[v];
1813       ierr = PetscSectionGetOffset(coordSection, numCells + v, &off);CHKERRQ(ierr);
1814       for (d = 0; d < coordDim; ++d)
1815         pointCoords[off+d] = (PetscReal) coords[node*3+d];
1816     }
1817     ierr = PetscFree(nodeMap);CHKERRQ(ierr);
1818     ierr = VecRestoreArray(coordinates, &pointCoords);CHKERRQ(ierr);
1819 
1820   }
1821 
1822   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
1823   ierr = VecSetBlockSize(coordinates, coordDim);CHKERRQ(ierr);
1824   ierr = DMSetCoordinatesLocal(*dm, coordinates);CHKERRQ(ierr);
1825   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
1826   ierr = DMSetPeriodicity(*dm, periodic, NULL, NULL, NULL);CHKERRQ(ierr);
1827 
1828   ierr = GmshMeshDestroy(&mesh);CHKERRQ(ierr);
1829   ierr = PetscBTDestroy(&periodicVerts);CHKERRQ(ierr);
1830   ierr = PetscBTDestroy(&periodicCells);CHKERRQ(ierr);
1831 
1832   if (highOrder && project)  {
1833     PetscFE         fe;
1834     const char      prefix[]   = "dm_plex_gmsh_project_";
1835     PetscBool       continuity = periodic ? PETSC_FALSE : PETSC_TRUE;
1836     PetscDTNodeType nodeType   = PETSCDTNODES_GAUSSJACOBI;
1837 
1838     if (isSimplex) continuity = PETSC_FALSE; /* XXX FIXME Requires DMPlexSetClosurePermutationLexicographic() */
1839 
1840     ierr = GmshCreateFE(comm, prefix, isSimplex, continuity, nodeType, dim, coordDim, order, &fe);CHKERRQ(ierr);
1841     ierr = PetscFEViewFromOptions(fe, NULL, "-dm_plex_gmsh_project_fe_view");CHKERRQ(ierr);
1842     ierr = DMProjectCoordinates(*dm, fe);CHKERRQ(ierr);
1843     ierr = PetscFEDestroy(&fe);CHKERRQ(ierr);
1844   }
1845 
1846   ierr = PetscLogEventEnd(DMPLEX_CreateGmsh,*dm,NULL,NULL,NULL);CHKERRQ(ierr);
1847   PetscFunctionReturn(0);
1848 }
1849