xref: /petsc/src/dm/impls/plex/plexgmsh.c (revision 2da392cc7c10228af19ad9843ce5155178acb644)
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 
188 typedef struct {
189   PetscViewer  viewer;
190   int          fileFormat;
191   int          dataSize;
192   PetscBool    binary;
193   PetscBool    byteSwap;
194   size_t       wlen;
195   void        *wbuf;
196   size_t       slen;
197   void        *sbuf;
198   PetscInt    *nbuf;
199   PetscInt     nodeStart;
200   PetscInt     nodeEnd;
201   PetscInt    *nodeMap;
202 } GmshFile;
203 
204 static PetscErrorCode GmshBufferGet(GmshFile *gmsh, size_t count, size_t eltsize, void *buf)
205 {
206   size_t         size = count * eltsize;
207   PetscErrorCode ierr;
208 
209   PetscFunctionBegin;
210   if (gmsh->wlen < size) {
211     ierr = PetscFree(gmsh->wbuf);CHKERRQ(ierr);
212     ierr = PetscMalloc(size, &gmsh->wbuf);CHKERRQ(ierr);
213     gmsh->wlen = size;
214   }
215   *(void**)buf = size ? gmsh->wbuf : NULL;
216   PetscFunctionReturn(0);
217 }
218 
219 static PetscErrorCode GmshBufferSizeGet(GmshFile *gmsh, size_t count, void *buf)
220 {
221   size_t         dataSize = (size_t)gmsh->dataSize;
222   size_t         size = count * dataSize;
223   PetscErrorCode ierr;
224 
225   PetscFunctionBegin;
226   if (gmsh->slen < size) {
227     ierr = PetscFree(gmsh->sbuf);CHKERRQ(ierr);
228     ierr = PetscMalloc(size, &gmsh->sbuf);CHKERRQ(ierr);
229     gmsh->slen = size;
230   }
231   *(void**)buf = size ? gmsh->sbuf : NULL;
232   PetscFunctionReturn(0);
233 }
234 
235 static PetscErrorCode GmshRead(GmshFile *gmsh, void *buf, PetscInt count, PetscDataType dtype)
236 {
237   PetscErrorCode ierr;
238   PetscFunctionBegin;
239   ierr = PetscViewerRead(gmsh->viewer, buf, count, NULL, dtype);CHKERRQ(ierr);
240   if (gmsh->byteSwap) {ierr = PetscByteSwap(buf, dtype, count);CHKERRQ(ierr);}
241   PetscFunctionReturn(0);
242 }
243 
244 static PetscErrorCode GmshReadString(GmshFile *gmsh, char *buf, PetscInt count)
245 {
246   PetscErrorCode ierr;
247   PetscFunctionBegin;
248   ierr = PetscViewerRead(gmsh->viewer, buf, count, NULL, PETSC_STRING);CHKERRQ(ierr);
249   PetscFunctionReturn(0);
250 }
251 
252 static PetscErrorCode GmshMatch(PETSC_UNUSED GmshFile *gmsh, const char Section[], char line[PETSC_MAX_PATH_LEN], PetscBool *match)
253 {
254   PetscErrorCode ierr;
255   PetscFunctionBegin;
256   ierr = PetscStrcmp(line, Section, match);CHKERRQ(ierr);
257   PetscFunctionReturn(0);
258 }
259 
260 static PetscErrorCode GmshExpect(GmshFile *gmsh, const char Section[], char line[PETSC_MAX_PATH_LEN])
261 {
262   PetscBool      match;
263   PetscErrorCode ierr;
264 
265   PetscFunctionBegin;
266   ierr = GmshMatch(gmsh, Section, line, &match);CHKERRQ(ierr);
267   if (!match) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file, expecting %s",Section);
268   PetscFunctionReturn(0);
269 }
270 
271 static PetscErrorCode GmshReadSection(GmshFile *gmsh, char line[PETSC_MAX_PATH_LEN])
272 {
273   PetscBool      match;
274   PetscErrorCode ierr;
275 
276   PetscFunctionBegin;
277   while (PETSC_TRUE) {
278     ierr = GmshReadString(gmsh, line, 1);CHKERRQ(ierr);
279     ierr = GmshMatch(gmsh, "$Comments", line, &match);CHKERRQ(ierr);
280     if (!match) break;
281     while (PETSC_TRUE) {
282       ierr = GmshReadString(gmsh, line, 1);CHKERRQ(ierr);
283       ierr = GmshMatch(gmsh, "$EndComments", line, &match);CHKERRQ(ierr);
284       if (match) break;
285     }
286   }
287   PetscFunctionReturn(0);
288 }
289 
290 static PetscErrorCode GmshReadEndSection(GmshFile *gmsh, const char EndSection[], char line[PETSC_MAX_PATH_LEN])
291 {
292   PetscErrorCode ierr;
293   PetscFunctionBegin;
294   ierr = GmshReadString(gmsh, line, 1);CHKERRQ(ierr);
295   ierr = GmshExpect(gmsh, EndSection, line);CHKERRQ(ierr);
296   PetscFunctionReturn(0);
297 }
298 
299 static PetscErrorCode GmshReadSize(GmshFile *gmsh, PetscInt *buf, PetscInt count)
300 {
301   PetscInt       i;
302   size_t         dataSize = (size_t)gmsh->dataSize;
303   PetscErrorCode ierr;
304 
305   PetscFunctionBegin;
306   if (dataSize == sizeof(PetscInt)) {
307     ierr = GmshRead(gmsh, buf, count, PETSC_INT);CHKERRQ(ierr);
308   } else  if (dataSize == sizeof(int)) {
309     int *ibuf = NULL;
310     ierr = GmshBufferSizeGet(gmsh, count, &ibuf);CHKERRQ(ierr);
311     ierr = GmshRead(gmsh, ibuf, count, PETSC_ENUM);CHKERRQ(ierr);
312     for (i = 0; i < count; ++i) buf[i] = (PetscInt)ibuf[i];
313   } else  if (dataSize == sizeof(long)) {
314     long *ibuf = NULL;
315     ierr = GmshBufferSizeGet(gmsh, count, &ibuf);CHKERRQ(ierr);
316     ierr = GmshRead(gmsh, ibuf, count, PETSC_LONG);CHKERRQ(ierr);
317     for (i = 0; i < count; ++i) buf[i] = (PetscInt)ibuf[i];
318   } else if (dataSize == sizeof(PetscInt64)) {
319     PetscInt64 *ibuf = NULL;
320     ierr = GmshBufferSizeGet(gmsh, count, &ibuf);CHKERRQ(ierr);
321     ierr = GmshRead(gmsh, ibuf, count, PETSC_INT64);CHKERRQ(ierr);
322     for (i = 0; i < count; ++i) buf[i] = (PetscInt)ibuf[i];
323   }
324   PetscFunctionReturn(0);
325 }
326 
327 static PetscErrorCode GmshReadInt(GmshFile *gmsh, int *buf, PetscInt count)
328 {
329   PetscErrorCode ierr;
330   PetscFunctionBegin;
331   ierr = GmshRead(gmsh, buf, count, PETSC_ENUM);CHKERRQ(ierr);
332   PetscFunctionReturn(0);
333 }
334 
335 static PetscErrorCode GmshReadDouble(GmshFile *gmsh, double *buf, PetscInt count)
336 {
337   PetscErrorCode ierr;
338   PetscFunctionBegin;
339   ierr = GmshRead(gmsh, buf, count, PETSC_DOUBLE);CHKERRQ(ierr);
340   PetscFunctionReturn(0);
341 }
342 
343 typedef struct {
344   PetscInt id;       /* Entity ID */
345   PetscInt dim;      /* Dimension */
346   double   bbox[6];  /* Bounding box */
347   PetscInt numTags;  /* Size of tag array */
348   int      tags[4];  /* Tag array */
349 } GmshEntity;
350 
351 typedef struct {
352   GmshEntity *entity[4];
353   PetscHMapI  entityMap[4];
354 } GmshEntities;
355 
356 static PetscErrorCode GmshEntitiesCreate(PetscInt count[4], GmshEntities **entities)
357 {
358   PetscInt       dim;
359   PetscErrorCode ierr;
360 
361   PetscFunctionBegin;
362   ierr = PetscNew(entities);CHKERRQ(ierr);
363   for (dim = 0; dim < 4; ++dim) {
364     ierr = PetscCalloc1(count[dim], &(*entities)->entity[dim]);CHKERRQ(ierr);
365     ierr = PetscHMapICreate(&(*entities)->entityMap[dim]);CHKERRQ(ierr);
366   }
367   PetscFunctionReturn(0);
368 }
369 
370 static PetscErrorCode GmshEntitiesDestroy(GmshEntities **entities)
371 {
372   PetscInt       dim;
373   PetscErrorCode ierr;
374 
375   PetscFunctionBegin;
376   if (!*entities) PetscFunctionReturn(0);
377   for (dim = 0; dim < 4; ++dim) {
378     ierr = PetscFree((*entities)->entity[dim]);CHKERRQ(ierr);
379     ierr = PetscHMapIDestroy(&(*entities)->entityMap[dim]);CHKERRQ(ierr);
380   }
381   ierr = PetscFree((*entities));CHKERRQ(ierr);
382   PetscFunctionReturn(0);
383 }
384 
385 static PetscErrorCode GmshEntitiesAdd(GmshEntities *entities, PetscInt index, PetscInt dim, PetscInt eid, GmshEntity** entity)
386 {
387   PetscErrorCode ierr;
388 
389   PetscFunctionBegin;
390   ierr = PetscHMapISet(entities->entityMap[dim], eid, index);CHKERRQ(ierr);
391   entities->entity[dim][index].dim = dim;
392   entities->entity[dim][index].id  = eid;
393   if (entity) *entity = &entities->entity[dim][index];
394   PetscFunctionReturn(0);
395 }
396 
397 static PetscErrorCode GmshEntitiesGet(GmshEntities *entities, PetscInt dim, PetscInt eid, GmshEntity** entity)
398 {
399   PetscInt       index;
400   PetscErrorCode ierr;
401 
402   PetscFunctionBegin;
403   ierr = PetscHMapIGet(entities->entityMap[dim], eid, &index);CHKERRQ(ierr);
404   *entity = &entities->entity[dim][index];
405   PetscFunctionReturn(0);
406 }
407 
408 typedef struct {
409   PetscInt *id;   /* Node IDs */
410   double   *xyz;  /* Coordinates */
411 } GmshNodes;
412 
413 static PetscErrorCode GmshNodesCreate(PetscInt count, GmshNodes **nodes)
414 {
415   PetscErrorCode ierr;
416 
417   PetscFunctionBegin;
418   ierr = PetscNew(nodes);CHKERRQ(ierr);
419   ierr = PetscMalloc1(count*1, &(*nodes)->id);CHKERRQ(ierr);
420   ierr = PetscMalloc1(count*3, &(*nodes)->xyz);CHKERRQ(ierr);
421   PetscFunctionReturn(0);
422 }
423 
424 static PetscErrorCode GmshNodesDestroy(GmshNodes **nodes)
425 {
426   PetscErrorCode ierr;
427   PetscFunctionBegin;
428   if (!*nodes) PetscFunctionReturn(0);
429   ierr = PetscFree((*nodes)->id);CHKERRQ(ierr);
430   ierr = PetscFree((*nodes)->xyz);CHKERRQ(ierr);
431   ierr = PetscFree((*nodes));CHKERRQ(ierr);
432   PetscFunctionReturn(0);
433 }
434 
435 typedef struct {
436   PetscInt id;       /* Element ID */
437   PetscInt dim;      /* Dimension */
438   PetscInt cellType; /* Cell type */
439   PetscInt numVerts; /* Size of vertex array */
440   PetscInt numNodes; /* Size of node array */
441   PetscInt *nodes;   /* Vertex/Node array */
442   PetscInt numTags;  /* Size of tag array */
443   int      tags[4];  /* Tag array */
444 } GmshElement;
445 
446 static PetscErrorCode GmshElementsCreate(PetscInt count, GmshElement **elements)
447 {
448   PetscErrorCode ierr;
449 
450   PetscFunctionBegin;
451   ierr = PetscCalloc1(count, elements);CHKERRQ(ierr);
452   PetscFunctionReturn(0);
453 }
454 
455 static PetscErrorCode GmshElementsDestroy(GmshElement **elements)
456 {
457   PetscErrorCode ierr;
458 
459   PetscFunctionBegin;
460   if (!*elements) PetscFunctionReturn(0);
461   ierr = PetscFree(*elements);CHKERRQ(ierr);
462   PetscFunctionReturn(0);
463 }
464 
465 typedef struct {
466   PetscInt       dim;
467   PetscInt       order;
468   GmshEntities  *entities;
469   PetscInt       numNodes;
470   GmshNodes     *nodelist;
471   PetscInt       numElems;
472   GmshElement   *elements;
473   PetscInt       numVerts;
474   PetscInt       numCells;
475   PetscInt      *periodMap;
476   PetscInt      *vertexMap;
477   PetscSegBuffer segbuf;
478 } GmshMesh;
479 
480 static PetscErrorCode GmshMeshCreate(GmshMesh **mesh)
481 {
482   PetscErrorCode ierr;
483 
484   PetscFunctionBegin;
485   ierr = PetscNew(mesh);CHKERRQ(ierr);
486   ierr = PetscSegBufferCreate(sizeof(PetscInt), 0, &(*mesh)->segbuf);CHKERRQ(ierr);
487   PetscFunctionReturn(0);
488 }
489 
490 static PetscErrorCode GmshMeshDestroy(GmshMesh **mesh)
491 {
492   PetscErrorCode ierr;
493 
494   PetscFunctionBegin;
495   if (!*mesh) PetscFunctionReturn(0);
496   ierr = GmshEntitiesDestroy(&(*mesh)->entities);CHKERRQ(ierr);
497   ierr = GmshNodesDestroy(&(*mesh)->nodelist);CHKERRQ(ierr);
498   ierr = GmshElementsDestroy(&(*mesh)->elements);CHKERRQ(ierr);
499   ierr = PetscFree((*mesh)->periodMap);CHKERRQ(ierr);
500   ierr = PetscFree((*mesh)->vertexMap);CHKERRQ(ierr);
501   ierr = PetscSegBufferDestroy(&(*mesh)->segbuf);CHKERRQ(ierr);
502   ierr = PetscFree((*mesh));CHKERRQ(ierr);
503   PetscFunctionReturn(0);
504 }
505 
506 static PetscErrorCode GmshReadNodes_v22(GmshFile *gmsh, GmshMesh *mesh)
507 {
508   PetscViewer    viewer = gmsh->viewer;
509   PetscBool      byteSwap = gmsh->byteSwap;
510   char           line[PETSC_MAX_PATH_LEN];
511   int            n, num, nid, snum;
512   GmshNodes      *nodes;
513   PetscErrorCode ierr;
514 
515   PetscFunctionBegin;
516   ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);
517   snum = sscanf(line, "%d", &num);
518   if (snum != 1) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
519   ierr = GmshNodesCreate(num, &nodes);CHKERRQ(ierr);
520   mesh->numNodes = num;
521   mesh->nodelist = nodes;
522   for (n = 0; n < num; ++n) {
523     double *xyz = nodes->xyz + n*3;
524     ierr = PetscViewerRead(viewer, &nid, 1, NULL, PETSC_ENUM);CHKERRQ(ierr);
525     ierr = PetscViewerRead(viewer, xyz, 3, NULL, PETSC_DOUBLE);CHKERRQ(ierr);
526     if (byteSwap) {ierr = PetscByteSwap(&nid, PETSC_ENUM, 1);CHKERRQ(ierr);}
527     if (byteSwap) {ierr = PetscByteSwap(xyz, PETSC_DOUBLE, 3);CHKERRQ(ierr);}
528     nodes->id[n] = nid;
529   }
530   PetscFunctionReturn(0);
531 }
532 
533 /* Gmsh elements can be of any dimension/co-dimension, so we need to traverse the
534    file contents multiple times to figure out the true number of cells and facets
535    in the given mesh. To make this more efficient we read the file contents only
536    once and store them in memory, while determining the true number of cells. */
537 static PetscErrorCode GmshReadElements_v22(GmshFile* gmsh, GmshMesh *mesh)
538 {
539   PetscViewer    viewer = gmsh->viewer;
540   PetscBool      binary = gmsh->binary;
541   PetscBool      byteSwap = gmsh->byteSwap;
542   char           line[PETSC_MAX_PATH_LEN];
543   int            i, c, p, num, ibuf[1+4+1000], snum;
544   int            cellType, numElem, numVerts, numNodes, numTags;
545   GmshElement   *elements;
546   PetscInt      *nodeMap = gmsh->nodeMap;
547   PetscErrorCode ierr;
548 
549   PetscFunctionBegin;
550   ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);
551   snum = sscanf(line, "%d", &num);
552   if (snum != 1) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
553   ierr = GmshElementsCreate(num, &elements);CHKERRQ(ierr);
554   mesh->numElems = num;
555   mesh->elements = elements;
556   for (c = 0; c < num;) {
557     ierr = PetscViewerRead(viewer, ibuf, 3, NULL, PETSC_ENUM);CHKERRQ(ierr);
558     if (byteSwap) {ierr = PetscByteSwap(ibuf, PETSC_ENUM, 3);CHKERRQ(ierr);}
559 
560     cellType = binary ? ibuf[0] : ibuf[1];
561     numElem  = binary ? ibuf[1] : 1;
562     numTags  = ibuf[2];
563 
564     ierr = GmshCellTypeCheck(cellType);CHKERRQ(ierr);
565     numVerts = GmshCellMap[cellType].numVerts;
566     numNodes = GmshCellMap[cellType].numNodes;
567 
568     for (i = 0; i < numElem; ++i, ++c) {
569       GmshElement *element = elements + c;
570       const int off = binary ? 0 : 1, nint = 1 + numTags + numNodes - off;
571       const int *id = ibuf, *nodes = ibuf + 1 + numTags, *tags = ibuf + 1;
572       ierr = PetscViewerRead(viewer, ibuf+off, nint, NULL, PETSC_ENUM);CHKERRQ(ierr);
573       if (byteSwap) {ierr = PetscByteSwap(ibuf+off, PETSC_ENUM, nint);CHKERRQ(ierr);}
574       element->id  = id[0];
575       element->dim = GmshCellMap[cellType].dim;
576       element->cellType = cellType;
577       element->numVerts = numVerts;
578       element->numNodes = numNodes;
579       element->numTags  = PetscMin(numTags, 4);
580       ierr = PetscSegBufferGet(mesh->segbuf, (size_t)element->numNodes, &element->nodes);CHKERRQ(ierr);
581       for (p = 0; p < element->numNodes; p++) element->nodes[p] = nodeMap[nodes[p]];
582       for (p = 0; p < element->numTags;  p++) element->tags[p]  = tags[p];
583     }
584   }
585   PetscFunctionReturn(0);
586 }
587 
588 /*
589 $Entities
590   numPoints(unsigned long) numCurves(unsigned long)
591     numSurfaces(unsigned long) numVolumes(unsigned long)
592   // points
593   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
594     boxMaxX(double) boxMaxY(double) boxMaxZ(double)
595     numPhysicals(unsigned long) phyisicalTag[...](int)
596   ...
597   // curves
598   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
599      boxMaxX(double) boxMaxY(double) boxMaxZ(double)
600      numPhysicals(unsigned long) physicalTag[...](int)
601      numBREPVert(unsigned long) tagBREPVert[...](int)
602   ...
603   // surfaces
604   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
605     boxMaxX(double) boxMaxY(double) boxMaxZ(double)
606     numPhysicals(unsigned long) physicalTag[...](int)
607     numBREPCurve(unsigned long) tagBREPCurve[...](int)
608   ...
609   // volumes
610   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
611     boxMaxX(double) boxMaxY(double) boxMaxZ(double)
612     numPhysicals(unsigned long) physicalTag[...](int)
613     numBREPSurfaces(unsigned long) tagBREPSurfaces[...](int)
614   ...
615 $EndEntities
616 */
617 static PetscErrorCode GmshReadEntities_v40(GmshFile *gmsh, GmshMesh *mesh)
618 {
619   PetscViewer    viewer = gmsh->viewer;
620   PetscBool      byteSwap = gmsh->byteSwap;
621   long           index, num, lbuf[4];
622   int            dim, eid, numTags, *ibuf, t;
623   PetscInt       count[4], i;
624   GmshEntity     *entity = NULL;
625   PetscErrorCode ierr;
626 
627   PetscFunctionBegin;
628   ierr = PetscViewerRead(viewer, lbuf, 4, NULL, PETSC_LONG);CHKERRQ(ierr);
629   if (byteSwap) {ierr = PetscByteSwap(lbuf, PETSC_LONG, 4);CHKERRQ(ierr);}
630   for (i = 0; i < 4; ++i) count[i] = lbuf[i];
631   ierr = GmshEntitiesCreate(count, &mesh->entities);CHKERRQ(ierr);
632   for (dim = 0; dim < 4; ++dim) {
633     for (index = 0; index < count[dim]; ++index) {
634       ierr = PetscViewerRead(viewer, &eid, 1, NULL, PETSC_ENUM);CHKERRQ(ierr);
635       if (byteSwap) {ierr = PetscByteSwap(&eid, PETSC_ENUM, 1);CHKERRQ(ierr);}
636       ierr = GmshEntitiesAdd(mesh->entities, (PetscInt)index, dim, eid, &entity);CHKERRQ(ierr);
637       ierr = PetscViewerRead(viewer, entity->bbox, 6, NULL, PETSC_DOUBLE);CHKERRQ(ierr);
638       if (byteSwap) {ierr = PetscByteSwap(entity->bbox, PETSC_DOUBLE, 6);CHKERRQ(ierr);}
639       ierr = PetscViewerRead(viewer, &num, 1, NULL, PETSC_LONG);CHKERRQ(ierr);
640       if (byteSwap) {ierr = PetscByteSwap(&num, PETSC_LONG, 1);CHKERRQ(ierr);}
641       ierr = GmshBufferGet(gmsh, num, sizeof(int), &ibuf);CHKERRQ(ierr);
642       ierr = PetscViewerRead(viewer, ibuf, num, NULL, PETSC_ENUM);CHKERRQ(ierr);
643       if (byteSwap) {ierr = PetscByteSwap(ibuf, PETSC_ENUM, num);CHKERRQ(ierr);}
644       entity->numTags = numTags = (int) PetscMin(num, 4);
645       for (t = 0; t < numTags; ++t) entity->tags[t] = ibuf[t];
646       if (dim == 0) continue;
647       ierr = PetscViewerRead(viewer, &num, 1, NULL, PETSC_LONG);CHKERRQ(ierr);
648       if (byteSwap) {ierr = PetscByteSwap(&num, PETSC_LONG, 1);CHKERRQ(ierr);}
649       ierr = GmshBufferGet(gmsh, num, sizeof(int), &ibuf);CHKERRQ(ierr);
650       ierr = PetscViewerRead(viewer, ibuf, num, NULL, PETSC_ENUM);CHKERRQ(ierr);
651       if (byteSwap) {ierr = PetscByteSwap(ibuf, PETSC_ENUM, num);CHKERRQ(ierr);}
652     }
653   }
654   PetscFunctionReturn(0);
655 }
656 
657 /*
658 $Nodes
659   numEntityBlocks(unsigned long) numNodes(unsigned long)
660   tagEntity(int) dimEntity(int) typeNode(int) numNodes(unsigned long)
661     tag(int) x(double) y(double) z(double)
662     ...
663   ...
664 $EndNodes
665 */
666 static PetscErrorCode GmshReadNodes_v40(GmshFile *gmsh, GmshMesh *mesh)
667 {
668   PetscViewer    viewer = gmsh->viewer;
669   PetscBool      byteSwap = gmsh->byteSwap;
670   long           block, node, n, numEntityBlocks, numTotalNodes, numNodes;
671   int            info[3], nid;
672   GmshNodes      *nodes;
673   PetscErrorCode ierr;
674 
675   PetscFunctionBegin;
676   ierr = PetscViewerRead(viewer, &numEntityBlocks, 1, NULL, PETSC_LONG);CHKERRQ(ierr);
677   if (byteSwap) {ierr = PetscByteSwap(&numEntityBlocks, PETSC_LONG, 1);CHKERRQ(ierr);}
678   ierr = PetscViewerRead(viewer, &numTotalNodes, 1, NULL, PETSC_LONG);CHKERRQ(ierr);
679   if (byteSwap) {ierr = PetscByteSwap(&numTotalNodes, PETSC_LONG, 1);CHKERRQ(ierr);}
680   ierr = GmshNodesCreate(numTotalNodes, &nodes);CHKERRQ(ierr);
681   mesh->numNodes = numTotalNodes;
682   mesh->nodelist = nodes;
683   for (n = 0, block = 0; block < numEntityBlocks; ++block) {
684     ierr = PetscViewerRead(viewer, info, 3, NULL, PETSC_ENUM);CHKERRQ(ierr);
685     ierr = PetscViewerRead(viewer, &numNodes, 1, NULL, PETSC_LONG);CHKERRQ(ierr);
686     if (byteSwap) {ierr = PetscByteSwap(&numNodes, PETSC_LONG, 1);CHKERRQ(ierr);}
687     if (gmsh->binary) {
688       size_t nbytes = sizeof(int) + 3*sizeof(double);
689       char   *cbuf = NULL; /* dummy value to prevent warning from compiler about possible unitilized value */
690       ierr = GmshBufferGet(gmsh, numNodes, nbytes, &cbuf);CHKERRQ(ierr);
691       ierr = PetscViewerRead(viewer, cbuf, numNodes*nbytes, NULL, PETSC_CHAR);CHKERRQ(ierr);
692       for (node = 0; node < numNodes; ++node, ++n) {
693         char   *cnid = cbuf + node*nbytes, *cxyz = cnid + sizeof(int);
694         double *xyz = nodes->xyz + n*3;
695         if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(cnid, PETSC_ENUM, 1);CHKERRQ(ierr);}
696         if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(cxyz, PETSC_DOUBLE, 3);CHKERRQ(ierr);}
697         ierr = PetscMemcpy(&nid, cnid, sizeof(int));CHKERRQ(ierr);
698         ierr = PetscMemcpy(xyz, cxyz, 3*sizeof(double));CHKERRQ(ierr);
699         if (byteSwap) {ierr = PetscByteSwap(&nid, PETSC_ENUM, 1);CHKERRQ(ierr);}
700         if (byteSwap) {ierr = PetscByteSwap(xyz, PETSC_DOUBLE, 3);CHKERRQ(ierr);}
701         nodes->id[n] = nid;
702       }
703     } else {
704       for (node = 0; node < numNodes; ++node, ++n) {
705         double *xyz = nodes->xyz + n*3;
706         ierr = PetscViewerRead(viewer, &nid, 1, NULL, PETSC_ENUM);CHKERRQ(ierr);
707         ierr = PetscViewerRead(viewer, xyz, 3, NULL, PETSC_DOUBLE);CHKERRQ(ierr);
708         if (byteSwap) {ierr = PetscByteSwap(&nid, PETSC_ENUM, 1);CHKERRQ(ierr);}
709         if (byteSwap) {ierr = PetscByteSwap(xyz, PETSC_DOUBLE, 3);CHKERRQ(ierr);}
710         nodes->id[n] = nid;
711       }
712     }
713   }
714   PetscFunctionReturn(0);
715 }
716 
717 /*
718 $Elements
719   numEntityBlocks(unsigned long) numElements(unsigned long)
720   tagEntity(int) dimEntity(int) typeEle(int) numElements(unsigned long)
721     tag(int) numVert[...](int)
722     ...
723   ...
724 $EndElements
725 */
726 static PetscErrorCode GmshReadElements_v40(GmshFile *gmsh, GmshMesh *mesh)
727 {
728   PetscViewer    viewer = gmsh->viewer;
729   PetscBool      byteSwap = gmsh->byteSwap;
730   long           c, block, numEntityBlocks, numTotalElements, elem, numElements;
731   int            p, info[3], *ibuf = NULL;
732   int            eid, dim, cellType, numVerts, numNodes, numTags;
733   GmshEntity     *entity = NULL;
734   GmshElement    *elements;
735   PetscInt       *nodeMap = gmsh->nodeMap;
736   PetscErrorCode ierr;
737 
738   PetscFunctionBegin;
739   ierr = PetscViewerRead(viewer, &numEntityBlocks, 1, NULL, PETSC_LONG);CHKERRQ(ierr);
740   if (byteSwap) {ierr = PetscByteSwap(&numEntityBlocks, PETSC_LONG, 1);CHKERRQ(ierr);}
741   ierr = PetscViewerRead(viewer, &numTotalElements, 1, NULL, PETSC_LONG);CHKERRQ(ierr);
742   if (byteSwap) {ierr = PetscByteSwap(&numTotalElements, PETSC_LONG, 1);CHKERRQ(ierr);}
743   ierr = GmshElementsCreate(numTotalElements, &elements);CHKERRQ(ierr);
744   mesh->numElems = numTotalElements;
745   mesh->elements = elements;
746   for (c = 0, block = 0; block < numEntityBlocks; ++block) {
747     ierr = PetscViewerRead(viewer, info, 3, NULL, PETSC_ENUM);CHKERRQ(ierr);
748     if (byteSwap) {ierr = PetscByteSwap(info, PETSC_ENUM, 3);CHKERRQ(ierr);}
749     eid = info[0]; dim = info[1]; cellType = info[2];
750     ierr = GmshEntitiesGet(mesh->entities, dim, eid, &entity);CHKERRQ(ierr);
751     ierr = GmshCellTypeCheck(cellType);CHKERRQ(ierr);
752     numVerts = GmshCellMap[cellType].numVerts;
753     numNodes = GmshCellMap[cellType].numNodes;
754     numTags  = entity->numTags;
755     ierr = PetscViewerRead(viewer, &numElements, 1, NULL, PETSC_LONG);CHKERRQ(ierr);
756     if (byteSwap) {ierr = PetscByteSwap(&numElements, PETSC_LONG, 1);CHKERRQ(ierr);}
757     ierr = GmshBufferGet(gmsh, (1+numNodes)*numElements, sizeof(int), &ibuf);CHKERRQ(ierr);
758     ierr = PetscViewerRead(viewer, ibuf, (1+numNodes)*numElements, NULL, PETSC_ENUM);CHKERRQ(ierr);
759     if (byteSwap) {ierr = PetscByteSwap(ibuf, PETSC_ENUM, (1+numNodes)*numElements);CHKERRQ(ierr);}
760     for (elem = 0; elem < numElements; ++elem, ++c) {
761       GmshElement *element = elements + c;
762       const int *id = ibuf + elem*(1+numNodes), *nodes = id + 1;
763       element->id  = id[0];
764       element->dim = dim;
765       element->cellType = cellType;
766       element->numVerts = numVerts;
767       element->numNodes = numNodes;
768       element->numTags  = numTags;
769       ierr = PetscSegBufferGet(mesh->segbuf, (size_t)element->numNodes, &element->nodes);CHKERRQ(ierr);
770       for (p = 0; p < element->numNodes; p++) element->nodes[p] = nodeMap[nodes[p]];
771       for (p = 0; p < element->numTags;  p++) element->tags[p]  = entity->tags[p];
772     }
773   }
774   PetscFunctionReturn(0);
775 }
776 
777 static PetscErrorCode GmshReadPeriodic_v40(GmshFile *gmsh, PetscInt periodicMap[])
778 {
779   PetscViewer    viewer = gmsh->viewer;
780   int            fileFormat = gmsh->fileFormat;
781   PetscBool      binary = gmsh->binary;
782   PetscBool      byteSwap = gmsh->byteSwap;
783   int            numPeriodic, snum, i;
784   char           line[PETSC_MAX_PATH_LEN];
785   PetscInt       *nodeMap = gmsh->nodeMap;
786   PetscErrorCode ierr;
787 
788   PetscFunctionBegin;
789   if (fileFormat == 22 || !binary) {
790     ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);
791     snum = sscanf(line, "%d", &numPeriodic);
792     if (snum != 1) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
793   } else {
794     ierr = PetscViewerRead(viewer, &numPeriodic, 1, NULL, PETSC_ENUM);CHKERRQ(ierr);
795     if (byteSwap) {ierr = PetscByteSwap(&numPeriodic, PETSC_ENUM, 1);CHKERRQ(ierr);}
796   }
797   for (i = 0; i < numPeriodic; i++) {
798     int    ibuf[3], slaveDim = -1, slaveTag = -1, masterTag = -1, slaveNode, masterNode;
799     long   j, nNodes;
800     double affine[16];
801 
802     if (fileFormat == 22 || !binary) {
803       ierr = PetscViewerRead(viewer, line, 3, NULL, PETSC_STRING);CHKERRQ(ierr);
804       snum = sscanf(line, "%d %d %d", &slaveDim, &slaveTag, &masterTag);
805       if (snum != 3) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
806     } else {
807       ierr = PetscViewerRead(viewer, ibuf, 3, NULL, PETSC_ENUM);CHKERRQ(ierr);
808       if (byteSwap) {ierr = PetscByteSwap(ibuf, PETSC_ENUM, 3);CHKERRQ(ierr);}
809       slaveDim = ibuf[0]; slaveTag = ibuf[1]; masterTag = ibuf[2];
810     }
811     (void)slaveDim; (void)slaveTag; (void)masterTag; /* unused */
812 
813     if (fileFormat == 22 || !binary) {
814       ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);
815       snum = sscanf(line, "%ld", &nNodes);
816       if (snum != 1) { /* discard transformation and try again */
817         ierr = PetscViewerRead(viewer, line, -PETSC_MAX_PATH_LEN, NULL, PETSC_STRING);CHKERRQ(ierr);
818         ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);
819         snum = sscanf(line, "%ld", &nNodes);
820         if (snum != 1) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
821       }
822     } else {
823       ierr = PetscViewerRead(viewer, &nNodes, 1, NULL, PETSC_LONG);CHKERRQ(ierr);
824       if (byteSwap) {ierr = PetscByteSwap(&nNodes, PETSC_LONG, 1);CHKERRQ(ierr);}
825       if (nNodes == -1) { /* discard transformation and try again */
826         ierr = PetscViewerRead(viewer, affine, 16, NULL, PETSC_DOUBLE);CHKERRQ(ierr);
827         ierr = PetscViewerRead(viewer, &nNodes, 1, NULL, PETSC_LONG);CHKERRQ(ierr);
828         if (byteSwap) {ierr = PetscByteSwap(&nNodes, PETSC_LONG, 1);CHKERRQ(ierr);}
829       }
830     }
831 
832     for (j = 0; j < nNodes; j++) {
833       if (fileFormat == 22 || !binary) {
834         ierr = PetscViewerRead(viewer, line, 2, NULL, PETSC_STRING);CHKERRQ(ierr);
835         snum = sscanf(line, "%d %d", &slaveNode, &masterNode);
836         if (snum != 2) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
837       } else {
838         ierr = PetscViewerRead(viewer, ibuf, 2, NULL, PETSC_ENUM);CHKERRQ(ierr);
839         if (byteSwap) {ierr = PetscByteSwap(ibuf, PETSC_ENUM, 2);CHKERRQ(ierr);}
840         slaveNode = ibuf[0]; masterNode = ibuf[1];
841       }
842       slaveNode  = (int) nodeMap[slaveNode];
843       masterNode = (int) nodeMap[masterNode];
844       periodicMap[slaveNode] = masterNode;
845     }
846   }
847   PetscFunctionReturn(0);
848 }
849 
850 /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
851 $Entities
852   numPoints(size_t) numCurves(size_t)
853     numSurfaces(size_t) numVolumes(size_t)
854   pointTag(int) X(double) Y(double) Z(double)
855     numPhysicalTags(size_t) physicalTag(int) ...
856   ...
857   curveTag(int) minX(double) minY(double) minZ(double)
858     maxX(double) maxY(double) maxZ(double)
859     numPhysicalTags(size_t) physicalTag(int) ...
860     numBoundingPoints(size_t) pointTag(int) ...
861   ...
862   surfaceTag(int) minX(double) minY(double) minZ(double)
863     maxX(double) maxY(double) maxZ(double)
864     numPhysicalTags(size_t) physicalTag(int) ...
865     numBoundingCurves(size_t) curveTag(int) ...
866   ...
867   volumeTag(int) minX(double) minY(double) minZ(double)
868     maxX(double) maxY(double) maxZ(double)
869     numPhysicalTags(size_t) physicalTag(int) ...
870     numBoundngSurfaces(size_t) surfaceTag(int) ...
871   ...
872 $EndEntities
873 */
874 static PetscErrorCode GmshReadEntities_v41(GmshFile *gmsh, GmshMesh *mesh)
875 {
876   PetscInt       count[4], index, numTags, i;
877   int            dim, eid, *tags = NULL;
878   GmshEntity     *entity = NULL;
879   PetscErrorCode ierr;
880 
881   PetscFunctionBegin;
882   ierr = GmshReadSize(gmsh, count, 4);CHKERRQ(ierr);
883   ierr = GmshEntitiesCreate(count, &mesh->entities);CHKERRQ(ierr);
884   for (dim = 0; dim < 4; ++dim) {
885     for (index = 0; index < count[dim]; ++index) {
886       ierr = GmshReadInt(gmsh, &eid, 1);CHKERRQ(ierr);
887       ierr = GmshEntitiesAdd(mesh->entities, (PetscInt)index, dim, eid, &entity);CHKERRQ(ierr);
888       ierr = GmshReadDouble(gmsh, entity->bbox, (dim == 0) ? 3 : 6);CHKERRQ(ierr);
889       ierr = GmshReadSize(gmsh, &numTags, 1);CHKERRQ(ierr);
890       ierr = GmshBufferGet(gmsh, numTags, sizeof(int), &tags);CHKERRQ(ierr);
891       ierr = GmshReadInt(gmsh, tags, numTags);CHKERRQ(ierr);
892       entity->numTags = PetscMin(numTags, 4);
893       for (i = 0; i < entity->numTags; ++i) entity->tags[i] = tags[i];
894       if (dim == 0) continue;
895       ierr = GmshReadSize(gmsh, &numTags, 1);CHKERRQ(ierr);
896       ierr = GmshBufferGet(gmsh, numTags, sizeof(int), &tags);CHKERRQ(ierr);
897       ierr = GmshReadInt(gmsh, tags, numTags);CHKERRQ(ierr);
898     }
899   }
900   PetscFunctionReturn(0);
901 }
902 
903 /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
904 $Nodes
905   numEntityBlocks(size_t) numNodes(size_t)
906     minNodeTag(size_t) maxNodeTag(size_t)
907   entityDim(int) entityTag(int) parametric(int; 0 or 1) numNodesBlock(size_t)
908     nodeTag(size_t)
909     ...
910     x(double) y(double) z(double)
911        < u(double; if parametric and entityDim = 1 or entityDim = 2) >
912        < v(double; if parametric and entityDim = 2) >
913     ...
914   ...
915 $EndNodes
916 */
917 static PetscErrorCode GmshReadNodes_v41(GmshFile *gmsh, GmshMesh *mesh)
918 {
919   int            info[3];
920   PetscInt       sizes[4], numEntityBlocks, numNodes, numNodesBlock = 0, block, node;
921   GmshNodes      *nodes;
922   PetscErrorCode ierr;
923 
924   PetscFunctionBegin;
925   ierr = GmshReadSize(gmsh, sizes, 4);CHKERRQ(ierr);
926   numEntityBlocks = sizes[0]; numNodes = sizes[1];
927   ierr = GmshNodesCreate(numNodes, &nodes);CHKERRQ(ierr);
928   mesh->numNodes = numNodes;
929   mesh->nodelist = nodes;
930   for (block = 0, node = 0; block < numEntityBlocks; ++block, node += numNodesBlock) {
931     ierr = GmshReadInt(gmsh, info, 3);CHKERRQ(ierr);
932     if (info[2] != 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Parametric coordinates not supported");
933     ierr = GmshReadSize(gmsh, &numNodesBlock, 1);CHKERRQ(ierr);
934     ierr = GmshReadSize(gmsh, nodes->id+node, numNodesBlock);CHKERRQ(ierr);
935     ierr = GmshReadDouble(gmsh, nodes->xyz+node*3, numNodesBlock*3);CHKERRQ(ierr);
936   }
937   gmsh->nodeStart = sizes[2];
938   gmsh->nodeEnd   = sizes[3]+1;
939   PetscFunctionReturn(0);
940 }
941 
942 /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
943 $Elements
944   numEntityBlocks(size_t) numElements(size_t)
945     minElementTag(size_t) maxElementTag(size_t)
946   entityDim(int) entityTag(int) elementType(int; see below) numElementsBlock(size_t)
947     elementTag(size_t) nodeTag(size_t) ...
948     ...
949   ...
950 $EndElements
951 */
952 static PetscErrorCode GmshReadElements_v41(GmshFile *gmsh, GmshMesh *mesh)
953 {
954   int            info[3], eid, dim, cellType;
955   PetscInt       sizes[4], *ibuf = NULL, numEntityBlocks, numElements, numBlockElements, numVerts, numNodes, numTags, block, elem, c, p;
956   GmshEntity     *entity = NULL;
957   GmshElement    *elements;
958   PetscInt       *nodeMap = gmsh->nodeMap;
959   PetscErrorCode ierr;
960 
961   PetscFunctionBegin;
962   ierr = GmshReadSize(gmsh, sizes, 4);CHKERRQ(ierr);
963   numEntityBlocks = sizes[0]; numElements = sizes[1];
964   ierr = GmshElementsCreate(numElements, &elements);CHKERRQ(ierr);
965   mesh->numElems = numElements;
966   mesh->elements = elements;
967   for (c = 0, block = 0; block < numEntityBlocks; ++block) {
968     ierr = GmshReadInt(gmsh, info, 3);CHKERRQ(ierr);
969     dim = info[0]; eid = info[1]; cellType = info[2];
970     ierr = GmshEntitiesGet(mesh->entities, dim, eid, &entity);CHKERRQ(ierr);
971     ierr = GmshCellTypeCheck(cellType);CHKERRQ(ierr);
972     numVerts = GmshCellMap[cellType].numVerts;
973     numNodes = GmshCellMap[cellType].numNodes;
974     numTags  = entity->numTags;
975     ierr = GmshReadSize(gmsh, &numBlockElements, 1);CHKERRQ(ierr);
976     ierr = GmshBufferGet(gmsh, (1+numNodes)*numBlockElements, sizeof(PetscInt), &ibuf);CHKERRQ(ierr);
977     ierr = GmshReadSize(gmsh, ibuf, (1+numNodes)*numBlockElements);CHKERRQ(ierr);
978     for (elem = 0; elem < numBlockElements; ++elem, ++c) {
979       GmshElement *element = elements + c;
980       const PetscInt *id = ibuf + elem*(1+numNodes), *nodes = id + 1;
981       element->id  = id[0];
982       element->dim = dim;
983       element->cellType = cellType;
984       element->numVerts = numVerts;
985       element->numNodes = numNodes;
986       element->numTags  = numTags;
987       ierr = PetscSegBufferGet(mesh->segbuf, (size_t)element->numNodes, &element->nodes);CHKERRQ(ierr);
988       for (p = 0; p < element->numNodes; p++) element->nodes[p] = nodeMap[nodes[p]];
989       for (p = 0; p < element->numTags;  p++) element->tags[p]  = entity->tags[p];
990     }
991   }
992   PetscFunctionReturn(0);
993 }
994 
995 /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
996 $Periodic
997   numPeriodicLinks(size_t)
998   entityDim(int) entityTag(int) entityTagMaster(int)
999   numAffine(size_t) value(double) ...
1000   numCorrespondingNodes(size_t)
1001     nodeTag(size_t) nodeTagMaster(size_t)
1002     ...
1003   ...
1004 $EndPeriodic
1005 */
1006 static PetscErrorCode GmshReadPeriodic_v41(GmshFile *gmsh, PetscInt periodicMap[])
1007 {
1008   int            info[3];
1009   double         dbuf[16];
1010   PetscInt       numPeriodicLinks, numAffine, numCorrespondingNodes, *nodeTags = NULL, link, node;
1011   PetscInt       *nodeMap = gmsh->nodeMap;
1012   PetscErrorCode ierr;
1013 
1014   PetscFunctionBegin;
1015   ierr = GmshReadSize(gmsh, &numPeriodicLinks, 1);CHKERRQ(ierr);
1016   for (link = 0; link < numPeriodicLinks; ++link) {
1017     ierr = GmshReadInt(gmsh, info, 3);CHKERRQ(ierr);
1018     ierr = GmshReadSize(gmsh, &numAffine, 1);CHKERRQ(ierr);
1019     ierr = GmshReadDouble(gmsh, dbuf, numAffine);CHKERRQ(ierr);
1020     ierr = GmshReadSize(gmsh, &numCorrespondingNodes, 1);CHKERRQ(ierr);
1021     ierr = GmshBufferGet(gmsh, numCorrespondingNodes, sizeof(PetscInt), &nodeTags);CHKERRQ(ierr);
1022     ierr = GmshReadSize(gmsh, nodeTags, numCorrespondingNodes*2);CHKERRQ(ierr);
1023     for (node = 0; node < numCorrespondingNodes; ++node) {
1024       PetscInt slaveNode  = nodeMap[nodeTags[node*2+0]];
1025       PetscInt masterNode = nodeMap[nodeTags[node*2+1]];
1026       periodicMap[slaveNode] = masterNode;
1027     }
1028   }
1029   PetscFunctionReturn(0);
1030 }
1031 
1032 /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
1033 $MeshFormat // same as MSH version 2
1034   version(ASCII double; currently 4.1)
1035   file-type(ASCII int; 0 for ASCII mode, 1 for binary mode)
1036   data-size(ASCII int; sizeof(size_t))
1037   < int with value one; only in binary mode, to detect endianness >
1038 $EndMeshFormat
1039 */
1040 static PetscErrorCode GmshReadMeshFormat(GmshFile *gmsh)
1041 {
1042   char           line[PETSC_MAX_PATH_LEN];
1043   int            snum, fileType, fileFormat, dataSize, checkEndian;
1044   float          version;
1045   PetscErrorCode ierr;
1046 
1047   PetscFunctionBegin;
1048   ierr = GmshReadString(gmsh, line, 3);CHKERRQ(ierr);
1049   snum = sscanf(line, "%f %d %d", &version, &fileType, &dataSize);
1050   if (snum != 3) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to parse Gmsh file header: %s", line);
1051   if (version < 2.2) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at least 2.2", (double)version);
1052   if ((int)version == 3) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f not supported", (double)version);
1053   if (version > 4.1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at most 4.1", (double)version);
1054   if (gmsh->binary && !fileType) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Viewer is binary but Gmsh file is ASCII");
1055   if (!gmsh->binary && fileType) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Viewer is ASCII but Gmsh file is binary");
1056   fileFormat = (int)(version*10); /* XXX Should use (int)roundf(version*10) ? */
1057   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);
1058   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);
1059   gmsh->fileFormat = fileFormat;
1060   gmsh->dataSize = dataSize;
1061   gmsh->byteSwap = PETSC_FALSE;
1062   if (gmsh->binary) {
1063     ierr = GmshReadInt(gmsh, &checkEndian, 1);CHKERRQ(ierr);
1064     if (checkEndian != 1) {
1065       ierr = PetscByteSwap(&checkEndian, PETSC_ENUM, 1);CHKERRQ(ierr);
1066       if (checkEndian != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to detect endianness in Gmsh file header: %s", line);
1067       gmsh->byteSwap = PETSC_TRUE;
1068     }
1069   }
1070   PetscFunctionReturn(0);
1071 }
1072 
1073 /*
1074 PhysicalNames
1075   numPhysicalNames(ASCII int)
1076   dimension(ASCII int) physicalTag(ASCII int) "name"(127 characters max)
1077   ...
1078 $EndPhysicalNames
1079 */
1080 static PetscErrorCode GmshReadPhysicalNames(GmshFile *gmsh)
1081 {
1082   char           line[PETSC_MAX_PATH_LEN], name[128+2], *p, *q;
1083   int            snum, numRegions, region, dim, tag;
1084   PetscErrorCode ierr;
1085 
1086   PetscFunctionBegin;
1087   ierr = GmshReadString(gmsh, line, 1);CHKERRQ(ierr);
1088   snum = sscanf(line, "%d", &numRegions);
1089   if (snum != 1) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
1090   for (region = 0; region < numRegions; ++region) {
1091     ierr = GmshReadString(gmsh, line, 2);CHKERRQ(ierr);
1092     snum = sscanf(line, "%d %d", &dim, &tag);
1093     if (snum != 2) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
1094     ierr = GmshReadString(gmsh, line, -(PetscInt)sizeof(line));CHKERRQ(ierr);
1095     ierr = PetscStrchr(line, '"', &p);CHKERRQ(ierr);
1096     if (!p) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
1097     ierr = PetscStrrchr(line, '"', &q);CHKERRQ(ierr);
1098     if (q == p) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
1099     ierr = PetscStrncpy(name, p+1, (size_t)(q-p-1));CHKERRQ(ierr);
1100   }
1101   PetscFunctionReturn(0);
1102 }
1103 
1104 static PetscErrorCode GmshReadEntities(GmshFile *gmsh, GmshMesh *mesh)
1105 {
1106   PetscErrorCode ierr;
1107 
1108   PetscFunctionBegin;
1109   switch (gmsh->fileFormat) {
1110   case 41: ierr = GmshReadEntities_v41(gmsh, mesh);CHKERRQ(ierr); break;
1111   default: ierr = GmshReadEntities_v40(gmsh, mesh);CHKERRQ(ierr); break;
1112   }
1113   PetscFunctionReturn(0);
1114 }
1115 
1116 static PetscErrorCode GmshReadNodes(GmshFile *gmsh, GmshMesh *mesh)
1117 {
1118   PetscErrorCode ierr;
1119 
1120   PetscFunctionBegin;
1121   switch (gmsh->fileFormat) {
1122   case 41: ierr = GmshReadNodes_v41(gmsh, mesh);CHKERRQ(ierr); break;
1123   case 40: ierr = GmshReadNodes_v40(gmsh, mesh);CHKERRQ(ierr); break;
1124   default: ierr = GmshReadNodes_v22(gmsh, mesh);CHKERRQ(ierr); break;
1125   }
1126 
1127   { /* Gmsh v2.2/v4.0 does not provide min/max node tags */
1128     if (mesh->numNodes > 0 && gmsh->nodeEnd >= gmsh->nodeStart) {
1129       PetscInt  tagMin = PETSC_MAX_INT, tagMax = PETSC_MIN_INT, n;
1130       GmshNodes *nodes = mesh->nodelist;
1131       for (n = 0; n < mesh->numNodes; ++n) {
1132         const PetscInt tag = nodes->id[n];
1133         tagMin = PetscMin(tag, tagMin);
1134         tagMax = PetscMax(tag, tagMax);
1135       }
1136       gmsh->nodeStart = tagMin;
1137       gmsh->nodeEnd   = tagMax+1;
1138     }
1139   }
1140 
1141   { /* Support for sparse node tags */
1142     PetscInt  n, t;
1143     GmshNodes *nodes = mesh->nodelist;
1144     ierr = PetscMalloc1(gmsh->nodeEnd - gmsh->nodeStart, &gmsh->nbuf);CHKERRQ(ierr);
1145     for (t = 0; t < gmsh->nodeEnd - gmsh->nodeStart; ++t) gmsh->nbuf[t] = PETSC_MIN_INT;
1146     gmsh->nodeMap = gmsh->nbuf - gmsh->nodeStart;
1147     for (n = 0; n < mesh->numNodes; ++n) {
1148       const PetscInt tag = nodes->id[n];
1149       if (gmsh->nodeMap[tag] >= 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Repeated node tag %D", tag);
1150       gmsh->nodeMap[tag] = n;
1151     }
1152   }
1153   PetscFunctionReturn(0);
1154 }
1155 
1156 static PetscErrorCode GmshReadElements(GmshFile *gmsh, GmshMesh *mesh)
1157 {
1158   PetscErrorCode ierr;
1159 
1160   PetscFunctionBegin;
1161   switch (gmsh->fileFormat) {
1162   case 41: ierr = GmshReadElements_v41(gmsh, mesh);CHKERRQ(ierr); break;
1163   case 40: ierr = GmshReadElements_v40(gmsh, mesh);CHKERRQ(ierr); break;
1164   default: ierr = GmshReadElements_v22(gmsh, mesh);CHKERRQ(ierr); break;
1165   }
1166 
1167   { /* Reorder elements by codimension and polytope type */
1168     PetscInt    ne = mesh->numElems;
1169     GmshElement *elements = mesh->elements;
1170     PetscInt    keymap[GMSH_NUM_POLYTOPES], nk = 0;
1171     PetscInt    offset[GMSH_NUM_POLYTOPES+1], e, k;
1172 
1173     for (k = 0; k < GMSH_NUM_POLYTOPES; ++k) keymap[k] = PETSC_MIN_INT;
1174     ierr = PetscMemzero(offset,sizeof(offset));CHKERRQ(ierr);
1175 
1176     keymap[GMSH_TET] = nk++;
1177     keymap[GMSH_HEX] = nk++;
1178     keymap[GMSH_PRI] = nk++;
1179     keymap[GMSH_PYR] = nk++;
1180     keymap[GMSH_TRI] = nk++;
1181     keymap[GMSH_QUA] = nk++;
1182     keymap[GMSH_SEG] = nk++;
1183     keymap[GMSH_VTX] = nk++;
1184 
1185     ierr = GmshElementsCreate(mesh->numElems, &mesh->elements);CHKERRQ(ierr);
1186 #define key(eid) keymap[GmshCellMap[elements[(eid)].cellType].polytope]
1187     for (e = 0; e < ne; ++e) offset[1+key(e)]++;
1188     for (k = 1; k < nk; ++k) offset[k] += offset[k-1];
1189     for (e = 0; e < ne; ++e) mesh->elements[offset[key(e)]++] = elements[e];
1190 #undef key
1191     ierr = GmshElementsDestroy(&elements);CHKERRQ(ierr);
1192   }
1193 
1194   { /* Mesh dimension and order */
1195     GmshElement *elem = mesh->numElems ? mesh->elements : NULL;
1196     mesh->dim   = elem ? GmshCellMap[elem->cellType].dim   : 0;
1197     mesh->order = elem ? GmshCellMap[elem->cellType].order : 0;
1198   }
1199 
1200   {
1201     PetscBT  vtx;
1202     PetscInt dim = mesh->dim, e, n, v;
1203 
1204     ierr = PetscBTCreate(mesh->numNodes, &vtx);CHKERRQ(ierr);
1205 
1206     /* Compute number of cells and set of vertices */
1207     mesh->numCells = 0;
1208     for (e = 0; e < mesh->numElems; ++e) {
1209       GmshElement *elem = mesh->elements + e;
1210       if (elem->dim == dim && dim > 0) mesh->numCells++;
1211       for (v = 0; v < elem->numVerts; v++) {
1212         ierr = PetscBTSet(vtx, elem->nodes[v]);CHKERRQ(ierr);
1213       }
1214     }
1215 
1216     /* Compute numbering for vertices */
1217     mesh->numVerts = 0;
1218     ierr = PetscMalloc1(mesh->numNodes, &mesh->vertexMap);CHKERRQ(ierr);
1219     for (n = 0; n < mesh->numNodes; ++n)
1220       mesh->vertexMap[n] = PetscBTLookup(vtx, n) ? mesh->numVerts++ : PETSC_MIN_INT;
1221 
1222     ierr = PetscBTDestroy(&vtx);CHKERRQ(ierr);
1223   }
1224   PetscFunctionReturn(0);
1225 }
1226 
1227 static PetscErrorCode GmshReadPeriodic(GmshFile *gmsh, GmshMesh *mesh)
1228 {
1229   PetscInt       n;
1230   PetscErrorCode ierr;
1231 
1232   PetscFunctionBegin;
1233   ierr = PetscMalloc1(mesh->numNodes, &mesh->periodMap);CHKERRQ(ierr);
1234   for (n = 0; n < mesh->numNodes; ++n) mesh->periodMap[n] = n;
1235   switch (gmsh->fileFormat) {
1236   case 41: ierr = GmshReadPeriodic_v41(gmsh, mesh->periodMap);CHKERRQ(ierr); break;
1237   default: ierr = GmshReadPeriodic_v40(gmsh, mesh->periodMap);CHKERRQ(ierr); break;
1238   }
1239 
1240   /* Find canonical master nodes */
1241   for (n = 0; n < mesh->numNodes; ++n)
1242     while (mesh->periodMap[n] != mesh->periodMap[mesh->periodMap[n]])
1243       mesh->periodMap[n] = mesh->periodMap[mesh->periodMap[n]];
1244 
1245   /* Renumber vertices (filter out slaves) */
1246   mesh->numVerts = 0;
1247   for (n = 0; n < mesh->numNodes; ++n)
1248     if (mesh->vertexMap[n] >= 0)   /* is vertex */
1249       if (mesh->periodMap[n] == n) /* is master */
1250         mesh->vertexMap[n] = mesh->numVerts++;
1251   for (n = 0; n < mesh->numNodes; ++n)
1252     if (mesh->vertexMap[n] >= 0)   /* is vertex */
1253       if (mesh->periodMap[n] != n) /* is slave  */
1254         mesh->vertexMap[n] = mesh->vertexMap[mesh->periodMap[n]];
1255   PetscFunctionReturn(0);
1256 }
1257 
1258 #define DM_POLYTOPE_VERTEX  DM_POLYTOPE_POINT
1259 #define DM_POLYTOPE_PYRAMID DM_POLYTOPE_UNKNOWN
1260 static const DMPolytopeType DMPolytopeMap[] = {
1261   /* GMSH_VTX */ DM_POLYTOPE_VERTEX,
1262   /* GMSH_SEG */ DM_POLYTOPE_SEGMENT,
1263   /* GMSH_TRI */ DM_POLYTOPE_TRIANGLE,
1264   /* GMSH_QUA */ DM_POLYTOPE_QUADRILATERAL,
1265   /* GMSH_TET */ DM_POLYTOPE_TETRAHEDRON,
1266   /* GMSH_HEX */ DM_POLYTOPE_HEXAHEDRON,
1267   /* GMSH_PRI */ DM_POLYTOPE_TRI_PRISM,
1268   /* GMSH_PYR */ DM_POLYTOPE_PYRAMID,
1269   DM_POLYTOPE_UNKNOWN
1270 };
1271 
1272 PETSC_STATIC_INLINE DMPolytopeType DMPolytopeTypeFromGmsh(PetscInt cellType)
1273 {
1274   return DMPolytopeMap[GmshCellMap[cellType].polytope];
1275 }
1276 
1277 static PetscErrorCode GmshCreateFE(MPI_Comm comm, const char prefix[], PetscBool isSimplex, PetscBool continuity, PetscDTNodeType nodeType, PetscInt dim, PetscInt Nc, PetscInt k, PetscFE *fem)
1278 {
1279   DM              K;
1280   PetscSpace      P;
1281   PetscDualSpace  Q;
1282   PetscQuadrature q, fq;
1283   PetscBool       isTensor = isSimplex ? PETSC_FALSE : PETSC_TRUE;
1284   PetscBool       endpoint = PETSC_TRUE;
1285   char            name[32];
1286   PetscErrorCode  ierr;
1287 
1288   PetscFunctionBegin;
1289   /* Create space */
1290   ierr = PetscSpaceCreate(comm, &P);CHKERRQ(ierr);
1291   ierr = PetscSpaceSetType(P, PETSCSPACEPOLYNOMIAL);CHKERRQ(ierr);
1292   ierr = PetscSpacePolynomialSetTensor(P, isTensor);CHKERRQ(ierr);
1293   ierr = PetscSpaceSetNumComponents(P, Nc);CHKERRQ(ierr);
1294   ierr = PetscSpaceSetNumVariables(P, dim);CHKERRQ(ierr);
1295   ierr = PetscSpaceSetDegree(P, k, PETSC_DETERMINE);CHKERRQ(ierr);
1296   if (prefix) {
1297     ierr = PetscObjectSetOptionsPrefix((PetscObject) P, prefix);CHKERRQ(ierr);
1298     ierr = PetscSpaceSetFromOptions(P);CHKERRQ(ierr);
1299     ierr = PetscObjectSetOptionsPrefix((PetscObject) P, NULL);CHKERRQ(ierr);
1300     ierr = PetscSpaceGetDegree(P, &k, NULL);CHKERRQ(ierr);
1301   }
1302   ierr = PetscSpaceSetUp(P);CHKERRQ(ierr);
1303   /* Create dual space */
1304   ierr = PetscDualSpaceCreate(comm, &Q);CHKERRQ(ierr);
1305   ierr = PetscDualSpaceSetType(Q, PETSCDUALSPACELAGRANGE);CHKERRQ(ierr);
1306   ierr = PetscDualSpaceLagrangeSetTensor(Q, isTensor);CHKERRQ(ierr);
1307   ierr = PetscDualSpaceLagrangeSetContinuity(Q, continuity);CHKERRQ(ierr);
1308   ierr = PetscDualSpaceLagrangeSetNodeType(Q, nodeType, endpoint, 0);CHKERRQ(ierr);
1309   ierr = PetscDualSpaceSetNumComponents(Q, Nc);CHKERRQ(ierr);
1310   ierr = PetscDualSpaceSetOrder(Q, k);CHKERRQ(ierr);
1311   ierr = PetscDualSpaceCreateReferenceCell(Q, dim, isSimplex, &K);CHKERRQ(ierr);
1312   ierr = PetscDualSpaceSetDM(Q, K);CHKERRQ(ierr);
1313   ierr = DMDestroy(&K);CHKERRQ(ierr);
1314   if (prefix) {
1315     ierr = PetscObjectSetOptionsPrefix((PetscObject) Q, prefix);CHKERRQ(ierr);
1316     ierr = PetscDualSpaceSetFromOptions(Q);CHKERRQ(ierr);
1317     ierr = PetscObjectSetOptionsPrefix((PetscObject) Q, NULL);CHKERRQ(ierr);
1318   }
1319   ierr = PetscDualSpaceSetUp(Q);CHKERRQ(ierr);
1320   /* Create quadrature */
1321   if (isSimplex) {
1322     ierr = PetscDTStroudConicalQuadrature(dim,   1, k+1, -1, +1, &q);CHKERRQ(ierr);
1323     ierr = PetscDTStroudConicalQuadrature(dim-1, 1, k+1, -1, +1, &fq);CHKERRQ(ierr);
1324   } else {
1325     ierr = PetscDTGaussTensorQuadrature(dim,   1, k+1, -1, +1, &q);CHKERRQ(ierr);
1326     ierr = PetscDTGaussTensorQuadrature(dim-1, 1, k+1, -1, +1, &fq);CHKERRQ(ierr);
1327   }
1328   /* Create finite element */
1329   ierr = PetscFECreate(comm, fem);CHKERRQ(ierr);
1330   ierr = PetscFESetType(*fem, PETSCFEBASIC);CHKERRQ(ierr);
1331   ierr = PetscFESetNumComponents(*fem, Nc);CHKERRQ(ierr);
1332   ierr = PetscFESetBasisSpace(*fem, P);CHKERRQ(ierr);
1333   ierr = PetscFESetDualSpace(*fem, Q);CHKERRQ(ierr);
1334   ierr = PetscFESetQuadrature(*fem, q);CHKERRQ(ierr);
1335   ierr = PetscFESetFaceQuadrature(*fem, fq);CHKERRQ(ierr);
1336   if (prefix) {
1337     ierr = PetscObjectSetOptionsPrefix((PetscObject) *fem, prefix);CHKERRQ(ierr);
1338     ierr = PetscFESetFromOptions(*fem);CHKERRQ(ierr);
1339     ierr = PetscObjectSetOptionsPrefix((PetscObject) *fem, NULL);CHKERRQ(ierr);
1340   }
1341   ierr = PetscFESetUp(*fem);CHKERRQ(ierr);
1342   /* Cleanup */
1343   ierr = PetscSpaceDestroy(&P);CHKERRQ(ierr);
1344   ierr = PetscDualSpaceDestroy(&Q);CHKERRQ(ierr);
1345   ierr = PetscQuadratureDestroy(&q);CHKERRQ(ierr);
1346   ierr = PetscQuadratureDestroy(&fq);CHKERRQ(ierr);
1347   /* Set finite element name */
1348   ierr = PetscSNPrintf(name, sizeof(name), "%s%D", isSimplex? "P" : "Q", k);CHKERRQ(ierr);
1349   ierr = PetscFESetName(*fem, name);CHKERRQ(ierr);
1350   PetscFunctionReturn(0);
1351 }
1352 
1353 /*@C
1354   DMPlexCreateGmshFromFile - Create a DMPlex mesh from a Gmsh file
1355 
1356 + comm        - The MPI communicator
1357 . filename    - Name of the Gmsh file
1358 - interpolate - Create faces and edges in the mesh
1359 
1360   Output Parameter:
1361 . dm  - The DM object representing the mesh
1362 
1363   Level: beginner
1364 
1365 .seealso: DMPlexCreateFromFile(), DMPlexCreateGmsh(), DMPlexCreate()
1366 @*/
1367 PetscErrorCode DMPlexCreateGmshFromFile(MPI_Comm comm, const char filename[], PetscBool interpolate, DM *dm)
1368 {
1369   PetscViewer     viewer;
1370   PetscMPIInt     rank;
1371   int             fileType;
1372   PetscViewerType vtype;
1373   PetscErrorCode  ierr;
1374 
1375   PetscFunctionBegin;
1376   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
1377 
1378   /* Determine Gmsh file type (ASCII or binary) from file header */
1379   if (!rank) {
1380     GmshFile    gmsh[1];
1381     char        line[PETSC_MAX_PATH_LEN];
1382     int         snum;
1383     float       version;
1384 
1385     ierr = PetscArrayzero(gmsh,1);CHKERRQ(ierr);
1386     ierr = PetscViewerCreate(PETSC_COMM_SELF, &gmsh->viewer);CHKERRQ(ierr);
1387     ierr = PetscViewerSetType(gmsh->viewer, PETSCVIEWERASCII);CHKERRQ(ierr);
1388     ierr = PetscViewerFileSetMode(gmsh->viewer, FILE_MODE_READ);CHKERRQ(ierr);
1389     ierr = PetscViewerFileSetName(gmsh->viewer, filename);CHKERRQ(ierr);
1390     /* Read only the first two lines of the Gmsh file */
1391     ierr = GmshReadSection(gmsh, line);CHKERRQ(ierr);
1392     ierr = GmshExpect(gmsh, "$MeshFormat", line);CHKERRQ(ierr);
1393     ierr = GmshReadString(gmsh, line, 2);CHKERRQ(ierr);
1394     snum = sscanf(line, "%f %d", &version, &fileType);
1395     if (snum != 2) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to parse Gmsh file header: %s", line);
1396     if (version < 2.2) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at least 2.2", (double)version);
1397     if ((int)version == 3) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f not supported", (double)version);
1398     if (version > 4.1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at most 4.1", (double)version);
1399     ierr = PetscViewerDestroy(&gmsh->viewer);CHKERRQ(ierr);
1400   }
1401   ierr = MPI_Bcast(&fileType, 1, MPI_INT, 0, comm);CHKERRQ(ierr);
1402   vtype = (fileType == 0) ? PETSCVIEWERASCII : PETSCVIEWERBINARY;
1403 
1404   /* Create appropriate viewer and build plex */
1405   ierr = PetscViewerCreate(comm, &viewer);CHKERRQ(ierr);
1406   ierr = PetscViewerSetType(viewer, vtype);CHKERRQ(ierr);
1407   ierr = PetscViewerFileSetMode(viewer, FILE_MODE_READ);CHKERRQ(ierr);
1408   ierr = PetscViewerFileSetName(viewer, filename);CHKERRQ(ierr);
1409   ierr = DMPlexCreateGmsh(comm, viewer, interpolate, dm);CHKERRQ(ierr);
1410   ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
1411   PetscFunctionReturn(0);
1412 }
1413 
1414 /*@
1415   DMPlexCreateGmsh - Create a DMPlex mesh from a Gmsh file viewer
1416 
1417   Collective
1418 
1419   Input Parameters:
1420 + comm  - The MPI communicator
1421 . viewer - The Viewer associated with a Gmsh file
1422 - interpolate - Create faces and edges in the mesh
1423 
1424   Output Parameter:
1425 . dm  - The DM object representing the mesh
1426 
1427   Note: http://gmsh.info/doc/texinfo/gmsh.html#MSH-file-format
1428 
1429   Level: beginner
1430 
1431 .seealso: DMPLEX, DMCreate()
1432 @*/
1433 PetscErrorCode DMPlexCreateGmsh(MPI_Comm comm, PetscViewer viewer, PetscBool interpolate, DM *dm)
1434 {
1435   GmshMesh      *mesh = NULL;
1436   PetscViewer    parentviewer = NULL;
1437   PetscBT        periodicVerts = NULL;
1438   PetscBT        periodicCells = NULL;
1439   DM             cdm;
1440   PetscSection   coordSection;
1441   Vec            coordinates;
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);CHKERRQ(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) {
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);CHKERRQ(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 && 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(*dm, "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) {
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(*dm, "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(*dm, "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(*dm, "Vertex Sets", vStart + vv, elem->tags[0]);CHKERRQ(ierr);
1686         }
1687       }
1688     }
1689   }
1690 
1691   if (periodic) {
1692     ierr = PetscBTCreate(numVerts, &periodicVerts);CHKERRQ(ierr);
1693     for (n = 0; n < numNodes; ++n) {
1694       if (mesh->vertexMap[n] >= 0) {
1695         if (PetscUnlikely(mesh->periodMap[n] != n)) {
1696           PetscInt m = mesh->periodMap[n];
1697           ierr= PetscBTSet(periodicVerts, mesh->vertexMap[n]);CHKERRQ(ierr);
1698           ierr= PetscBTSet(periodicVerts, mesh->vertexMap[m]);CHKERRQ(ierr);
1699         }
1700       }
1701     }
1702     ierr = PetscBTCreate(numCells, &periodicCells);CHKERRQ(ierr);
1703     for (cell = 0; cell < numCells; ++cell) {
1704       GmshElement *elem = mesh->elements + cell;
1705       for (v = 0; v < elem->numVerts; ++v) {
1706         PetscInt nn = elem->nodes[v];
1707         PetscInt vv = mesh->vertexMap[nn];
1708         if (PetscUnlikely(PetscBTLookup(periodicVerts, vv))) {
1709           ierr = PetscBTSet(periodicCells, cell);CHKERRQ(ierr); break;
1710         }
1711       }
1712     }
1713   }
1714 
1715   /* Setup coordinate DM */
1716   if (coordDim < 0) coordDim = dim;
1717   ierr = DMSetCoordinateDim(*dm, coordDim);CHKERRQ(ierr);
1718   ierr = DMGetCoordinateDM(*dm, &cdm);CHKERRQ(ierr);
1719   if (highOrder) {
1720     PetscFE         fe;
1721     PetscBool       continuity = periodic ? PETSC_FALSE : PETSC_TRUE;
1722     PetscDTNodeType nodeType   = PETSCDTNODES_EQUISPACED;
1723 
1724     if (isSimplex) continuity = PETSC_FALSE; /* XXX FIXME Requires DMPlexSetClosurePermutationLexicographic() */
1725 
1726     ierr = GmshCreateFE(comm, NULL, isSimplex, continuity, nodeType, dim, coordDim, order, &fe);CHKERRQ(ierr);
1727     ierr = PetscFEViewFromOptions(fe, NULL, "-dm_plex_gmsh_fe_view");CHKERRQ(ierr);
1728     ierr = DMSetField(cdm, 0, NULL, (PetscObject) fe);CHKERRQ(ierr);
1729     ierr = PetscFEDestroy(&fe);CHKERRQ(ierr);
1730     ierr = DMCreateDS(cdm);CHKERRQ(ierr);
1731   }
1732 
1733   /* Create coordinates */
1734   if (highOrder) {
1735 
1736     PetscInt     maxDof = GmshNumNodes_HEX(order)*coordDim;
1737     double       *coords = mesh ? mesh->nodelist->xyz : NULL;
1738     PetscSection section;
1739     PetscScalar  *cellCoords;
1740 
1741     ierr = DMSetLocalSection(cdm, NULL);CHKERRQ(ierr);
1742     ierr = DMGetLocalSection(cdm, &coordSection);CHKERRQ(ierr);
1743     ierr = PetscSectionClone(coordSection, &section);CHKERRQ(ierr);
1744     ierr = DMPlexSetClosurePermutationTensor(cdm, 0, section);CHKERRQ(ierr); /* XXX Implement DMPlexSetClosurePermutationLexicographic() */
1745 
1746     ierr = DMCreateLocalVector(cdm, &coordinates);CHKERRQ(ierr);
1747     ierr = PetscMalloc1(maxDof, &cellCoords);CHKERRQ(ierr);
1748     for (cell = 0; cell < numCells; ++cell) {
1749       GmshElement *elem = mesh->elements + cell;
1750       const int *lexorder = GmshCellMap[elem->cellType].lexorder();
1751       for (n = 0; n < elem->numNodes; ++n) {
1752         const PetscInt node = elem->nodes[lexorder[n]];
1753         for (d = 0; d < coordDim; ++d)
1754           cellCoords[n*coordDim+d] = (PetscReal) coords[node*3+d];
1755       }
1756       ierr = DMPlexVecSetClosure(cdm, section, coordinates, cell, cellCoords, INSERT_VALUES);CHKERRQ(ierr);
1757     }
1758     ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
1759     ierr = PetscFree(cellCoords);CHKERRQ(ierr);
1760 
1761   } else {
1762 
1763     PetscInt    *nodeMap;
1764     double      *coords = mesh ? mesh->nodelist->xyz : NULL;
1765     PetscScalar *pointCoords;
1766 
1767     ierr = DMGetLocalSection(cdm, &coordSection);CHKERRQ(ierr);
1768     ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
1769     ierr = PetscSectionSetFieldComponents(coordSection, 0, coordDim);CHKERRQ(ierr);
1770     if (periodic) { /* we need to localize coordinates on cells */
1771       ierr = PetscSectionSetChart(coordSection, 0, numCells+numVerts);CHKERRQ(ierr);
1772     } else {
1773       ierr = PetscSectionSetChart(coordSection, numCells, numCells+numVerts);CHKERRQ(ierr);
1774     }
1775     if (periodic) {
1776       for (cell = 0; cell < numCells; ++cell) {
1777         if (PetscUnlikely(PetscBTLookup(periodicCells, cell))) {
1778           GmshElement *elem = mesh->elements + cell;
1779           PetscInt dof = elem->numVerts * coordDim;
1780           ierr = PetscSectionSetDof(coordSection, cell, dof);CHKERRQ(ierr);
1781           ierr = PetscSectionSetFieldDof(coordSection, cell, 0, dof);CHKERRQ(ierr);
1782         }
1783       }
1784     }
1785     for (v = numCells; v < numCells+numVerts; ++v) {
1786       ierr = PetscSectionSetDof(coordSection, v, coordDim);CHKERRQ(ierr);
1787       ierr = PetscSectionSetFieldDof(coordSection, v, 0, coordDim);CHKERRQ(ierr);
1788     }
1789     ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
1790 
1791     ierr = DMCreateLocalVector(cdm, &coordinates);CHKERRQ(ierr);
1792     ierr = VecGetArray(coordinates, &pointCoords);CHKERRQ(ierr);
1793     if (periodic) {
1794       for (cell = 0; cell < numCells; ++cell) {
1795         if (PetscUnlikely(PetscBTLookup(periodicCells, cell))) {
1796           GmshElement *elem = mesh->elements + cell;
1797           PetscInt off, node;
1798           for (v = 0; v < elem->numVerts; ++v)
1799             cone[v] = elem->nodes[v];
1800           ierr = DMPlexReorderCell(cdm, cell, cone);CHKERRQ(ierr);
1801           ierr = PetscSectionGetOffset(coordSection, cell, &off);CHKERRQ(ierr);
1802           for (v = 0; v < elem->numVerts; ++v)
1803             for (node = cone[v], d = 0; d < coordDim; ++d)
1804               pointCoords[off++] = (PetscReal) coords[node*3+d];
1805         }
1806       }
1807     }
1808     ierr = PetscMalloc1(numVerts, &nodeMap);CHKERRQ(ierr);
1809     for (n = 0; n < numNodes; n++)
1810       if (mesh->vertexMap[n] >= 0)
1811         nodeMap[mesh->vertexMap[n]] = n;
1812     for (v = 0; v < numVerts; ++v) {
1813       PetscInt off, node = nodeMap[v];
1814       ierr = PetscSectionGetOffset(coordSection, numCells + v, &off);CHKERRQ(ierr);
1815       for (d = 0; d < coordDim; ++d)
1816         pointCoords[off+d] = (PetscReal) coords[node*3+d];
1817     }
1818     ierr = PetscFree(nodeMap);CHKERRQ(ierr);
1819     ierr = VecRestoreArray(coordinates, &pointCoords);CHKERRQ(ierr);
1820 
1821   }
1822 
1823   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
1824   ierr = VecSetBlockSize(coordinates, coordDim);CHKERRQ(ierr);
1825   ierr = DMSetCoordinatesLocal(*dm, coordinates);CHKERRQ(ierr);
1826   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
1827   ierr = DMSetPeriodicity(*dm, periodic, NULL, NULL, NULL);CHKERRQ(ierr);
1828 
1829   ierr = GmshMeshDestroy(&mesh);CHKERRQ(ierr);
1830   ierr = PetscBTDestroy(&periodicVerts);CHKERRQ(ierr);
1831   ierr = PetscBTDestroy(&periodicCells);CHKERRQ(ierr);
1832 
1833   if (highOrder && project)  {
1834     PetscFE         fe;
1835     const char      prefix[]   = "dm_plex_gmsh_project_";
1836     PetscBool       continuity = periodic ? PETSC_FALSE : PETSC_TRUE;
1837     PetscDTNodeType nodeType   = PETSCDTNODES_GAUSSJACOBI;
1838 
1839     if (isSimplex) continuity = PETSC_FALSE; /* XXX FIXME Requires DMPlexSetClosurePermutationLexicographic() */
1840 
1841     ierr = GmshCreateFE(comm, prefix, isSimplex, continuity, nodeType, dim, coordDim, order, &fe);CHKERRQ(ierr);
1842     ierr = PetscFEViewFromOptions(fe, NULL, "-dm_plex_gmsh_project_fe_view");CHKERRQ(ierr);
1843     ierr = DMProjectCoordinates(*dm, fe);CHKERRQ(ierr);
1844     ierr = PetscFEDestroy(&fe);CHKERRQ(ierr);
1845   }
1846 
1847   ierr = PetscLogEventEnd(DMPLEX_CreateGmsh,*dm,NULL,NULL,NULL);CHKERRQ(ierr);
1848   PetscFunctionReturn(0);
1849 }
1850