xref: /petsc/src/dm/impls/plex/plexgmsh.c (revision a4e35b1925eceef64945ea472b84f2bf06a67b5e)
1331830f3SMatthew G. Knepley #define PETSCDM_DLL
2af0996ceSBarry Smith #include <petsc/private/dmpleximpl.h> /*I   "petscdmplex.h"   I*/
3730356f6SLisandro Dalcin #include <petsc/private/hashmapi.h>
4331830f3SMatthew G. Knepley 
5066ea43fSLisandro Dalcin #include <../src/dm/impls/plex/gmshlex.h>
6066ea43fSLisandro Dalcin 
7066ea43fSLisandro Dalcin #define GMSH_LEXORDER_ITEM(T, p) \
8d71ae5a4SJacob Faibussowitsch   static int *GmshLexOrder_##T##_##p(void) \
9d71ae5a4SJacob Faibussowitsch   { \
10066ea43fSLisandro Dalcin     static int Gmsh_LexOrder_##T##_##p[GmshNumNodes_##T(p)] = {-1}; \
11066ea43fSLisandro Dalcin     int       *lex                                          = Gmsh_LexOrder_##T##_##p; \
12066ea43fSLisandro Dalcin     if (lex[0] == -1) (void)GmshLexOrder_##T(p, lex, 0); \
13066ea43fSLisandro Dalcin     return lex; \
14066ea43fSLisandro Dalcin   }
15066ea43fSLisandro Dalcin 
16d71ae5a4SJacob Faibussowitsch static int *GmshLexOrder_QUA_2_Serendipity(void)
17d71ae5a4SJacob Faibussowitsch {
18b9bf55e5SMatthew G. Knepley   static int Gmsh_LexOrder_QUA_2_Serendipity[9] = {-1};
19b9bf55e5SMatthew G. Knepley   int       *lex                                = Gmsh_LexOrder_QUA_2_Serendipity;
20b9bf55e5SMatthew G. Knepley   if (lex[0] == -1) {
21b9bf55e5SMatthew G. Knepley     /* Vertices */
229371c9d4SSatish Balay     lex[0] = 0;
239371c9d4SSatish Balay     lex[2] = 1;
249371c9d4SSatish Balay     lex[8] = 2;
259371c9d4SSatish Balay     lex[6] = 3;
26b9bf55e5SMatthew G. Knepley     /* Edges */
279371c9d4SSatish Balay     lex[1] = 4;
289371c9d4SSatish Balay     lex[5] = 5;
299371c9d4SSatish Balay     lex[7] = 6;
309371c9d4SSatish Balay     lex[3] = 7;
31b9bf55e5SMatthew G. Knepley     /* Cell */
32b9bf55e5SMatthew G. Knepley     lex[4] = -8;
33b9bf55e5SMatthew G. Knepley   }
34b9bf55e5SMatthew G. Knepley   return lex;
35b9bf55e5SMatthew G. Knepley }
36b9bf55e5SMatthew G. Knepley 
37d71ae5a4SJacob Faibussowitsch static int *GmshLexOrder_HEX_2_Serendipity(void)
38d71ae5a4SJacob Faibussowitsch {
39b9bf55e5SMatthew G. Knepley   static int Gmsh_LexOrder_HEX_2_Serendipity[27] = {-1};
40b9bf55e5SMatthew G. Knepley   int       *lex                                 = Gmsh_LexOrder_HEX_2_Serendipity;
41b9bf55e5SMatthew G. Knepley   if (lex[0] == -1) {
42b9bf55e5SMatthew G. Knepley     /* Vertices */
439371c9d4SSatish Balay     lex[0]  = 0;
449371c9d4SSatish Balay     lex[2]  = 1;
459371c9d4SSatish Balay     lex[8]  = 2;
469371c9d4SSatish Balay     lex[6]  = 3;
479371c9d4SSatish Balay     lex[18] = 4;
489371c9d4SSatish Balay     lex[20] = 5;
499371c9d4SSatish Balay     lex[26] = 6;
509371c9d4SSatish Balay     lex[24] = 7;
51b9bf55e5SMatthew G. Knepley     /* Edges */
529371c9d4SSatish Balay     lex[1]  = 8;
539371c9d4SSatish Balay     lex[3]  = 9;
549371c9d4SSatish Balay     lex[9]  = 10;
559371c9d4SSatish Balay     lex[5]  = 11;
569371c9d4SSatish Balay     lex[11] = 12;
579371c9d4SSatish Balay     lex[7]  = 13;
589371c9d4SSatish Balay     lex[17] = 14;
599371c9d4SSatish Balay     lex[15] = 15;
609371c9d4SSatish Balay     lex[19] = 16;
619371c9d4SSatish Balay     lex[21] = 17;
629371c9d4SSatish Balay     lex[23] = 18;
639371c9d4SSatish Balay     lex[25] = 19;
64b9bf55e5SMatthew G. Knepley     /* Faces */
659371c9d4SSatish Balay     lex[4]  = -20;
669371c9d4SSatish Balay     lex[10] = -21;
679371c9d4SSatish Balay     lex[12] = -22;
689371c9d4SSatish Balay     lex[14] = -23;
699371c9d4SSatish Balay     lex[16] = -24;
709371c9d4SSatish Balay     lex[22] = -25;
71b9bf55e5SMatthew G. Knepley     /* Cell */
72b9bf55e5SMatthew G. Knepley     lex[13] = -26;
73b9bf55e5SMatthew G. Knepley   }
74b9bf55e5SMatthew G. Knepley   return lex;
75b9bf55e5SMatthew G. Knepley }
76b9bf55e5SMatthew G. Knepley 
77066ea43fSLisandro Dalcin #define GMSH_LEXORDER_LIST(T) \
78066ea43fSLisandro Dalcin   GMSH_LEXORDER_ITEM(T, 1) \
79066ea43fSLisandro Dalcin   GMSH_LEXORDER_ITEM(T, 2) \
80066ea43fSLisandro Dalcin   GMSH_LEXORDER_ITEM(T, 3) \
81066ea43fSLisandro Dalcin   GMSH_LEXORDER_ITEM(T, 4) \
82066ea43fSLisandro Dalcin   GMSH_LEXORDER_ITEM(T, 5) \
83066ea43fSLisandro Dalcin   GMSH_LEXORDER_ITEM(T, 6) \
84066ea43fSLisandro Dalcin   GMSH_LEXORDER_ITEM(T, 7) \
85066ea43fSLisandro Dalcin   GMSH_LEXORDER_ITEM(T, 8) \
86066ea43fSLisandro Dalcin   GMSH_LEXORDER_ITEM(T, 9) \
87066ea43fSLisandro Dalcin   GMSH_LEXORDER_ITEM(T, 10)
88066ea43fSLisandro Dalcin 
89066ea43fSLisandro Dalcin GMSH_LEXORDER_ITEM(VTX, 0)
90066ea43fSLisandro Dalcin GMSH_LEXORDER_LIST(SEG)
91066ea43fSLisandro Dalcin GMSH_LEXORDER_LIST(TRI)
92066ea43fSLisandro Dalcin GMSH_LEXORDER_LIST(QUA)
93066ea43fSLisandro Dalcin GMSH_LEXORDER_LIST(TET)
94066ea43fSLisandro Dalcin GMSH_LEXORDER_LIST(HEX)
95066ea43fSLisandro Dalcin GMSH_LEXORDER_LIST(PRI)
96066ea43fSLisandro Dalcin GMSH_LEXORDER_LIST(PYR)
97066ea43fSLisandro Dalcin 
98066ea43fSLisandro Dalcin typedef enum {
99066ea43fSLisandro Dalcin   GMSH_VTX           = 0,
100066ea43fSLisandro Dalcin   GMSH_SEG           = 1,
101066ea43fSLisandro Dalcin   GMSH_TRI           = 2,
102066ea43fSLisandro Dalcin   GMSH_QUA           = 3,
103066ea43fSLisandro Dalcin   GMSH_TET           = 4,
104066ea43fSLisandro Dalcin   GMSH_HEX           = 5,
105066ea43fSLisandro Dalcin   GMSH_PRI           = 6,
106066ea43fSLisandro Dalcin   GMSH_PYR           = 7,
107066ea43fSLisandro Dalcin   GMSH_NUM_POLYTOPES = 8
108066ea43fSLisandro Dalcin } GmshPolytopeType;
109066ea43fSLisandro Dalcin 
110de78e4feSLisandro Dalcin typedef struct {
1110598e1a2SLisandro Dalcin   int cellType;
112066ea43fSLisandro Dalcin   int polytope;
1130598e1a2SLisandro Dalcin   int dim;
1140598e1a2SLisandro Dalcin   int order;
115066ea43fSLisandro Dalcin   int numVerts;
1160598e1a2SLisandro Dalcin   int numNodes;
117066ea43fSLisandro Dalcin   int *(*lexorder)(void);
1180598e1a2SLisandro Dalcin } GmshCellInfo;
1190598e1a2SLisandro Dalcin 
120066ea43fSLisandro Dalcin #define GmshCellEntry(cellType, polytope, dim, order) \
121d71ae5a4SJacob Faibussowitsch   { \
122d71ae5a4SJacob Faibussowitsch     cellType, GMSH_##polytope, dim, order, GmshNumNodes_##polytope(1), GmshNumNodes_##polytope(order), GmshLexOrder_##polytope##_##order \
123d71ae5a4SJacob Faibussowitsch   }
1240598e1a2SLisandro Dalcin 
1250598e1a2SLisandro Dalcin static const GmshCellInfo GmshCellTable[] = {
126066ea43fSLisandro Dalcin   GmshCellEntry(15, VTX, 0, 0),
1270598e1a2SLisandro Dalcin 
1289371c9d4SSatish Balay   GmshCellEntry(1, SEG, 1, 1),   GmshCellEntry(8, SEG, 1, 2),   GmshCellEntry(26, SEG, 1, 3),
1299371c9d4SSatish Balay   GmshCellEntry(27, SEG, 1, 4),  GmshCellEntry(28, SEG, 1, 5),  GmshCellEntry(62, SEG, 1, 6),
1309371c9d4SSatish Balay   GmshCellEntry(63, SEG, 1, 7),  GmshCellEntry(64, SEG, 1, 8),  GmshCellEntry(65, SEG, 1, 9),
131066ea43fSLisandro Dalcin   GmshCellEntry(66, SEG, 1, 10),
1320598e1a2SLisandro Dalcin 
1339371c9d4SSatish Balay   GmshCellEntry(2, TRI, 2, 1),   GmshCellEntry(9, TRI, 2, 2),   GmshCellEntry(21, TRI, 2, 3),
1349371c9d4SSatish Balay   GmshCellEntry(23, TRI, 2, 4),  GmshCellEntry(25, TRI, 2, 5),  GmshCellEntry(42, TRI, 2, 6),
1359371c9d4SSatish Balay   GmshCellEntry(43, TRI, 2, 7),  GmshCellEntry(44, TRI, 2, 8),  GmshCellEntry(45, TRI, 2, 9),
136066ea43fSLisandro Dalcin   GmshCellEntry(46, TRI, 2, 10),
1370598e1a2SLisandro Dalcin 
1389371c9d4SSatish Balay   GmshCellEntry(3, QUA, 2, 1),   GmshCellEntry(10, QUA, 2, 2),  {16, GMSH_QUA, 2, 2, 4, 8,  GmshLexOrder_QUA_2_Serendipity},
1399371c9d4SSatish Balay   GmshCellEntry(36, QUA, 2, 3),  GmshCellEntry(37, QUA, 2, 4),  GmshCellEntry(38, QUA, 2, 5),
1409371c9d4SSatish Balay   GmshCellEntry(47, QUA, 2, 6),  GmshCellEntry(48, QUA, 2, 7),  GmshCellEntry(49, QUA, 2, 8),
1419371c9d4SSatish Balay   GmshCellEntry(50, QUA, 2, 9),  GmshCellEntry(51, QUA, 2, 10),
1420598e1a2SLisandro Dalcin 
1439371c9d4SSatish Balay   GmshCellEntry(4, TET, 3, 1),   GmshCellEntry(11, TET, 3, 2),  GmshCellEntry(29, TET, 3, 3),
1449371c9d4SSatish Balay   GmshCellEntry(30, TET, 3, 4),  GmshCellEntry(31, TET, 3, 5),  GmshCellEntry(71, TET, 3, 6),
1459371c9d4SSatish Balay   GmshCellEntry(72, TET, 3, 7),  GmshCellEntry(73, TET, 3, 8),  GmshCellEntry(74, TET, 3, 9),
146066ea43fSLisandro Dalcin   GmshCellEntry(75, TET, 3, 10),
1470598e1a2SLisandro Dalcin 
1489371c9d4SSatish Balay   GmshCellEntry(5, HEX, 3, 1),   GmshCellEntry(12, HEX, 3, 2),  {17, GMSH_HEX, 3, 2, 8, 20, GmshLexOrder_HEX_2_Serendipity},
1499371c9d4SSatish Balay   GmshCellEntry(92, HEX, 3, 3),  GmshCellEntry(93, HEX, 3, 4),  GmshCellEntry(94, HEX, 3, 5),
1509371c9d4SSatish Balay   GmshCellEntry(95, HEX, 3, 6),  GmshCellEntry(96, HEX, 3, 7),  GmshCellEntry(97, HEX, 3, 8),
1519371c9d4SSatish Balay   GmshCellEntry(98, HEX, 3, 9),  GmshCellEntry(-1, HEX, 3, 10),
1520598e1a2SLisandro Dalcin 
1539371c9d4SSatish Balay   GmshCellEntry(6, PRI, 3, 1),   GmshCellEntry(13, PRI, 3, 2),  GmshCellEntry(90, PRI, 3, 3),
1549371c9d4SSatish Balay   GmshCellEntry(91, PRI, 3, 4),  GmshCellEntry(106, PRI, 3, 5), GmshCellEntry(107, PRI, 3, 6),
1559371c9d4SSatish Balay   GmshCellEntry(108, PRI, 3, 7), GmshCellEntry(109, PRI, 3, 8), GmshCellEntry(110, PRI, 3, 9),
156066ea43fSLisandro Dalcin   GmshCellEntry(-1, PRI, 3, 10),
1570598e1a2SLisandro Dalcin 
1589371c9d4SSatish Balay   GmshCellEntry(7, PYR, 3, 1),   GmshCellEntry(14, PYR, 3, 2),  GmshCellEntry(118, PYR, 3, 3),
1599371c9d4SSatish Balay   GmshCellEntry(119, PYR, 3, 4), GmshCellEntry(120, PYR, 3, 5), GmshCellEntry(121, PYR, 3, 6),
1609371c9d4SSatish Balay   GmshCellEntry(122, PYR, 3, 7), GmshCellEntry(123, PYR, 3, 8), GmshCellEntry(124, PYR, 3, 9),
161066ea43fSLisandro Dalcin   GmshCellEntry(-1, PYR, 3, 10)
1620598e1a2SLisandro Dalcin 
1630598e1a2SLisandro Dalcin #if 0
164066ea43fSLisandro Dalcin   {20, GMSH_TRI, 2, 3, 3,  9, NULL},
165066ea43fSLisandro Dalcin   {18, GMSH_PRI, 3, 2, 6, 15, NULL},
166066ea43fSLisandro Dalcin   {19, GMSH_PYR, 3, 2, 5, 13, NULL},
1670598e1a2SLisandro Dalcin #endif
1680598e1a2SLisandro Dalcin };
1690598e1a2SLisandro Dalcin 
1700598e1a2SLisandro Dalcin static GmshCellInfo GmshCellMap[150];
1710598e1a2SLisandro Dalcin 
172d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshCellInfoSetUp(void)
173d71ae5a4SJacob Faibussowitsch {
1740598e1a2SLisandro Dalcin   size_t           i, n;
1750598e1a2SLisandro Dalcin   static PetscBool called = PETSC_FALSE;
1760598e1a2SLisandro Dalcin 
1773ba16761SJacob Faibussowitsch   if (called) return PETSC_SUCCESS;
1780598e1a2SLisandro Dalcin   PetscFunctionBegin;
1790598e1a2SLisandro Dalcin   called = PETSC_TRUE;
180dd39110bSPierre Jolivet   n      = PETSC_STATIC_ARRAY_LENGTH(GmshCellMap);
1810598e1a2SLisandro Dalcin   for (i = 0; i < n; ++i) {
1820598e1a2SLisandro Dalcin     GmshCellMap[i].cellType = -1;
183066ea43fSLisandro Dalcin     GmshCellMap[i].polytope = -1;
1840598e1a2SLisandro Dalcin   }
185dd39110bSPierre Jolivet   n = PETSC_STATIC_ARRAY_LENGTH(GmshCellTable);
186066ea43fSLisandro Dalcin   for (i = 0; i < n; ++i) {
187066ea43fSLisandro Dalcin     if (GmshCellTable[i].cellType <= 0) continue;
188066ea43fSLisandro Dalcin     GmshCellMap[GmshCellTable[i].cellType] = GmshCellTable[i];
189066ea43fSLisandro Dalcin   }
1903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1910598e1a2SLisandro Dalcin }
1920598e1a2SLisandro Dalcin 
1939371c9d4SSatish Balay #define GmshCellTypeCheck(ct) \
1949371c9d4SSatish Balay   PetscMacroReturnStandard(const int _ct_ = (int)ct; PetscCheck(_ct_ >= 0 && _ct_ < (int)PETSC_STATIC_ARRAY_LENGTH(GmshCellMap), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid Gmsh element type %d", _ct_); PetscCheck(GmshCellMap[_ct_].cellType == _ct_, PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported Gmsh element type %d", _ct_); \
1959371c9d4SSatish Balay                            PetscCheck(GmshCellMap[_ct_].polytope != -1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported Gmsh element type %d", _ct_);)
1960598e1a2SLisandro Dalcin 
1970598e1a2SLisandro Dalcin typedef struct {
198698a79b9SLisandro Dalcin   PetscViewer viewer;
199698a79b9SLisandro Dalcin   int         fileFormat;
200698a79b9SLisandro Dalcin   int         dataSize;
201698a79b9SLisandro Dalcin   PetscBool   binary;
202698a79b9SLisandro Dalcin   PetscBool   byteSwap;
203698a79b9SLisandro Dalcin   size_t      wlen;
204698a79b9SLisandro Dalcin   void       *wbuf;
205698a79b9SLisandro Dalcin   size_t      slen;
206698a79b9SLisandro Dalcin   void       *sbuf;
2070598e1a2SLisandro Dalcin   PetscInt   *nbuf;
2080598e1a2SLisandro Dalcin   PetscInt    nodeStart;
2090598e1a2SLisandro Dalcin   PetscInt    nodeEnd;
21033a088b6SMatthew G. Knepley   PetscInt   *nodeMap;
211698a79b9SLisandro Dalcin } GmshFile;
212de78e4feSLisandro Dalcin 
213d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshBufferGet(GmshFile *gmsh, size_t count, size_t eltsize, void *buf)
214d71ae5a4SJacob Faibussowitsch {
215de78e4feSLisandro Dalcin   size_t size = count * eltsize;
21611c56cb0SLisandro Dalcin 
21711c56cb0SLisandro Dalcin   PetscFunctionBegin;
218698a79b9SLisandro Dalcin   if (gmsh->wlen < size) {
2199566063dSJacob Faibussowitsch     PetscCall(PetscFree(gmsh->wbuf));
2209566063dSJacob Faibussowitsch     PetscCall(PetscMalloc(size, &gmsh->wbuf));
221698a79b9SLisandro Dalcin     gmsh->wlen = size;
222de78e4feSLisandro Dalcin   }
223698a79b9SLisandro Dalcin   *(void **)buf = size ? gmsh->wbuf : NULL;
2243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
225de78e4feSLisandro Dalcin }
226de78e4feSLisandro Dalcin 
227d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshBufferSizeGet(GmshFile *gmsh, size_t count, void *buf)
228d71ae5a4SJacob Faibussowitsch {
229698a79b9SLisandro Dalcin   size_t dataSize = (size_t)gmsh->dataSize;
230698a79b9SLisandro Dalcin   size_t size     = count * dataSize;
231698a79b9SLisandro Dalcin 
232698a79b9SLisandro Dalcin   PetscFunctionBegin;
233698a79b9SLisandro Dalcin   if (gmsh->slen < size) {
2349566063dSJacob Faibussowitsch     PetscCall(PetscFree(gmsh->sbuf));
2359566063dSJacob Faibussowitsch     PetscCall(PetscMalloc(size, &gmsh->sbuf));
236698a79b9SLisandro Dalcin     gmsh->slen = size;
237698a79b9SLisandro Dalcin   }
238698a79b9SLisandro Dalcin   *(void **)buf = size ? gmsh->sbuf : NULL;
2393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
240698a79b9SLisandro Dalcin }
241698a79b9SLisandro Dalcin 
242d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshRead(GmshFile *gmsh, void *buf, PetscInt count, PetscDataType dtype)
243d71ae5a4SJacob Faibussowitsch {
244de78e4feSLisandro Dalcin   PetscFunctionBegin;
2459566063dSJacob Faibussowitsch   PetscCall(PetscViewerRead(gmsh->viewer, buf, count, NULL, dtype));
2469566063dSJacob Faibussowitsch   if (gmsh->byteSwap) PetscCall(PetscByteSwap(buf, dtype, count));
2473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
248698a79b9SLisandro Dalcin }
249698a79b9SLisandro Dalcin 
250d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadString(GmshFile *gmsh, char *buf, PetscInt count)
251d71ae5a4SJacob Faibussowitsch {
252698a79b9SLisandro Dalcin   PetscFunctionBegin;
2539566063dSJacob Faibussowitsch   PetscCall(PetscViewerRead(gmsh->viewer, buf, count, NULL, PETSC_STRING));
2543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
255698a79b9SLisandro Dalcin }
256698a79b9SLisandro Dalcin 
257d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshMatch(PETSC_UNUSED GmshFile *gmsh, const char Section[], char line[PETSC_MAX_PATH_LEN], PetscBool *match)
258d71ae5a4SJacob Faibussowitsch {
259d6689ca9SLisandro Dalcin   PetscFunctionBegin;
2609566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(line, Section, match));
2613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
262d6689ca9SLisandro Dalcin }
263d6689ca9SLisandro Dalcin 
264d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshExpect(GmshFile *gmsh, const char Section[], char line[PETSC_MAX_PATH_LEN])
265d71ae5a4SJacob Faibussowitsch {
266d6689ca9SLisandro Dalcin   PetscBool match;
267d6689ca9SLisandro Dalcin 
268d6689ca9SLisandro Dalcin   PetscFunctionBegin;
2699566063dSJacob Faibussowitsch   PetscCall(GmshMatch(gmsh, Section, line, &match));
27028b400f6SJacob Faibussowitsch   PetscCheck(match, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file, expecting %s", Section);
2713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
272d6689ca9SLisandro Dalcin }
273d6689ca9SLisandro Dalcin 
274d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadSection(GmshFile *gmsh, char line[PETSC_MAX_PATH_LEN])
275d71ae5a4SJacob Faibussowitsch {
276d6689ca9SLisandro Dalcin   PetscBool match;
277d6689ca9SLisandro Dalcin 
278d6689ca9SLisandro Dalcin   PetscFunctionBegin;
279d6689ca9SLisandro Dalcin   while (PETSC_TRUE) {
2809566063dSJacob Faibussowitsch     PetscCall(GmshReadString(gmsh, line, 1));
2819566063dSJacob Faibussowitsch     PetscCall(GmshMatch(gmsh, "$Comments", line, &match));
282d6689ca9SLisandro Dalcin     if (!match) break;
283d6689ca9SLisandro Dalcin     while (PETSC_TRUE) {
2849566063dSJacob Faibussowitsch       PetscCall(GmshReadString(gmsh, line, 1));
2859566063dSJacob Faibussowitsch       PetscCall(GmshMatch(gmsh, "$EndComments", line, &match));
286d6689ca9SLisandro Dalcin       if (match) break;
287d6689ca9SLisandro Dalcin     }
288d6689ca9SLisandro Dalcin   }
2893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
290d6689ca9SLisandro Dalcin }
291d6689ca9SLisandro Dalcin 
292d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadEndSection(GmshFile *gmsh, const char EndSection[], char line[PETSC_MAX_PATH_LEN])
293d71ae5a4SJacob Faibussowitsch {
294d6689ca9SLisandro Dalcin   PetscFunctionBegin;
2959566063dSJacob Faibussowitsch   PetscCall(GmshReadString(gmsh, line, 1));
2969566063dSJacob Faibussowitsch   PetscCall(GmshExpect(gmsh, EndSection, line));
2973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
298d6689ca9SLisandro Dalcin }
299d6689ca9SLisandro Dalcin 
300d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadSize(GmshFile *gmsh, PetscInt *buf, PetscInt count)
301d71ae5a4SJacob Faibussowitsch {
302698a79b9SLisandro Dalcin   PetscInt i;
303698a79b9SLisandro Dalcin   size_t   dataSize = (size_t)gmsh->dataSize;
304698a79b9SLisandro Dalcin 
305698a79b9SLisandro Dalcin   PetscFunctionBegin;
306698a79b9SLisandro Dalcin   if (dataSize == sizeof(PetscInt)) {
3079566063dSJacob Faibussowitsch     PetscCall(GmshRead(gmsh, buf, count, PETSC_INT));
308698a79b9SLisandro Dalcin   } else if (dataSize == sizeof(int)) {
309698a79b9SLisandro Dalcin     int *ibuf = NULL;
3109566063dSJacob Faibussowitsch     PetscCall(GmshBufferSizeGet(gmsh, count, &ibuf));
3119566063dSJacob Faibussowitsch     PetscCall(GmshRead(gmsh, ibuf, count, PETSC_ENUM));
312698a79b9SLisandro Dalcin     for (i = 0; i < count; ++i) buf[i] = (PetscInt)ibuf[i];
313698a79b9SLisandro Dalcin   } else if (dataSize == sizeof(long)) {
314698a79b9SLisandro Dalcin     long *ibuf = NULL;
3159566063dSJacob Faibussowitsch     PetscCall(GmshBufferSizeGet(gmsh, count, &ibuf));
3169566063dSJacob Faibussowitsch     PetscCall(GmshRead(gmsh, ibuf, count, PETSC_LONG));
317698a79b9SLisandro Dalcin     for (i = 0; i < count; ++i) buf[i] = (PetscInt)ibuf[i];
318698a79b9SLisandro Dalcin   } else if (dataSize == sizeof(PetscInt64)) {
319698a79b9SLisandro Dalcin     PetscInt64 *ibuf = NULL;
3209566063dSJacob Faibussowitsch     PetscCall(GmshBufferSizeGet(gmsh, count, &ibuf));
3219566063dSJacob Faibussowitsch     PetscCall(GmshRead(gmsh, ibuf, count, PETSC_INT64));
322698a79b9SLisandro Dalcin     for (i = 0; i < count; ++i) buf[i] = (PetscInt)ibuf[i];
323698a79b9SLisandro Dalcin   }
3243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
325698a79b9SLisandro Dalcin }
326698a79b9SLisandro Dalcin 
327d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadInt(GmshFile *gmsh, int *buf, PetscInt count)
328d71ae5a4SJacob Faibussowitsch {
329698a79b9SLisandro Dalcin   PetscFunctionBegin;
3309566063dSJacob Faibussowitsch   PetscCall(GmshRead(gmsh, buf, count, PETSC_ENUM));
3313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
332698a79b9SLisandro Dalcin }
333698a79b9SLisandro Dalcin 
334d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadDouble(GmshFile *gmsh, double *buf, PetscInt count)
335d71ae5a4SJacob Faibussowitsch {
336698a79b9SLisandro Dalcin   PetscFunctionBegin;
3379566063dSJacob Faibussowitsch   PetscCall(GmshRead(gmsh, buf, count, PETSC_DOUBLE));
3383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
339de78e4feSLisandro Dalcin }
340de78e4feSLisandro Dalcin 
3419c0edc59SMatthew G. Knepley #define GMSH_MAX_TAGS 16
3427d5b9244SMatthew G. Knepley 
343de78e4feSLisandro Dalcin typedef struct {
3440598e1a2SLisandro Dalcin   PetscInt id;                  /* Entity ID */
3450598e1a2SLisandro Dalcin   PetscInt dim;                 /* Dimension */
346de78e4feSLisandro Dalcin   double   bbox[6];             /* Bounding box */
347de78e4feSLisandro Dalcin   PetscInt numTags;             /* Size of tag array */
3487d5b9244SMatthew G. Knepley   int      tags[GMSH_MAX_TAGS]; /* Tag array */
349de78e4feSLisandro Dalcin } GmshEntity;
350de78e4feSLisandro Dalcin 
351de78e4feSLisandro Dalcin typedef struct {
352730356f6SLisandro Dalcin   GmshEntity *entity[4];
353730356f6SLisandro Dalcin   PetscHMapI  entityMap[4];
354730356f6SLisandro Dalcin } GmshEntities;
355730356f6SLisandro Dalcin 
356d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshEntitiesCreate(PetscInt count[4], GmshEntities **entities)
357d71ae5a4SJacob Faibussowitsch {
358730356f6SLisandro Dalcin   PetscInt dim;
359730356f6SLisandro Dalcin 
360730356f6SLisandro Dalcin   PetscFunctionBegin;
3619566063dSJacob Faibussowitsch   PetscCall(PetscNew(entities));
362730356f6SLisandro Dalcin   for (dim = 0; dim < 4; ++dim) {
3639566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(count[dim], &(*entities)->entity[dim]));
3649566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&(*entities)->entityMap[dim]));
365730356f6SLisandro Dalcin   }
3663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
367730356f6SLisandro Dalcin }
368730356f6SLisandro Dalcin 
369d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshEntitiesDestroy(GmshEntities **entities)
370d71ae5a4SJacob Faibussowitsch {
3710598e1a2SLisandro Dalcin   PetscInt dim;
3720598e1a2SLisandro Dalcin 
3730598e1a2SLisandro Dalcin   PetscFunctionBegin;
3743ba16761SJacob Faibussowitsch   if (!*entities) PetscFunctionReturn(PETSC_SUCCESS);
3750598e1a2SLisandro Dalcin   for (dim = 0; dim < 4; ++dim) {
3769566063dSJacob Faibussowitsch     PetscCall(PetscFree((*entities)->entity[dim]));
3779566063dSJacob Faibussowitsch     PetscCall(PetscHMapIDestroy(&(*entities)->entityMap[dim]));
3780598e1a2SLisandro Dalcin   }
3799566063dSJacob Faibussowitsch   PetscCall(PetscFree((*entities)));
3803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3810598e1a2SLisandro Dalcin }
3820598e1a2SLisandro Dalcin 
383d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshEntitiesAdd(GmshEntities *entities, PetscInt index, PetscInt dim, PetscInt eid, GmshEntity **entity)
384d71ae5a4SJacob Faibussowitsch {
385730356f6SLisandro Dalcin   PetscFunctionBegin;
3869566063dSJacob Faibussowitsch   PetscCall(PetscHMapISet(entities->entityMap[dim], eid, index));
387730356f6SLisandro Dalcin   entities->entity[dim][index].dim = dim;
388730356f6SLisandro Dalcin   entities->entity[dim][index].id  = eid;
389730356f6SLisandro Dalcin   if (entity) *entity = &entities->entity[dim][index];
3903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
391730356f6SLisandro Dalcin }
392730356f6SLisandro Dalcin 
393d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshEntitiesGet(GmshEntities *entities, PetscInt dim, PetscInt eid, GmshEntity **entity)
394d71ae5a4SJacob Faibussowitsch {
395730356f6SLisandro Dalcin   PetscInt index;
396730356f6SLisandro Dalcin 
397730356f6SLisandro Dalcin   PetscFunctionBegin;
3989566063dSJacob Faibussowitsch   PetscCall(PetscHMapIGet(entities->entityMap[dim], eid, &index));
399730356f6SLisandro Dalcin   *entity = &entities->entity[dim][index];
4003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
401730356f6SLisandro Dalcin }
402730356f6SLisandro Dalcin 
4030598e1a2SLisandro Dalcin typedef struct {
4040598e1a2SLisandro Dalcin   PetscInt *id;  /* Node IDs */
4050598e1a2SLisandro Dalcin   double   *xyz; /* Coordinates */
40681a1af93SMatthew G. Knepley   PetscInt *tag; /* Physical tag */
4070598e1a2SLisandro Dalcin } GmshNodes;
4080598e1a2SLisandro Dalcin 
409d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshNodesCreate(PetscInt count, GmshNodes **nodes)
410d71ae5a4SJacob Faibussowitsch {
411730356f6SLisandro Dalcin   PetscFunctionBegin;
4129566063dSJacob Faibussowitsch   PetscCall(PetscNew(nodes));
4139566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(count * 1, &(*nodes)->id));
4149566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(count * 3, &(*nodes)->xyz));
4157d5b9244SMatthew G. Knepley   PetscCall(PetscMalloc1(count * GMSH_MAX_TAGS, &(*nodes)->tag));
4163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
417730356f6SLisandro Dalcin }
4180598e1a2SLisandro Dalcin 
419d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshNodesDestroy(GmshNodes **nodes)
420d71ae5a4SJacob Faibussowitsch {
4210598e1a2SLisandro Dalcin   PetscFunctionBegin;
4223ba16761SJacob Faibussowitsch   if (!*nodes) PetscFunctionReturn(PETSC_SUCCESS);
4239566063dSJacob Faibussowitsch   PetscCall(PetscFree((*nodes)->id));
4249566063dSJacob Faibussowitsch   PetscCall(PetscFree((*nodes)->xyz));
4259566063dSJacob Faibussowitsch   PetscCall(PetscFree((*nodes)->tag));
4269566063dSJacob Faibussowitsch   PetscCall(PetscFree((*nodes)));
4273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
428730356f6SLisandro Dalcin }
429730356f6SLisandro Dalcin 
430730356f6SLisandro Dalcin typedef struct {
4310598e1a2SLisandro Dalcin   PetscInt  id;                  /* Element ID */
4320598e1a2SLisandro Dalcin   PetscInt  dim;                 /* Dimension */
433de78e4feSLisandro Dalcin   PetscInt  cellType;            /* Cell type */
4340598e1a2SLisandro Dalcin   PetscInt  numVerts;            /* Size of vertex array */
435de78e4feSLisandro Dalcin   PetscInt  numNodes;            /* Size of node array */
4360598e1a2SLisandro Dalcin   PetscInt *nodes;               /* Vertex/Node array */
43781a1af93SMatthew G. Knepley   PetscInt  numTags;             /* Size of physical tag array */
4387d5b9244SMatthew G. Knepley   int       tags[GMSH_MAX_TAGS]; /* Physical tag array */
439de78e4feSLisandro Dalcin } GmshElement;
440de78e4feSLisandro Dalcin 
441d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshElementsCreate(PetscInt count, GmshElement **elements)
442d71ae5a4SJacob Faibussowitsch {
4430598e1a2SLisandro Dalcin   PetscFunctionBegin;
4449566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(count, elements));
4453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4460598e1a2SLisandro Dalcin }
4470598e1a2SLisandro Dalcin 
448d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshElementsDestroy(GmshElement **elements)
449d71ae5a4SJacob Faibussowitsch {
4500598e1a2SLisandro Dalcin   PetscFunctionBegin;
4513ba16761SJacob Faibussowitsch   if (!*elements) PetscFunctionReturn(PETSC_SUCCESS);
4529566063dSJacob Faibussowitsch   PetscCall(PetscFree(*elements));
4533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4540598e1a2SLisandro Dalcin }
4550598e1a2SLisandro Dalcin 
4560598e1a2SLisandro Dalcin typedef struct {
4570598e1a2SLisandro Dalcin   PetscInt       dim;
458066ea43fSLisandro Dalcin   PetscInt       order;
4590598e1a2SLisandro Dalcin   GmshEntities  *entities;
4600598e1a2SLisandro Dalcin   PetscInt       numNodes;
4610598e1a2SLisandro Dalcin   GmshNodes     *nodelist;
4620598e1a2SLisandro Dalcin   PetscInt       numElems;
4630598e1a2SLisandro Dalcin   GmshElement   *elements;
4640598e1a2SLisandro Dalcin   PetscInt       numVerts;
4650598e1a2SLisandro Dalcin   PetscInt       numCells;
4660598e1a2SLisandro Dalcin   PetscInt      *periodMap;
4670598e1a2SLisandro Dalcin   PetscInt      *vertexMap;
4680598e1a2SLisandro Dalcin   PetscSegBuffer segbuf;
469a45dabc8SMatthew G. Knepley   PetscInt       numRegions;
47090d778b8SLisandro Dalcin   PetscInt      *regionDims;
471a45dabc8SMatthew G. Knepley   PetscInt      *regionTags;
472a45dabc8SMatthew G. Knepley   char         **regionNames;
4730598e1a2SLisandro Dalcin } GmshMesh;
4740598e1a2SLisandro Dalcin 
475d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshMeshCreate(GmshMesh **mesh)
476d71ae5a4SJacob Faibussowitsch {
4770598e1a2SLisandro Dalcin   PetscFunctionBegin;
4789566063dSJacob Faibussowitsch   PetscCall(PetscNew(mesh));
4799566063dSJacob Faibussowitsch   PetscCall(PetscSegBufferCreate(sizeof(PetscInt), 0, &(*mesh)->segbuf));
4803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4810598e1a2SLisandro Dalcin }
4820598e1a2SLisandro Dalcin 
483d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshMeshDestroy(GmshMesh **mesh)
484d71ae5a4SJacob Faibussowitsch {
485a45dabc8SMatthew G. Knepley   PetscInt r;
4860598e1a2SLisandro Dalcin 
4870598e1a2SLisandro Dalcin   PetscFunctionBegin;
4883ba16761SJacob Faibussowitsch   if (!*mesh) PetscFunctionReturn(PETSC_SUCCESS);
4899566063dSJacob Faibussowitsch   PetscCall(GmshEntitiesDestroy(&(*mesh)->entities));
4909566063dSJacob Faibussowitsch   PetscCall(GmshNodesDestroy(&(*mesh)->nodelist));
4919566063dSJacob Faibussowitsch   PetscCall(GmshElementsDestroy(&(*mesh)->elements));
4929566063dSJacob Faibussowitsch   PetscCall(PetscFree((*mesh)->periodMap));
4939566063dSJacob Faibussowitsch   PetscCall(PetscFree((*mesh)->vertexMap));
4949566063dSJacob Faibussowitsch   PetscCall(PetscSegBufferDestroy(&(*mesh)->segbuf));
4959566063dSJacob Faibussowitsch   for (r = 0; r < (*mesh)->numRegions; ++r) PetscCall(PetscFree((*mesh)->regionNames[r]));
49690d778b8SLisandro Dalcin   PetscCall(PetscFree3((*mesh)->regionDims, (*mesh)->regionTags, (*mesh)->regionNames));
4979566063dSJacob Faibussowitsch   PetscCall(PetscFree((*mesh)));
4983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4990598e1a2SLisandro Dalcin }
5000598e1a2SLisandro Dalcin 
501d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadNodes_v22(GmshFile *gmsh, GmshMesh *mesh)
502d71ae5a4SJacob Faibussowitsch {
503698a79b9SLisandro Dalcin   PetscViewer viewer   = gmsh->viewer;
504698a79b9SLisandro Dalcin   PetscBool   byteSwap = gmsh->byteSwap;
505de78e4feSLisandro Dalcin   char        line[PETSC_MAX_PATH_LEN];
5067d5b9244SMatthew G. Knepley   int         n, t, num, nid, snum;
5070598e1a2SLisandro Dalcin   GmshNodes  *nodes;
508de78e4feSLisandro Dalcin 
509de78e4feSLisandro Dalcin   PetscFunctionBegin;
5109566063dSJacob Faibussowitsch   PetscCall(PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING));
511698a79b9SLisandro Dalcin   snum = sscanf(line, "%d", &num);
51208401ef6SPierre Jolivet   PetscCheck(snum == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
5139566063dSJacob Faibussowitsch   PetscCall(GmshNodesCreate(num, &nodes));
5140598e1a2SLisandro Dalcin   mesh->numNodes = num;
5150598e1a2SLisandro Dalcin   mesh->nodelist = nodes;
5160598e1a2SLisandro Dalcin   for (n = 0; n < num; ++n) {
5170598e1a2SLisandro Dalcin     double *xyz = nodes->xyz + n * 3;
5189566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, &nid, 1, NULL, PETSC_ENUM));
5199566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, xyz, 3, NULL, PETSC_DOUBLE));
5209566063dSJacob Faibussowitsch     if (byteSwap) PetscCall(PetscByteSwap(&nid, PETSC_ENUM, 1));
5219566063dSJacob Faibussowitsch     if (byteSwap) PetscCall(PetscByteSwap(xyz, PETSC_DOUBLE, 3));
5220598e1a2SLisandro Dalcin     nodes->id[n] = nid;
5237d5b9244SMatthew G. Knepley     for (t = 0; t < GMSH_MAX_TAGS; ++t) nodes->tag[n * GMSH_MAX_TAGS + t] = -1;
52411c56cb0SLisandro Dalcin   }
5253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
52611c56cb0SLisandro Dalcin }
52711c56cb0SLisandro Dalcin 
528de78e4feSLisandro Dalcin /* Gmsh elements can be of any dimension/co-dimension, so we need to traverse the
529de78e4feSLisandro Dalcin    file contents multiple times to figure out the true number of cells and facets
530de78e4feSLisandro Dalcin    in the given mesh. To make this more efficient we read the file contents only
531de78e4feSLisandro Dalcin    once and store them in memory, while determining the true number of cells. */
532d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadElements_v22(GmshFile *gmsh, GmshMesh *mesh)
533d71ae5a4SJacob Faibussowitsch {
534698a79b9SLisandro Dalcin   PetscViewer  viewer   = gmsh->viewer;
535698a79b9SLisandro Dalcin   PetscBool    binary   = gmsh->binary;
536698a79b9SLisandro Dalcin   PetscBool    byteSwap = gmsh->byteSwap;
537de78e4feSLisandro Dalcin   char         line[PETSC_MAX_PATH_LEN];
5380598e1a2SLisandro Dalcin   int          i, c, p, num, ibuf[1 + 4 + 1000], snum;
5390598e1a2SLisandro Dalcin   int          cellType, numElem, numVerts, numNodes, numTags;
540df032b82SMatthew G. Knepley   GmshElement *elements;
5410598e1a2SLisandro Dalcin   PetscInt    *nodeMap = gmsh->nodeMap;
542df032b82SMatthew G. Knepley 
543df032b82SMatthew G. Knepley   PetscFunctionBegin;
5449566063dSJacob Faibussowitsch   PetscCall(PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING));
545698a79b9SLisandro Dalcin   snum = sscanf(line, "%d", &num);
54608401ef6SPierre Jolivet   PetscCheck(snum == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
5479566063dSJacob Faibussowitsch   PetscCall(GmshElementsCreate(num, &elements));
5480598e1a2SLisandro Dalcin   mesh->numElems = num;
5490598e1a2SLisandro Dalcin   mesh->elements = elements;
550698a79b9SLisandro Dalcin   for (c = 0; c < num;) {
5519566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, ibuf, 3, NULL, PETSC_ENUM));
5529566063dSJacob Faibussowitsch     if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, 3));
5530598e1a2SLisandro Dalcin 
5540598e1a2SLisandro Dalcin     cellType = binary ? ibuf[0] : ibuf[1];
5550598e1a2SLisandro Dalcin     numElem  = binary ? ibuf[1] : 1;
556df032b82SMatthew G. Knepley     numTags  = ibuf[2];
5570598e1a2SLisandro Dalcin 
5589566063dSJacob Faibussowitsch     PetscCall(GmshCellTypeCheck(cellType));
5590598e1a2SLisandro Dalcin     numVerts = GmshCellMap[cellType].numVerts;
5600598e1a2SLisandro Dalcin     numNodes = GmshCellMap[cellType].numNodes;
5610598e1a2SLisandro Dalcin 
562df032b82SMatthew G. Knepley     for (i = 0; i < numElem; ++i, ++c) {
5630598e1a2SLisandro Dalcin       GmshElement *element = elements + c;
5640598e1a2SLisandro Dalcin       const int    off = binary ? 0 : 1, nint = 1 + numTags + numNodes - off;
5650598e1a2SLisandro Dalcin       const int   *id = ibuf, *nodes = ibuf + 1 + numTags, *tags = ibuf + 1;
5669566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, ibuf + off, nint, NULL, PETSC_ENUM));
5679566063dSJacob Faibussowitsch       if (byteSwap) PetscCall(PetscByteSwap(ibuf + off, PETSC_ENUM, nint));
5680598e1a2SLisandro Dalcin       element->id       = id[0];
5690598e1a2SLisandro Dalcin       element->dim      = GmshCellMap[cellType].dim;
5700598e1a2SLisandro Dalcin       element->cellType = cellType;
5710598e1a2SLisandro Dalcin       element->numVerts = numVerts;
5720598e1a2SLisandro Dalcin       element->numNodes = numNodes;
5737d5b9244SMatthew G. Knepley       element->numTags  = PetscMin(numTags, GMSH_MAX_TAGS);
5749566063dSJacob Faibussowitsch       PetscCall(PetscSegBufferGet(mesh->segbuf, (size_t)element->numNodes, &element->nodes));
5750598e1a2SLisandro Dalcin       for (p = 0; p < element->numNodes; p++) element->nodes[p] = nodeMap[nodes[p]];
5760598e1a2SLisandro Dalcin       for (p = 0; p < element->numTags; p++) element->tags[p] = tags[p];
577df032b82SMatthew G. Knepley     }
578df032b82SMatthew G. Knepley   }
5793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
580df032b82SMatthew G. Knepley }
5817d282ae0SMichael Lange 
582de78e4feSLisandro Dalcin /*
583de78e4feSLisandro Dalcin $Entities
584de78e4feSLisandro Dalcin   numPoints(unsigned long) numCurves(unsigned long)
585de78e4feSLisandro Dalcin     numSurfaces(unsigned long) numVolumes(unsigned long)
586de78e4feSLisandro Dalcin   // points
587de78e4feSLisandro Dalcin   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
588de78e4feSLisandro Dalcin     boxMaxX(double) boxMaxY(double) boxMaxZ(double)
589de78e4feSLisandro Dalcin     numPhysicals(unsigned long) phyisicalTag[...](int)
590de78e4feSLisandro Dalcin   ...
591de78e4feSLisandro Dalcin   // curves
592de78e4feSLisandro Dalcin   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
593de78e4feSLisandro Dalcin      boxMaxX(double) boxMaxY(double) boxMaxZ(double)
594de78e4feSLisandro Dalcin      numPhysicals(unsigned long) physicalTag[...](int)
595de78e4feSLisandro Dalcin      numBREPVert(unsigned long) tagBREPVert[...](int)
596de78e4feSLisandro Dalcin   ...
597de78e4feSLisandro Dalcin   // surfaces
598de78e4feSLisandro Dalcin   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
599de78e4feSLisandro Dalcin     boxMaxX(double) boxMaxY(double) boxMaxZ(double)
600de78e4feSLisandro Dalcin     numPhysicals(unsigned long) physicalTag[...](int)
601de78e4feSLisandro Dalcin     numBREPCurve(unsigned long) tagBREPCurve[...](int)
602de78e4feSLisandro Dalcin   ...
603de78e4feSLisandro Dalcin   // volumes
604de78e4feSLisandro Dalcin   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
605de78e4feSLisandro Dalcin     boxMaxX(double) boxMaxY(double) boxMaxZ(double)
606de78e4feSLisandro Dalcin     numPhysicals(unsigned long) physicalTag[...](int)
607de78e4feSLisandro Dalcin     numBREPSurfaces(unsigned long) tagBREPSurfaces[...](int)
608de78e4feSLisandro Dalcin   ...
609de78e4feSLisandro Dalcin $EndEntities
610de78e4feSLisandro Dalcin */
611d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadEntities_v40(GmshFile *gmsh, GmshMesh *mesh)
612d71ae5a4SJacob Faibussowitsch {
613698a79b9SLisandro Dalcin   PetscViewer viewer   = gmsh->viewer;
614698a79b9SLisandro Dalcin   PetscBool   byteSwap = gmsh->byteSwap;
615698a79b9SLisandro Dalcin   long        index, num, lbuf[4];
616730356f6SLisandro Dalcin   int         dim, eid, numTags, *ibuf, t;
617698a79b9SLisandro Dalcin   PetscInt    count[4], i;
618a5ba3d71SLisandro Dalcin   GmshEntity *entity = NULL;
619de78e4feSLisandro Dalcin 
620de78e4feSLisandro Dalcin   PetscFunctionBegin;
6219566063dSJacob Faibussowitsch   PetscCall(PetscViewerRead(viewer, lbuf, 4, NULL, PETSC_LONG));
6229566063dSJacob Faibussowitsch   if (byteSwap) PetscCall(PetscByteSwap(lbuf, PETSC_LONG, 4));
623698a79b9SLisandro Dalcin   for (i = 0; i < 4; ++i) count[i] = lbuf[i];
6249566063dSJacob Faibussowitsch   PetscCall(GmshEntitiesCreate(count, &mesh->entities));
625de78e4feSLisandro Dalcin   for (dim = 0; dim < 4; ++dim) {
626730356f6SLisandro Dalcin     for (index = 0; index < count[dim]; ++index) {
6279566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, &eid, 1, NULL, PETSC_ENUM));
6289566063dSJacob Faibussowitsch       if (byteSwap) PetscCall(PetscByteSwap(&eid, PETSC_ENUM, 1));
6299566063dSJacob Faibussowitsch       PetscCall(GmshEntitiesAdd(mesh->entities, (PetscInt)index, dim, eid, &entity));
6309566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, entity->bbox, 6, NULL, PETSC_DOUBLE));
6319566063dSJacob Faibussowitsch       if (byteSwap) PetscCall(PetscByteSwap(entity->bbox, PETSC_DOUBLE, 6));
6329566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, &num, 1, NULL, PETSC_LONG));
6339566063dSJacob Faibussowitsch       if (byteSwap) PetscCall(PetscByteSwap(&num, PETSC_LONG, 1));
6349566063dSJacob Faibussowitsch       PetscCall(GmshBufferGet(gmsh, num, sizeof(int), &ibuf));
6359566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, ibuf, num, NULL, PETSC_ENUM));
6369566063dSJacob Faibussowitsch       if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, num));
6377d5b9244SMatthew G. Knepley       entity->numTags = numTags = (int)PetscMin(num, GMSH_MAX_TAGS);
638de78e4feSLisandro Dalcin       for (t = 0; t < numTags; ++t) entity->tags[t] = ibuf[t];
639de78e4feSLisandro Dalcin       if (dim == 0) continue;
6409566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, &num, 1, NULL, PETSC_LONG));
6419566063dSJacob Faibussowitsch       if (byteSwap) PetscCall(PetscByteSwap(&num, PETSC_LONG, 1));
6429566063dSJacob Faibussowitsch       PetscCall(GmshBufferGet(gmsh, num, sizeof(int), &ibuf));
6439566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, ibuf, num, NULL, PETSC_ENUM));
6449566063dSJacob Faibussowitsch       if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, num));
645de78e4feSLisandro Dalcin     }
646de78e4feSLisandro Dalcin   }
6473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
648de78e4feSLisandro Dalcin }
649de78e4feSLisandro Dalcin 
650de78e4feSLisandro Dalcin /*
651de78e4feSLisandro Dalcin $Nodes
652de78e4feSLisandro Dalcin   numEntityBlocks(unsigned long) numNodes(unsigned long)
653de78e4feSLisandro Dalcin   tagEntity(int) dimEntity(int) typeNode(int) numNodes(unsigned long)
654de78e4feSLisandro Dalcin     tag(int) x(double) y(double) z(double)
655de78e4feSLisandro Dalcin     ...
656de78e4feSLisandro Dalcin   ...
657de78e4feSLisandro Dalcin $EndNodes
658de78e4feSLisandro Dalcin */
659d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadNodes_v40(GmshFile *gmsh, GmshMesh *mesh)
660d71ae5a4SJacob Faibussowitsch {
661698a79b9SLisandro Dalcin   PetscViewer viewer   = gmsh->viewer;
662698a79b9SLisandro Dalcin   PetscBool   byteSwap = gmsh->byteSwap;
6637d5b9244SMatthew G. Knepley   long        block, node, n, t, numEntityBlocks, numTotalNodes, numNodes;
664de78e4feSLisandro Dalcin   int         info[3], nid;
6650598e1a2SLisandro Dalcin   GmshNodes  *nodes;
666de78e4feSLisandro Dalcin 
667de78e4feSLisandro Dalcin   PetscFunctionBegin;
6689566063dSJacob Faibussowitsch   PetscCall(PetscViewerRead(viewer, &numEntityBlocks, 1, NULL, PETSC_LONG));
6699566063dSJacob Faibussowitsch   if (byteSwap) PetscCall(PetscByteSwap(&numEntityBlocks, PETSC_LONG, 1));
6709566063dSJacob Faibussowitsch   PetscCall(PetscViewerRead(viewer, &numTotalNodes, 1, NULL, PETSC_LONG));
6719566063dSJacob Faibussowitsch   if (byteSwap) PetscCall(PetscByteSwap(&numTotalNodes, PETSC_LONG, 1));
6729566063dSJacob Faibussowitsch   PetscCall(GmshNodesCreate(numTotalNodes, &nodes));
6730598e1a2SLisandro Dalcin   mesh->numNodes = numTotalNodes;
6740598e1a2SLisandro Dalcin   mesh->nodelist = nodes;
6750598e1a2SLisandro Dalcin   for (n = 0, block = 0; block < numEntityBlocks; ++block) {
6769566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, info, 3, NULL, PETSC_ENUM));
6779566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, &numNodes, 1, NULL, PETSC_LONG));
6789566063dSJacob Faibussowitsch     if (byteSwap) PetscCall(PetscByteSwap(&numNodes, PETSC_LONG, 1));
679698a79b9SLisandro Dalcin     if (gmsh->binary) {
680277f51e8SBarry Smith       size_t nbytes = sizeof(int) + 3 * sizeof(double);
681da81f932SPierre Jolivet       char  *cbuf   = NULL; /* dummy value to prevent warning from compiler about possible uninitialized value */
6829566063dSJacob Faibussowitsch       PetscCall(GmshBufferGet(gmsh, numNodes, nbytes, &cbuf));
6839566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, cbuf, numNodes * nbytes, NULL, PETSC_CHAR));
6840598e1a2SLisandro Dalcin       for (node = 0; node < numNodes; ++node, ++n) {
685de78e4feSLisandro Dalcin         char   *cnid = cbuf + node * nbytes, *cxyz = cnid + sizeof(int);
6860598e1a2SLisandro Dalcin         double *xyz = nodes->xyz + n * 3;
6879566063dSJacob Faibussowitsch         if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(cnid, PETSC_ENUM, 1));
6889566063dSJacob Faibussowitsch         if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(cxyz, PETSC_DOUBLE, 3));
6899566063dSJacob Faibussowitsch         PetscCall(PetscMemcpy(&nid, cnid, sizeof(int)));
6909566063dSJacob Faibussowitsch         PetscCall(PetscMemcpy(xyz, cxyz, 3 * sizeof(double)));
6919566063dSJacob Faibussowitsch         if (byteSwap) PetscCall(PetscByteSwap(&nid, PETSC_ENUM, 1));
6929566063dSJacob Faibussowitsch         if (byteSwap) PetscCall(PetscByteSwap(xyz, PETSC_DOUBLE, 3));
6930598e1a2SLisandro Dalcin         nodes->id[n] = nid;
6947d5b9244SMatthew G. Knepley         for (t = 0; t < GMSH_MAX_TAGS; ++t) nodes->tag[n * GMSH_MAX_TAGS + t] = -1;
695de78e4feSLisandro Dalcin       }
696de78e4feSLisandro Dalcin     } else {
6970598e1a2SLisandro Dalcin       for (node = 0; node < numNodes; ++node, ++n) {
6980598e1a2SLisandro Dalcin         double *xyz = nodes->xyz + n * 3;
6999566063dSJacob Faibussowitsch         PetscCall(PetscViewerRead(viewer, &nid, 1, NULL, PETSC_ENUM));
7009566063dSJacob Faibussowitsch         PetscCall(PetscViewerRead(viewer, xyz, 3, NULL, PETSC_DOUBLE));
7019566063dSJacob Faibussowitsch         if (byteSwap) PetscCall(PetscByteSwap(&nid, PETSC_ENUM, 1));
7029566063dSJacob Faibussowitsch         if (byteSwap) PetscCall(PetscByteSwap(xyz, PETSC_DOUBLE, 3));
7030598e1a2SLisandro Dalcin         nodes->id[n] = nid;
7047d5b9244SMatthew G. Knepley         for (t = 0; t < GMSH_MAX_TAGS; ++t) nodes->tag[n * GMSH_MAX_TAGS + t] = -1;
705de78e4feSLisandro Dalcin       }
706de78e4feSLisandro Dalcin     }
707de78e4feSLisandro Dalcin   }
7083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
709de78e4feSLisandro Dalcin }
710de78e4feSLisandro Dalcin 
711de78e4feSLisandro Dalcin /*
712de78e4feSLisandro Dalcin $Elements
713de78e4feSLisandro Dalcin   numEntityBlocks(unsigned long) numElements(unsigned long)
714de78e4feSLisandro Dalcin   tagEntity(int) dimEntity(int) typeEle(int) numElements(unsigned long)
715de78e4feSLisandro Dalcin     tag(int) numVert[...](int)
716de78e4feSLisandro Dalcin     ...
717de78e4feSLisandro Dalcin   ...
718de78e4feSLisandro Dalcin $EndElements
719de78e4feSLisandro Dalcin */
720d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadElements_v40(GmshFile *gmsh, GmshMesh *mesh)
721d71ae5a4SJacob Faibussowitsch {
722698a79b9SLisandro Dalcin   PetscViewer  viewer   = gmsh->viewer;
723698a79b9SLisandro Dalcin   PetscBool    byteSwap = gmsh->byteSwap;
724de78e4feSLisandro Dalcin   long         c, block, numEntityBlocks, numTotalElements, elem, numElements;
725de78e4feSLisandro Dalcin   int          p, info[3], *ibuf = NULL;
7260598e1a2SLisandro Dalcin   int          eid, dim, cellType, numVerts, numNodes, numTags;
727a5ba3d71SLisandro Dalcin   GmshEntity  *entity = NULL;
728de78e4feSLisandro Dalcin   GmshElement *elements;
7290598e1a2SLisandro Dalcin   PetscInt    *nodeMap = gmsh->nodeMap;
730de78e4feSLisandro Dalcin 
731de78e4feSLisandro Dalcin   PetscFunctionBegin;
7329566063dSJacob Faibussowitsch   PetscCall(PetscViewerRead(viewer, &numEntityBlocks, 1, NULL, PETSC_LONG));
7339566063dSJacob Faibussowitsch   if (byteSwap) PetscCall(PetscByteSwap(&numEntityBlocks, PETSC_LONG, 1));
7349566063dSJacob Faibussowitsch   PetscCall(PetscViewerRead(viewer, &numTotalElements, 1, NULL, PETSC_LONG));
7359566063dSJacob Faibussowitsch   if (byteSwap) PetscCall(PetscByteSwap(&numTotalElements, PETSC_LONG, 1));
7369566063dSJacob Faibussowitsch   PetscCall(GmshElementsCreate(numTotalElements, &elements));
7370598e1a2SLisandro Dalcin   mesh->numElems = numTotalElements;
7380598e1a2SLisandro Dalcin   mesh->elements = elements;
739de78e4feSLisandro Dalcin   for (c = 0, block = 0; block < numEntityBlocks; ++block) {
7409566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, info, 3, NULL, PETSC_ENUM));
7419566063dSJacob Faibussowitsch     if (byteSwap) PetscCall(PetscByteSwap(info, PETSC_ENUM, 3));
7429371c9d4SSatish Balay     eid      = info[0];
7439371c9d4SSatish Balay     dim      = info[1];
7449371c9d4SSatish Balay     cellType = info[2];
7459566063dSJacob Faibussowitsch     PetscCall(GmshEntitiesGet(mesh->entities, dim, eid, &entity));
7469566063dSJacob Faibussowitsch     PetscCall(GmshCellTypeCheck(cellType));
7470598e1a2SLisandro Dalcin     numVerts = GmshCellMap[cellType].numVerts;
7480598e1a2SLisandro Dalcin     numNodes = GmshCellMap[cellType].numNodes;
749730356f6SLisandro Dalcin     numTags  = entity->numTags;
7509566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, &numElements, 1, NULL, PETSC_LONG));
7519566063dSJacob Faibussowitsch     if (byteSwap) PetscCall(PetscByteSwap(&numElements, PETSC_LONG, 1));
7529566063dSJacob Faibussowitsch     PetscCall(GmshBufferGet(gmsh, (1 + numNodes) * numElements, sizeof(int), &ibuf));
7539566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, ibuf, (1 + numNodes) * numElements, NULL, PETSC_ENUM));
7549566063dSJacob Faibussowitsch     if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, (1 + numNodes) * numElements));
755de78e4feSLisandro Dalcin     for (elem = 0; elem < numElements; ++elem, ++c) {
756de78e4feSLisandro Dalcin       GmshElement *element = elements + c;
7570598e1a2SLisandro Dalcin       const int   *id = ibuf + elem * (1 + numNodes), *nodes = id + 1;
7580598e1a2SLisandro Dalcin       element->id       = id[0];
759de78e4feSLisandro Dalcin       element->dim      = dim;
760de78e4feSLisandro Dalcin       element->cellType = cellType;
7610598e1a2SLisandro Dalcin       element->numVerts = numVerts;
762de78e4feSLisandro Dalcin       element->numNodes = numNodes;
763de78e4feSLisandro Dalcin       element->numTags  = numTags;
7649566063dSJacob Faibussowitsch       PetscCall(PetscSegBufferGet(mesh->segbuf, (size_t)element->numNodes, &element->nodes));
7650598e1a2SLisandro Dalcin       for (p = 0; p < element->numNodes; p++) element->nodes[p] = nodeMap[nodes[p]];
7660598e1a2SLisandro Dalcin       for (p = 0; p < element->numTags; p++) element->tags[p] = entity->tags[p];
767de78e4feSLisandro Dalcin     }
768de78e4feSLisandro Dalcin   }
7693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
770698a79b9SLisandro Dalcin }
771698a79b9SLisandro Dalcin 
772d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadPeriodic_v40(GmshFile *gmsh, PetscInt periodicMap[])
773d71ae5a4SJacob Faibussowitsch {
774698a79b9SLisandro Dalcin   PetscViewer viewer     = gmsh->viewer;
775698a79b9SLisandro Dalcin   int         fileFormat = gmsh->fileFormat;
776698a79b9SLisandro Dalcin   PetscBool   binary     = gmsh->binary;
777698a79b9SLisandro Dalcin   PetscBool   byteSwap   = gmsh->byteSwap;
778698a79b9SLisandro Dalcin   int         numPeriodic, snum, i;
779698a79b9SLisandro Dalcin   char        line[PETSC_MAX_PATH_LEN];
7800598e1a2SLisandro Dalcin   PetscInt   *nodeMap = gmsh->nodeMap;
781698a79b9SLisandro Dalcin 
782698a79b9SLisandro Dalcin   PetscFunctionBegin;
783698a79b9SLisandro Dalcin   if (fileFormat == 22 || !binary) {
7849566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING));
785698a79b9SLisandro Dalcin     snum = sscanf(line, "%d", &numPeriodic);
78608401ef6SPierre Jolivet     PetscCheck(snum == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
787698a79b9SLisandro Dalcin   } else {
7889566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, &numPeriodic, 1, NULL, PETSC_ENUM));
7899566063dSJacob Faibussowitsch     if (byteSwap) PetscCall(PetscByteSwap(&numPeriodic, PETSC_ENUM, 1));
790698a79b9SLisandro Dalcin   }
791698a79b9SLisandro Dalcin   for (i = 0; i < numPeriodic; i++) {
7929dddd249SSatish Balay     int    ibuf[3], correspondingDim = -1, correspondingTag = -1, primaryTag = -1, correspondingNode, primaryNode;
793698a79b9SLisandro Dalcin     long   j, nNodes;
794698a79b9SLisandro Dalcin     double affine[16];
795698a79b9SLisandro Dalcin 
796698a79b9SLisandro Dalcin     if (fileFormat == 22 || !binary) {
7979566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, line, 3, NULL, PETSC_STRING));
7989dddd249SSatish Balay       snum = sscanf(line, "%d %d %d", &correspondingDim, &correspondingTag, &primaryTag);
79908401ef6SPierre Jolivet       PetscCheck(snum == 3, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
800698a79b9SLisandro Dalcin     } else {
8019566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, ibuf, 3, NULL, PETSC_ENUM));
8029566063dSJacob Faibussowitsch       if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, 3));
8039371c9d4SSatish Balay       correspondingDim = ibuf[0];
8049371c9d4SSatish Balay       correspondingTag = ibuf[1];
8059371c9d4SSatish Balay       primaryTag       = ibuf[2];
806698a79b9SLisandro Dalcin     }
8079371c9d4SSatish Balay     (void)correspondingDim;
8089371c9d4SSatish Balay     (void)correspondingTag;
8099371c9d4SSatish Balay     (void)primaryTag; /* unused */
810698a79b9SLisandro Dalcin 
811698a79b9SLisandro Dalcin     if (fileFormat == 22 || !binary) {
8129566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING));
813698a79b9SLisandro Dalcin       snum = sscanf(line, "%ld", &nNodes);
8144c500f23SPierre Jolivet       if (snum != 1) { /* discard transformation and try again */
8159566063dSJacob Faibussowitsch         PetscCall(PetscViewerRead(viewer, line, -PETSC_MAX_PATH_LEN, NULL, PETSC_STRING));
8169566063dSJacob Faibussowitsch         PetscCall(PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING));
817698a79b9SLisandro Dalcin         snum = sscanf(line, "%ld", &nNodes);
81808401ef6SPierre Jolivet         PetscCheck(snum == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
819698a79b9SLisandro Dalcin       }
820698a79b9SLisandro Dalcin     } else {
8219566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, &nNodes, 1, NULL, PETSC_LONG));
8229566063dSJacob Faibussowitsch       if (byteSwap) PetscCall(PetscByteSwap(&nNodes, PETSC_LONG, 1));
8234c500f23SPierre Jolivet       if (nNodes == -1) { /* discard transformation and try again */
8249566063dSJacob Faibussowitsch         PetscCall(PetscViewerRead(viewer, affine, 16, NULL, PETSC_DOUBLE));
8259566063dSJacob Faibussowitsch         PetscCall(PetscViewerRead(viewer, &nNodes, 1, NULL, PETSC_LONG));
8269566063dSJacob Faibussowitsch         if (byteSwap) PetscCall(PetscByteSwap(&nNodes, PETSC_LONG, 1));
827698a79b9SLisandro Dalcin       }
828698a79b9SLisandro Dalcin     }
829698a79b9SLisandro Dalcin 
830698a79b9SLisandro Dalcin     for (j = 0; j < nNodes; j++) {
831698a79b9SLisandro Dalcin       if (fileFormat == 22 || !binary) {
8329566063dSJacob Faibussowitsch         PetscCall(PetscViewerRead(viewer, line, 2, NULL, PETSC_STRING));
8339dddd249SSatish Balay         snum = sscanf(line, "%d %d", &correspondingNode, &primaryNode);
83408401ef6SPierre Jolivet         PetscCheck(snum == 2, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
835698a79b9SLisandro Dalcin       } else {
8369566063dSJacob Faibussowitsch         PetscCall(PetscViewerRead(viewer, ibuf, 2, NULL, PETSC_ENUM));
8379566063dSJacob Faibussowitsch         if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, 2));
8389371c9d4SSatish Balay         correspondingNode = ibuf[0];
8399371c9d4SSatish Balay         primaryNode       = ibuf[1];
840698a79b9SLisandro Dalcin       }
8419dddd249SSatish Balay       correspondingNode              = (int)nodeMap[correspondingNode];
8429dddd249SSatish Balay       primaryNode                    = (int)nodeMap[primaryNode];
8439dddd249SSatish Balay       periodicMap[correspondingNode] = primaryNode;
844698a79b9SLisandro Dalcin     }
845698a79b9SLisandro Dalcin   }
8463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
847698a79b9SLisandro Dalcin }
848698a79b9SLisandro Dalcin 
8490598e1a2SLisandro Dalcin /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
850698a79b9SLisandro Dalcin $Entities
851698a79b9SLisandro Dalcin   numPoints(size_t) numCurves(size_t)
852698a79b9SLisandro Dalcin     numSurfaces(size_t) numVolumes(size_t)
853698a79b9SLisandro Dalcin   pointTag(int) X(double) Y(double) Z(double)
854698a79b9SLisandro Dalcin     numPhysicalTags(size_t) physicalTag(int) ...
855698a79b9SLisandro Dalcin   ...
856698a79b9SLisandro Dalcin   curveTag(int) minX(double) minY(double) minZ(double)
857698a79b9SLisandro Dalcin     maxX(double) maxY(double) maxZ(double)
858698a79b9SLisandro Dalcin     numPhysicalTags(size_t) physicalTag(int) ...
859698a79b9SLisandro Dalcin     numBoundingPoints(size_t) pointTag(int) ...
860698a79b9SLisandro Dalcin   ...
861698a79b9SLisandro Dalcin   surfaceTag(int) minX(double) minY(double) minZ(double)
862698a79b9SLisandro Dalcin     maxX(double) maxY(double) maxZ(double)
863698a79b9SLisandro Dalcin     numPhysicalTags(size_t) physicalTag(int) ...
864698a79b9SLisandro Dalcin     numBoundingCurves(size_t) curveTag(int) ...
865698a79b9SLisandro Dalcin   ...
866698a79b9SLisandro Dalcin   volumeTag(int) minX(double) minY(double) minZ(double)
867698a79b9SLisandro Dalcin     maxX(double) maxY(double) maxZ(double)
868698a79b9SLisandro Dalcin     numPhysicalTags(size_t) physicalTag(int) ...
869698a79b9SLisandro Dalcin     numBoundngSurfaces(size_t) surfaceTag(int) ...
870698a79b9SLisandro Dalcin   ...
871698a79b9SLisandro Dalcin $EndEntities
872698a79b9SLisandro Dalcin */
873d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadEntities_v41(GmshFile *gmsh, GmshMesh *mesh)
874d71ae5a4SJacob Faibussowitsch {
875698a79b9SLisandro Dalcin   PetscInt    count[4], index, numTags, i;
876698a79b9SLisandro Dalcin   int         dim, eid, *tags = NULL;
877698a79b9SLisandro Dalcin   GmshEntity *entity = NULL;
878698a79b9SLisandro Dalcin 
879698a79b9SLisandro Dalcin   PetscFunctionBegin;
8809566063dSJacob Faibussowitsch   PetscCall(GmshReadSize(gmsh, count, 4));
8819566063dSJacob Faibussowitsch   PetscCall(GmshEntitiesCreate(count, &mesh->entities));
882698a79b9SLisandro Dalcin   for (dim = 0; dim < 4; ++dim) {
883698a79b9SLisandro Dalcin     for (index = 0; index < count[dim]; ++index) {
8849566063dSJacob Faibussowitsch       PetscCall(GmshReadInt(gmsh, &eid, 1));
8859566063dSJacob Faibussowitsch       PetscCall(GmshEntitiesAdd(mesh->entities, (PetscInt)index, dim, eid, &entity));
8869566063dSJacob Faibussowitsch       PetscCall(GmshReadDouble(gmsh, entity->bbox, (dim == 0) ? 3 : 6));
8879566063dSJacob Faibussowitsch       PetscCall(GmshReadSize(gmsh, &numTags, 1));
8889566063dSJacob Faibussowitsch       PetscCall(GmshBufferGet(gmsh, numTags, sizeof(int), &tags));
8899566063dSJacob Faibussowitsch       PetscCall(GmshReadInt(gmsh, tags, numTags));
8909c0edc59SMatthew G. Knepley       PetscCheck(numTags <= GMSH_MAX_TAGS, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "PETSc currently supports up to %" PetscInt_FMT " tags per entity, not %" PetscInt_FMT, (PetscInt)GMSH_MAX_TAGS, numTags);
8917d5b9244SMatthew G. Knepley       entity->numTags = numTags;
892698a79b9SLisandro Dalcin       for (i = 0; i < entity->numTags; ++i) entity->tags[i] = tags[i];
893698a79b9SLisandro Dalcin       if (dim == 0) continue;
8949566063dSJacob Faibussowitsch       PetscCall(GmshReadSize(gmsh, &numTags, 1));
8959566063dSJacob Faibussowitsch       PetscCall(GmshBufferGet(gmsh, numTags, sizeof(int), &tags));
8969566063dSJacob Faibussowitsch       PetscCall(GmshReadInt(gmsh, tags, numTags));
89781a1af93SMatthew G. Knepley       /* Currently, we do not save the ids for the bounding entities */
898698a79b9SLisandro Dalcin     }
899698a79b9SLisandro Dalcin   }
9003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
901698a79b9SLisandro Dalcin }
902698a79b9SLisandro Dalcin 
90333a088b6SMatthew G. Knepley /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
904698a79b9SLisandro Dalcin $Nodes
905698a79b9SLisandro Dalcin   numEntityBlocks(size_t) numNodes(size_t)
906698a79b9SLisandro Dalcin     minNodeTag(size_t) maxNodeTag(size_t)
907698a79b9SLisandro Dalcin   entityDim(int) entityTag(int) parametric(int; 0 or 1) numNodesBlock(size_t)
908698a79b9SLisandro Dalcin     nodeTag(size_t)
909698a79b9SLisandro Dalcin     ...
910698a79b9SLisandro Dalcin     x(double) y(double) z(double)
911698a79b9SLisandro Dalcin        < u(double; if parametric and entityDim = 1 or entityDim = 2) >
912698a79b9SLisandro Dalcin        < v(double; if parametric and entityDim = 2) >
913698a79b9SLisandro Dalcin     ...
914698a79b9SLisandro Dalcin   ...
915698a79b9SLisandro Dalcin $EndNodes
916698a79b9SLisandro Dalcin */
917d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadNodes_v41(GmshFile *gmsh, GmshMesh *mesh)
918d71ae5a4SJacob Faibussowitsch {
91981a1af93SMatthew G. Knepley   int         info[3], dim, eid, parametric;
9207d5b9244SMatthew G. Knepley   PetscInt    sizes[4], numEntityBlocks, numTags, t, numNodes, numNodesBlock = 0, block, node, n;
92181a1af93SMatthew G. Knepley   GmshEntity *entity = NULL;
9220598e1a2SLisandro Dalcin   GmshNodes  *nodes;
923698a79b9SLisandro Dalcin 
924698a79b9SLisandro Dalcin   PetscFunctionBegin;
9259566063dSJacob Faibussowitsch   PetscCall(GmshReadSize(gmsh, sizes, 4));
9269371c9d4SSatish Balay   numEntityBlocks = sizes[0];
9279371c9d4SSatish Balay   numNodes        = sizes[1];
9289566063dSJacob Faibussowitsch   PetscCall(GmshNodesCreate(numNodes, &nodes));
9290598e1a2SLisandro Dalcin   mesh->numNodes = numNodes;
9300598e1a2SLisandro Dalcin   mesh->nodelist = nodes;
931698a79b9SLisandro Dalcin   for (block = 0, node = 0; block < numEntityBlocks; ++block, node += numNodesBlock) {
9329566063dSJacob Faibussowitsch     PetscCall(GmshReadInt(gmsh, info, 3));
9339371c9d4SSatish Balay     dim        = info[0];
9349371c9d4SSatish Balay     eid        = info[1];
9359371c9d4SSatish Balay     parametric = info[2];
9369566063dSJacob Faibussowitsch     PetscCall(GmshEntitiesGet(mesh->entities, dim, eid, &entity));
9377d5b9244SMatthew G. Knepley     numTags = entity->numTags;
93881a1af93SMatthew G. Knepley     PetscCheck(!parametric, PETSC_COMM_SELF, PETSC_ERR_SUP, "Parametric coordinates not supported");
9399566063dSJacob Faibussowitsch     PetscCall(GmshReadSize(gmsh, &numNodesBlock, 1));
9409566063dSJacob Faibussowitsch     PetscCall(GmshReadSize(gmsh, nodes->id + node, numNodesBlock));
9419566063dSJacob Faibussowitsch     PetscCall(GmshReadDouble(gmsh, nodes->xyz + node * 3, numNodesBlock * 3));
9427d5b9244SMatthew G. Knepley     for (n = 0; n < numNodesBlock; ++n) {
9437d5b9244SMatthew G. Knepley       PetscInt *tags = &nodes->tag[node * GMSH_MAX_TAGS];
9447d5b9244SMatthew G. Knepley 
9457d5b9244SMatthew G. Knepley       for (t = 0; t < numTags; ++t) tags[n * GMSH_MAX_TAGS + t] = entity->tags[t];
9467d5b9244SMatthew G. Knepley       for (t = numTags; t < GMSH_MAX_TAGS; ++t) tags[n * GMSH_MAX_TAGS + t] = -1;
9477d5b9244SMatthew G. Knepley     }
948698a79b9SLisandro Dalcin   }
9490598e1a2SLisandro Dalcin   gmsh->nodeStart = sizes[2];
9500598e1a2SLisandro Dalcin   gmsh->nodeEnd   = sizes[3] + 1;
9513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
952698a79b9SLisandro Dalcin }
953698a79b9SLisandro Dalcin 
95433a088b6SMatthew G. Knepley /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
955698a79b9SLisandro Dalcin $Elements
956698a79b9SLisandro Dalcin   numEntityBlocks(size_t) numElements(size_t)
957698a79b9SLisandro Dalcin     minElementTag(size_t) maxElementTag(size_t)
958698a79b9SLisandro Dalcin   entityDim(int) entityTag(int) elementType(int; see below) numElementsBlock(size_t)
959698a79b9SLisandro Dalcin     elementTag(size_t) nodeTag(size_t) ...
960698a79b9SLisandro Dalcin     ...
961698a79b9SLisandro Dalcin   ...
962698a79b9SLisandro Dalcin $EndElements
963698a79b9SLisandro Dalcin */
964d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadElements_v41(GmshFile *gmsh, GmshMesh *mesh)
965d71ae5a4SJacob Faibussowitsch {
9660598e1a2SLisandro Dalcin   int          info[3], eid, dim, cellType;
9670598e1a2SLisandro Dalcin   PetscInt     sizes[4], *ibuf = NULL, numEntityBlocks, numElements, numBlockElements, numVerts, numNodes, numTags, block, elem, c, p;
968698a79b9SLisandro Dalcin   GmshEntity  *entity = NULL;
969698a79b9SLisandro Dalcin   GmshElement *elements;
9700598e1a2SLisandro Dalcin   PetscInt    *nodeMap = gmsh->nodeMap;
971698a79b9SLisandro Dalcin 
972698a79b9SLisandro Dalcin   PetscFunctionBegin;
9739566063dSJacob Faibussowitsch   PetscCall(GmshReadSize(gmsh, sizes, 4));
9749371c9d4SSatish Balay   numEntityBlocks = sizes[0];
9759371c9d4SSatish Balay   numElements     = sizes[1];
9769566063dSJacob Faibussowitsch   PetscCall(GmshElementsCreate(numElements, &elements));
9770598e1a2SLisandro Dalcin   mesh->numElems = numElements;
9780598e1a2SLisandro Dalcin   mesh->elements = elements;
979698a79b9SLisandro Dalcin   for (c = 0, block = 0; block < numEntityBlocks; ++block) {
9809566063dSJacob Faibussowitsch     PetscCall(GmshReadInt(gmsh, info, 3));
9819371c9d4SSatish Balay     dim      = info[0];
9829371c9d4SSatish Balay     eid      = info[1];
9839371c9d4SSatish Balay     cellType = info[2];
9849566063dSJacob Faibussowitsch     PetscCall(GmshEntitiesGet(mesh->entities, dim, eid, &entity));
9859566063dSJacob Faibussowitsch     PetscCall(GmshCellTypeCheck(cellType));
9860598e1a2SLisandro Dalcin     numVerts = GmshCellMap[cellType].numVerts;
9870598e1a2SLisandro Dalcin     numNodes = GmshCellMap[cellType].numNodes;
9887d5b9244SMatthew G. Knepley     numTags  = entity->numTags;
9899566063dSJacob Faibussowitsch     PetscCall(GmshReadSize(gmsh, &numBlockElements, 1));
9909566063dSJacob Faibussowitsch     PetscCall(GmshBufferGet(gmsh, (1 + numNodes) * numBlockElements, sizeof(PetscInt), &ibuf));
9919566063dSJacob Faibussowitsch     PetscCall(GmshReadSize(gmsh, ibuf, (1 + numNodes) * numBlockElements));
992698a79b9SLisandro Dalcin     for (elem = 0; elem < numBlockElements; ++elem, ++c) {
993698a79b9SLisandro Dalcin       GmshElement    *element = elements + c;
9940598e1a2SLisandro Dalcin       const PetscInt *id = ibuf + elem * (1 + numNodes), *nodes = id + 1;
995698a79b9SLisandro Dalcin       element->id       = id[0];
996698a79b9SLisandro Dalcin       element->dim      = dim;
997698a79b9SLisandro Dalcin       element->cellType = cellType;
9980598e1a2SLisandro Dalcin       element->numVerts = numVerts;
999698a79b9SLisandro Dalcin       element->numNodes = numNodes;
1000698a79b9SLisandro Dalcin       element->numTags  = numTags;
10019566063dSJacob Faibussowitsch       PetscCall(PetscSegBufferGet(mesh->segbuf, (size_t)element->numNodes, &element->nodes));
10020598e1a2SLisandro Dalcin       for (p = 0; p < element->numNodes; p++) element->nodes[p] = nodeMap[nodes[p]];
10030598e1a2SLisandro Dalcin       for (p = 0; p < element->numTags; p++) element->tags[p] = entity->tags[p];
1004698a79b9SLisandro Dalcin     }
1005698a79b9SLisandro Dalcin   }
10063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1007698a79b9SLisandro Dalcin }
1008698a79b9SLisandro Dalcin 
10090598e1a2SLisandro Dalcin /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
1010698a79b9SLisandro Dalcin $Periodic
1011698a79b9SLisandro Dalcin   numPeriodicLinks(size_t)
10129dddd249SSatish Balay   entityDim(int) entityTag(int) entityTagPrimary(int)
1013698a79b9SLisandro Dalcin   numAffine(size_t) value(double) ...
1014698a79b9SLisandro Dalcin   numCorrespondingNodes(size_t)
10159dddd249SSatish Balay     nodeTag(size_t) nodeTagPrimary(size_t)
1016698a79b9SLisandro Dalcin     ...
1017698a79b9SLisandro Dalcin   ...
1018698a79b9SLisandro Dalcin $EndPeriodic
1019698a79b9SLisandro Dalcin */
1020d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadPeriodic_v41(GmshFile *gmsh, PetscInt periodicMap[])
1021d71ae5a4SJacob Faibussowitsch {
1022698a79b9SLisandro Dalcin   int       info[3];
1023698a79b9SLisandro Dalcin   double    dbuf[16];
10240598e1a2SLisandro Dalcin   PetscInt  numPeriodicLinks, numAffine, numCorrespondingNodes, *nodeTags = NULL, link, node;
10250598e1a2SLisandro Dalcin   PetscInt *nodeMap = gmsh->nodeMap;
1026698a79b9SLisandro Dalcin 
1027698a79b9SLisandro Dalcin   PetscFunctionBegin;
10289566063dSJacob Faibussowitsch   PetscCall(GmshReadSize(gmsh, &numPeriodicLinks, 1));
1029698a79b9SLisandro Dalcin   for (link = 0; link < numPeriodicLinks; ++link) {
10309566063dSJacob Faibussowitsch     PetscCall(GmshReadInt(gmsh, info, 3));
10319566063dSJacob Faibussowitsch     PetscCall(GmshReadSize(gmsh, &numAffine, 1));
10329566063dSJacob Faibussowitsch     PetscCall(GmshReadDouble(gmsh, dbuf, numAffine));
10339566063dSJacob Faibussowitsch     PetscCall(GmshReadSize(gmsh, &numCorrespondingNodes, 1));
10349566063dSJacob Faibussowitsch     PetscCall(GmshBufferGet(gmsh, numCorrespondingNodes, sizeof(PetscInt), &nodeTags));
10359566063dSJacob Faibussowitsch     PetscCall(GmshReadSize(gmsh, nodeTags, numCorrespondingNodes * 2));
1036698a79b9SLisandro Dalcin     for (node = 0; node < numCorrespondingNodes; ++node) {
10379dddd249SSatish Balay       PetscInt correspondingNode     = nodeMap[nodeTags[node * 2 + 0]];
10389dddd249SSatish Balay       PetscInt primaryNode           = nodeMap[nodeTags[node * 2 + 1]];
10399dddd249SSatish Balay       periodicMap[correspondingNode] = primaryNode;
1040698a79b9SLisandro Dalcin     }
1041698a79b9SLisandro Dalcin   }
10423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1043698a79b9SLisandro Dalcin }
1044698a79b9SLisandro Dalcin 
10450598e1a2SLisandro Dalcin /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
1046d6689ca9SLisandro Dalcin $MeshFormat // same as MSH version 2
1047d6689ca9SLisandro Dalcin   version(ASCII double; currently 4.1)
1048d6689ca9SLisandro Dalcin   file-type(ASCII int; 0 for ASCII mode, 1 for binary mode)
1049d6689ca9SLisandro Dalcin   data-size(ASCII int; sizeof(size_t))
1050d6689ca9SLisandro Dalcin   < int with value one; only in binary mode, to detect endianness >
1051d6689ca9SLisandro Dalcin $EndMeshFormat
1052d6689ca9SLisandro Dalcin */
1053d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadMeshFormat(GmshFile *gmsh)
1054d71ae5a4SJacob Faibussowitsch {
1055698a79b9SLisandro Dalcin   char  line[PETSC_MAX_PATH_LEN];
1056698a79b9SLisandro Dalcin   int   snum, fileType, fileFormat, dataSize, checkEndian;
1057698a79b9SLisandro Dalcin   float version;
1058698a79b9SLisandro Dalcin 
1059698a79b9SLisandro Dalcin   PetscFunctionBegin;
10609566063dSJacob Faibussowitsch   PetscCall(GmshReadString(gmsh, line, 3));
1061698a79b9SLisandro Dalcin   snum       = sscanf(line, "%f %d %d", &version, &fileType, &dataSize);
1062a8d4e440SJunchao Zhang   fileFormat = (int)roundf(version * 10);
106308401ef6SPierre Jolivet   PetscCheck(snum == 3, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to parse Gmsh file header: %s", line);
1064a8d4e440SJunchao Zhang   PetscCheck(fileFormat >= 22, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at least 2.2", (double)version);
10651dca8a05SBarry Smith   PetscCheck((int)version != 3, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f not supported", (double)version);
1066a8d4e440SJunchao Zhang   PetscCheck(fileFormat <= 41, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at most 4.1", (double)version);
106708401ef6SPierre Jolivet   PetscCheck(!gmsh->binary || fileType, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Viewer is binary but Gmsh file is ASCII");
106808401ef6SPierre Jolivet   PetscCheck(gmsh->binary || !fileType, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Viewer is ASCII but Gmsh file is binary");
10691dca8a05SBarry Smith   PetscCheck(fileFormat > 40 || dataSize == sizeof(double), PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Data size %d is not valid for a Gmsh file", dataSize);
10701dca8a05SBarry Smith   PetscCheck(fileFormat < 41 || dataSize == sizeof(int) || dataSize == sizeof(PetscInt64), PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Data size %d is not valid for a Gmsh file", dataSize);
1071698a79b9SLisandro Dalcin   gmsh->fileFormat = fileFormat;
1072698a79b9SLisandro Dalcin   gmsh->dataSize   = dataSize;
1073698a79b9SLisandro Dalcin   gmsh->byteSwap   = PETSC_FALSE;
1074698a79b9SLisandro Dalcin   if (gmsh->binary) {
10759566063dSJacob Faibussowitsch     PetscCall(GmshReadInt(gmsh, &checkEndian, 1));
1076698a79b9SLisandro Dalcin     if (checkEndian != 1) {
10779566063dSJacob Faibussowitsch       PetscCall(PetscByteSwap(&checkEndian, PETSC_ENUM, 1));
107808401ef6SPierre Jolivet       PetscCheck(checkEndian == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to detect endianness in Gmsh file header: %s", line);
1079698a79b9SLisandro Dalcin       gmsh->byteSwap = PETSC_TRUE;
1080698a79b9SLisandro Dalcin     }
1081698a79b9SLisandro Dalcin   }
10823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1083698a79b9SLisandro Dalcin }
1084698a79b9SLisandro Dalcin 
10851f643af3SLisandro Dalcin /*
10861f643af3SLisandro Dalcin PhysicalNames
10871f643af3SLisandro Dalcin   numPhysicalNames(ASCII int)
10881f643af3SLisandro Dalcin   dimension(ASCII int) physicalTag(ASCII int) "name"(127 characters max)
10891f643af3SLisandro Dalcin   ...
10901f643af3SLisandro Dalcin $EndPhysicalNames
10911f643af3SLisandro Dalcin */
1092d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadPhysicalNames(GmshFile *gmsh, GmshMesh *mesh)
1093d71ae5a4SJacob Faibussowitsch {
1094bbcf679cSJacob Faibussowitsch   char line[PETSC_MAX_PATH_LEN], name[128 + 2], *p = NULL, *q = NULL, *r = NULL;
1095a45dabc8SMatthew G. Knepley   int  snum, region, dim, tag;
1096698a79b9SLisandro Dalcin 
1097698a79b9SLisandro Dalcin   PetscFunctionBegin;
10989566063dSJacob Faibussowitsch   PetscCall(GmshReadString(gmsh, line, 1));
1099a45dabc8SMatthew G. Knepley   snum             = sscanf(line, "%d", &region);
1100a45dabc8SMatthew G. Knepley   mesh->numRegions = region;
110108401ef6SPierre Jolivet   PetscCheck(snum == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
110290d778b8SLisandro Dalcin   PetscCall(PetscMalloc3(mesh->numRegions, &mesh->regionDims, mesh->numRegions, &mesh->regionTags, mesh->numRegions, &mesh->regionNames));
1103a45dabc8SMatthew G. Knepley   for (region = 0; region < mesh->numRegions; ++region) {
11049566063dSJacob Faibussowitsch     PetscCall(GmshReadString(gmsh, line, 2));
11051f643af3SLisandro Dalcin     snum = sscanf(line, "%d %d", &dim, &tag);
110608401ef6SPierre Jolivet     PetscCheck(snum == 2, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
11079566063dSJacob Faibussowitsch     PetscCall(GmshReadString(gmsh, line, -(PetscInt)sizeof(line)));
11089566063dSJacob Faibussowitsch     PetscCall(PetscStrchr(line, '"', &p));
110928b400f6SJacob Faibussowitsch     PetscCheck(p, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
11109566063dSJacob Faibussowitsch     PetscCall(PetscStrrchr(line, '"', &q));
111108401ef6SPierre Jolivet     PetscCheck(q != p, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
11125f5cd6d5SMatthew G. Knepley     PetscCall(PetscStrrchr(line, ':', &r));
11135f5cd6d5SMatthew G. Knepley     if (p != r) q = r;
11149566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(name, p + 1, (size_t)(q - p - 1)));
111590d778b8SLisandro Dalcin     mesh->regionDims[region] = dim;
1116a45dabc8SMatthew G. Knepley     mesh->regionTags[region] = tag;
11179566063dSJacob Faibussowitsch     PetscCall(PetscStrallocpy(name, &mesh->regionNames[region]));
1118698a79b9SLisandro Dalcin   }
11193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1120de78e4feSLisandro Dalcin }
1121de78e4feSLisandro Dalcin 
1122d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadEntities(GmshFile *gmsh, GmshMesh *mesh)
1123d71ae5a4SJacob Faibussowitsch {
11240598e1a2SLisandro Dalcin   PetscFunctionBegin;
11250598e1a2SLisandro Dalcin   switch (gmsh->fileFormat) {
1126d71ae5a4SJacob Faibussowitsch   case 41:
1127d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadEntities_v41(gmsh, mesh));
1128d71ae5a4SJacob Faibussowitsch     break;
1129d71ae5a4SJacob Faibussowitsch   default:
1130d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadEntities_v40(gmsh, mesh));
1131d71ae5a4SJacob Faibussowitsch     break;
113296ca5757SLisandro Dalcin   }
11333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11340598e1a2SLisandro Dalcin }
11350598e1a2SLisandro Dalcin 
1136d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadNodes(GmshFile *gmsh, GmshMesh *mesh)
1137d71ae5a4SJacob Faibussowitsch {
11380598e1a2SLisandro Dalcin   PetscFunctionBegin;
11390598e1a2SLisandro Dalcin   switch (gmsh->fileFormat) {
1140d71ae5a4SJacob Faibussowitsch   case 41:
1141d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadNodes_v41(gmsh, mesh));
1142d71ae5a4SJacob Faibussowitsch     break;
1143d71ae5a4SJacob Faibussowitsch   case 40:
1144d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadNodes_v40(gmsh, mesh));
1145d71ae5a4SJacob Faibussowitsch     break;
1146d71ae5a4SJacob Faibussowitsch   default:
1147d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadNodes_v22(gmsh, mesh));
1148d71ae5a4SJacob Faibussowitsch     break;
11490598e1a2SLisandro Dalcin   }
11500598e1a2SLisandro Dalcin 
11510598e1a2SLisandro Dalcin   { /* Gmsh v2.2/v4.0 does not provide min/max node tags */
11520598e1a2SLisandro Dalcin     if (mesh->numNodes > 0 && gmsh->nodeEnd >= gmsh->nodeStart) {
11530598e1a2SLisandro Dalcin       PetscInt   tagMin = PETSC_MAX_INT, tagMax = PETSC_MIN_INT, n;
11540598e1a2SLisandro Dalcin       GmshNodes *nodes = mesh->nodelist;
11550598e1a2SLisandro Dalcin       for (n = 0; n < mesh->numNodes; ++n) {
11560598e1a2SLisandro Dalcin         const PetscInt tag = nodes->id[n];
11570598e1a2SLisandro Dalcin         tagMin             = PetscMin(tag, tagMin);
11580598e1a2SLisandro Dalcin         tagMax             = PetscMax(tag, tagMax);
11590598e1a2SLisandro Dalcin       }
11600598e1a2SLisandro Dalcin       gmsh->nodeStart = tagMin;
11610598e1a2SLisandro Dalcin       gmsh->nodeEnd   = tagMax + 1;
11620598e1a2SLisandro Dalcin     }
11630598e1a2SLisandro Dalcin   }
11640598e1a2SLisandro Dalcin 
11650598e1a2SLisandro Dalcin   { /* Support for sparse node tags */
11660598e1a2SLisandro Dalcin     PetscInt   n, t;
11670598e1a2SLisandro Dalcin     GmshNodes *nodes = mesh->nodelist;
11689566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(gmsh->nodeEnd - gmsh->nodeStart, &gmsh->nbuf));
11690598e1a2SLisandro Dalcin     for (t = 0; t < gmsh->nodeEnd - gmsh->nodeStart; ++t) gmsh->nbuf[t] = PETSC_MIN_INT;
11700598e1a2SLisandro Dalcin     gmsh->nodeMap = gmsh->nbuf - gmsh->nodeStart;
11710598e1a2SLisandro Dalcin     for (n = 0; n < mesh->numNodes; ++n) {
11720598e1a2SLisandro Dalcin       const PetscInt tag = nodes->id[n];
117363a3b9bcSJacob Faibussowitsch       PetscCheck(gmsh->nodeMap[tag] < 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Repeated node tag %" PetscInt_FMT, tag);
11740598e1a2SLisandro Dalcin       gmsh->nodeMap[tag] = n;
11750598e1a2SLisandro Dalcin     }
11760598e1a2SLisandro Dalcin   }
11773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11780598e1a2SLisandro Dalcin }
11790598e1a2SLisandro Dalcin 
1180d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadElements(GmshFile *gmsh, GmshMesh *mesh)
1181d71ae5a4SJacob Faibussowitsch {
11820598e1a2SLisandro Dalcin   PetscFunctionBegin;
11830598e1a2SLisandro Dalcin   switch (gmsh->fileFormat) {
1184d71ae5a4SJacob Faibussowitsch   case 41:
1185d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadElements_v41(gmsh, mesh));
1186d71ae5a4SJacob Faibussowitsch     break;
1187d71ae5a4SJacob Faibussowitsch   case 40:
1188d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadElements_v40(gmsh, mesh));
1189d71ae5a4SJacob Faibussowitsch     break;
1190d71ae5a4SJacob Faibussowitsch   default:
1191d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadElements_v22(gmsh, mesh));
1192d71ae5a4SJacob Faibussowitsch     break;
11930598e1a2SLisandro Dalcin   }
11940598e1a2SLisandro Dalcin 
11950598e1a2SLisandro Dalcin   { /* Reorder elements by codimension and polytope type */
11960598e1a2SLisandro Dalcin     PetscInt     ne       = mesh->numElems;
11970598e1a2SLisandro Dalcin     GmshElement *elements = mesh->elements;
1198066ea43fSLisandro Dalcin     PetscInt     keymap[GMSH_NUM_POLYTOPES], nk = 0;
1199066ea43fSLisandro Dalcin     PetscInt     offset[GMSH_NUM_POLYTOPES + 1], e, k;
12000598e1a2SLisandro Dalcin 
1201066ea43fSLisandro Dalcin     for (k = 0; k < GMSH_NUM_POLYTOPES; ++k) keymap[k] = PETSC_MIN_INT;
12029566063dSJacob Faibussowitsch     PetscCall(PetscMemzero(offset, sizeof(offset)));
12030598e1a2SLisandro Dalcin 
1204066ea43fSLisandro Dalcin     keymap[GMSH_TET] = nk++;
1205066ea43fSLisandro Dalcin     keymap[GMSH_HEX] = nk++;
1206066ea43fSLisandro Dalcin     keymap[GMSH_PRI] = nk++;
1207066ea43fSLisandro Dalcin     keymap[GMSH_PYR] = nk++;
1208066ea43fSLisandro Dalcin     keymap[GMSH_TRI] = nk++;
1209066ea43fSLisandro Dalcin     keymap[GMSH_QUA] = nk++;
1210066ea43fSLisandro Dalcin     keymap[GMSH_SEG] = nk++;
1211066ea43fSLisandro Dalcin     keymap[GMSH_VTX] = nk++;
12120598e1a2SLisandro Dalcin 
12139566063dSJacob Faibussowitsch     PetscCall(GmshElementsCreate(mesh->numElems, &mesh->elements));
12140598e1a2SLisandro Dalcin #define key(eid) keymap[GmshCellMap[elements[(eid)].cellType].polytope]
12150598e1a2SLisandro Dalcin     for (e = 0; e < ne; ++e) offset[1 + key(e)]++;
12160598e1a2SLisandro Dalcin     for (k = 1; k < nk; ++k) offset[k] += offset[k - 1];
12170598e1a2SLisandro Dalcin     for (e = 0; e < ne; ++e) mesh->elements[offset[key(e)]++] = elements[e];
12180598e1a2SLisandro Dalcin #undef key
12199566063dSJacob Faibussowitsch     PetscCall(GmshElementsDestroy(&elements));
1220066ea43fSLisandro Dalcin   }
12210598e1a2SLisandro Dalcin 
1222066ea43fSLisandro Dalcin   { /* Mesh dimension and order */
1223066ea43fSLisandro Dalcin     GmshElement *elem = mesh->numElems ? mesh->elements : NULL;
1224066ea43fSLisandro Dalcin     mesh->dim         = elem ? GmshCellMap[elem->cellType].dim : 0;
1225066ea43fSLisandro Dalcin     mesh->order       = elem ? GmshCellMap[elem->cellType].order : 0;
12260598e1a2SLisandro Dalcin   }
12270598e1a2SLisandro Dalcin 
12280598e1a2SLisandro Dalcin   {
12290598e1a2SLisandro Dalcin     PetscBT  vtx;
12300598e1a2SLisandro Dalcin     PetscInt dim = mesh->dim, e, n, v;
12310598e1a2SLisandro Dalcin 
12329566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(mesh->numNodes, &vtx));
12330598e1a2SLisandro Dalcin 
12340598e1a2SLisandro Dalcin     /* Compute number of cells and set of vertices */
12350598e1a2SLisandro Dalcin     mesh->numCells = 0;
12360598e1a2SLisandro Dalcin     for (e = 0; e < mesh->numElems; ++e) {
12370598e1a2SLisandro Dalcin       GmshElement *elem = mesh->elements + e;
12380598e1a2SLisandro Dalcin       if (elem->dim == dim && dim > 0) mesh->numCells++;
123948a46eb9SPierre Jolivet       for (v = 0; v < elem->numVerts; v++) PetscCall(PetscBTSet(vtx, elem->nodes[v]));
12400598e1a2SLisandro Dalcin     }
12410598e1a2SLisandro Dalcin 
12420598e1a2SLisandro Dalcin     /* Compute numbering for vertices */
12430598e1a2SLisandro Dalcin     mesh->numVerts = 0;
12449566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(mesh->numNodes, &mesh->vertexMap));
12459371c9d4SSatish Balay     for (n = 0; n < mesh->numNodes; ++n) mesh->vertexMap[n] = PetscBTLookup(vtx, n) ? mesh->numVerts++ : PETSC_MIN_INT;
12460598e1a2SLisandro Dalcin 
12479566063dSJacob Faibussowitsch     PetscCall(PetscBTDestroy(&vtx));
12480598e1a2SLisandro Dalcin   }
12493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12500598e1a2SLisandro Dalcin }
12510598e1a2SLisandro Dalcin 
1252d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadPeriodic(GmshFile *gmsh, GmshMesh *mesh)
1253d71ae5a4SJacob Faibussowitsch {
12540598e1a2SLisandro Dalcin   PetscInt n;
12550598e1a2SLisandro Dalcin 
12560598e1a2SLisandro Dalcin   PetscFunctionBegin;
12579566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(mesh->numNodes, &mesh->periodMap));
12580598e1a2SLisandro Dalcin   for (n = 0; n < mesh->numNodes; ++n) mesh->periodMap[n] = n;
12590598e1a2SLisandro Dalcin   switch (gmsh->fileFormat) {
1260d71ae5a4SJacob Faibussowitsch   case 41:
1261d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadPeriodic_v41(gmsh, mesh->periodMap));
1262d71ae5a4SJacob Faibussowitsch     break;
1263d71ae5a4SJacob Faibussowitsch   default:
1264d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadPeriodic_v40(gmsh, mesh->periodMap));
1265d71ae5a4SJacob Faibussowitsch     break;
12660598e1a2SLisandro Dalcin   }
12670598e1a2SLisandro Dalcin 
12689dddd249SSatish Balay   /* Find canonical primary nodes */
12690598e1a2SLisandro Dalcin   for (n = 0; n < mesh->numNodes; ++n)
12709371c9d4SSatish Balay     while (mesh->periodMap[n] != mesh->periodMap[mesh->periodMap[n]]) mesh->periodMap[n] = mesh->periodMap[mesh->periodMap[n]];
12710598e1a2SLisandro Dalcin 
12729dddd249SSatish Balay   /* Renumber vertices (filter out correspondings) */
12730598e1a2SLisandro Dalcin   mesh->numVerts = 0;
12740598e1a2SLisandro Dalcin   for (n = 0; n < mesh->numNodes; ++n)
12750598e1a2SLisandro Dalcin     if (mesh->vertexMap[n] >= 0)   /* is vertex */
12769dddd249SSatish Balay       if (mesh->periodMap[n] == n) /* is primary */
12770598e1a2SLisandro Dalcin         mesh->vertexMap[n] = mesh->numVerts++;
12780598e1a2SLisandro Dalcin   for (n = 0; n < mesh->numNodes; ++n)
12790598e1a2SLisandro Dalcin     if (mesh->vertexMap[n] >= 0)   /* is vertex */
12809dddd249SSatish Balay       if (mesh->periodMap[n] != n) /* is corresponding  */
12810598e1a2SLisandro Dalcin         mesh->vertexMap[n] = mesh->vertexMap[mesh->periodMap[n]];
12823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12830598e1a2SLisandro Dalcin }
12840598e1a2SLisandro Dalcin 
1285066ea43fSLisandro Dalcin #define DM_POLYTOPE_VERTEX DM_POLYTOPE_POINT
1286066ea43fSLisandro Dalcin static const DMPolytopeType DMPolytopeMap[] = {
1287066ea43fSLisandro Dalcin   /* GMSH_VTX */ DM_POLYTOPE_VERTEX,
1288066ea43fSLisandro Dalcin   /* GMSH_SEG */ DM_POLYTOPE_SEGMENT,
1289066ea43fSLisandro Dalcin   /* GMSH_TRI */ DM_POLYTOPE_TRIANGLE,
1290066ea43fSLisandro Dalcin   /* GMSH_QUA */ DM_POLYTOPE_QUADRILATERAL,
1291066ea43fSLisandro Dalcin   /* GMSH_TET */ DM_POLYTOPE_TETRAHEDRON,
1292066ea43fSLisandro Dalcin   /* GMSH_HEX */ DM_POLYTOPE_HEXAHEDRON,
1293066ea43fSLisandro Dalcin   /* GMSH_PRI */ DM_POLYTOPE_TRI_PRISM,
12949371c9d4SSatish Balay   /* GMSH_PYR */ DM_POLYTOPE_PYRAMID,       DM_POLYTOPE_UNKNOWN};
12950598e1a2SLisandro Dalcin 
1296d71ae5a4SJacob Faibussowitsch static inline DMPolytopeType DMPolytopeTypeFromGmsh(PetscInt cellType)
1297d71ae5a4SJacob Faibussowitsch {
1298066ea43fSLisandro Dalcin   return DMPolytopeMap[GmshCellMap[cellType].polytope];
1299066ea43fSLisandro Dalcin }
1300066ea43fSLisandro Dalcin 
1301d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshCreateFE(MPI_Comm comm, const char prefix[], PetscBool isSimplex, PetscBool continuity, PetscDTNodeType nodeType, PetscInt dim, PetscInt Nc, PetscInt k, PetscFE *fem)
1302d71ae5a4SJacob Faibussowitsch {
1303066ea43fSLisandro Dalcin   DM              K;
1304066ea43fSLisandro Dalcin   PetscSpace      P;
1305066ea43fSLisandro Dalcin   PetscDualSpace  Q;
1306066ea43fSLisandro Dalcin   PetscQuadrature q, fq;
1307066ea43fSLisandro Dalcin   PetscBool       isTensor = isSimplex ? PETSC_FALSE : PETSC_TRUE;
1308066ea43fSLisandro Dalcin   PetscBool       endpoint = PETSC_TRUE;
1309066ea43fSLisandro Dalcin   char            name[32];
1310066ea43fSLisandro Dalcin 
1311066ea43fSLisandro Dalcin   PetscFunctionBegin;
1312066ea43fSLisandro Dalcin   /* Create space */
13139566063dSJacob Faibussowitsch   PetscCall(PetscSpaceCreate(comm, &P));
13149566063dSJacob Faibussowitsch   PetscCall(PetscSpaceSetType(P, PETSCSPACEPOLYNOMIAL));
13159566063dSJacob Faibussowitsch   PetscCall(PetscSpacePolynomialSetTensor(P, isTensor));
13169566063dSJacob Faibussowitsch   PetscCall(PetscSpaceSetNumComponents(P, Nc));
13179566063dSJacob Faibussowitsch   PetscCall(PetscSpaceSetNumVariables(P, dim));
13189566063dSJacob Faibussowitsch   PetscCall(PetscSpaceSetDegree(P, k, PETSC_DETERMINE));
1319066ea43fSLisandro Dalcin   if (prefix) {
13209566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)P, prefix));
13219566063dSJacob Faibussowitsch     PetscCall(PetscSpaceSetFromOptions(P));
13229566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)P, NULL));
13239566063dSJacob Faibussowitsch     PetscCall(PetscSpaceGetDegree(P, &k, NULL));
1324066ea43fSLisandro Dalcin   }
13259566063dSJacob Faibussowitsch   PetscCall(PetscSpaceSetUp(P));
1326066ea43fSLisandro Dalcin   /* Create dual space */
13279566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceCreate(comm, &Q));
13289566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetType(Q, PETSCDUALSPACELAGRANGE));
13299566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceLagrangeSetTensor(Q, isTensor));
13309566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceLagrangeSetContinuity(Q, continuity));
13319566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceLagrangeSetNodeType(Q, nodeType, endpoint, 0));
13329566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetNumComponents(Q, Nc));
13339566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetOrder(Q, k));
13349566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceCell(PETSC_COMM_SELF, DMPolytopeTypeSimpleShape(dim, isSimplex), &K));
13359566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetDM(Q, K));
13369566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&K));
1337066ea43fSLisandro Dalcin   if (prefix) {
13389566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)Q, prefix));
13399566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceSetFromOptions(Q));
13409566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)Q, NULL));
1341066ea43fSLisandro Dalcin   }
13429566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetUp(Q));
1343066ea43fSLisandro Dalcin   /* Create quadrature */
1344066ea43fSLisandro Dalcin   if (isSimplex) {
13459566063dSJacob Faibussowitsch     PetscCall(PetscDTStroudConicalQuadrature(dim, 1, k + 1, -1, +1, &q));
13469566063dSJacob Faibussowitsch     PetscCall(PetscDTStroudConicalQuadrature(dim - 1, 1, k + 1, -1, +1, &fq));
1347066ea43fSLisandro Dalcin   } else {
13489566063dSJacob Faibussowitsch     PetscCall(PetscDTGaussTensorQuadrature(dim, 1, k + 1, -1, +1, &q));
13499566063dSJacob Faibussowitsch     PetscCall(PetscDTGaussTensorQuadrature(dim - 1, 1, k + 1, -1, +1, &fq));
1350066ea43fSLisandro Dalcin   }
1351066ea43fSLisandro Dalcin   /* Create finite element */
13529566063dSJacob Faibussowitsch   PetscCall(PetscFECreate(comm, fem));
13539566063dSJacob Faibussowitsch   PetscCall(PetscFESetType(*fem, PETSCFEBASIC));
13549566063dSJacob Faibussowitsch   PetscCall(PetscFESetNumComponents(*fem, Nc));
13559566063dSJacob Faibussowitsch   PetscCall(PetscFESetBasisSpace(*fem, P));
13569566063dSJacob Faibussowitsch   PetscCall(PetscFESetDualSpace(*fem, Q));
13579566063dSJacob Faibussowitsch   PetscCall(PetscFESetQuadrature(*fem, q));
13589566063dSJacob Faibussowitsch   PetscCall(PetscFESetFaceQuadrature(*fem, fq));
1359066ea43fSLisandro Dalcin   if (prefix) {
13609566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*fem, prefix));
13619566063dSJacob Faibussowitsch     PetscCall(PetscFESetFromOptions(*fem));
13629566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*fem, NULL));
1363066ea43fSLisandro Dalcin   }
13649566063dSJacob Faibussowitsch   PetscCall(PetscFESetUp(*fem));
1365066ea43fSLisandro Dalcin   /* Cleanup */
13669566063dSJacob Faibussowitsch   PetscCall(PetscSpaceDestroy(&P));
13679566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceDestroy(&Q));
13689566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureDestroy(&q));
13699566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureDestroy(&fq));
1370066ea43fSLisandro Dalcin   /* Set finite element name */
137163a3b9bcSJacob Faibussowitsch   PetscCall(PetscSNPrintf(name, sizeof(name), "%s%" PetscInt_FMT, isSimplex ? "P" : "Q", k));
13729566063dSJacob Faibussowitsch   PetscCall(PetscFESetName(*fem, name));
13733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
137496ca5757SLisandro Dalcin }
137596ca5757SLisandro Dalcin 
1376d6689ca9SLisandro Dalcin /*@C
1377a1cb98faSBarry Smith   DMPlexCreateGmshFromFile - Create a `DMPLEX` mesh from a Gmsh file
1378d6689ca9SLisandro Dalcin 
1379*a4e35b19SJacob Faibussowitsch   Input Parameters:
1380d6689ca9SLisandro Dalcin + comm        - The MPI communicator
1381d6689ca9SLisandro Dalcin . filename    - Name of the Gmsh file
1382d6689ca9SLisandro Dalcin - interpolate - Create faces and edges in the mesh
1383d6689ca9SLisandro Dalcin 
1384d6689ca9SLisandro Dalcin   Output Parameter:
1385a1cb98faSBarry Smith . dm - The `DM` object representing the mesh
1386d6689ca9SLisandro Dalcin 
1387d6689ca9SLisandro Dalcin   Level: beginner
1388d6689ca9SLisandro Dalcin 
13891cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromFile()`, `DMPlexCreateGmsh()`, `DMPlexCreate()`
1390d6689ca9SLisandro Dalcin @*/
1391d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateGmshFromFile(MPI_Comm comm, const char filename[], PetscBool interpolate, DM *dm)
1392d71ae5a4SJacob Faibussowitsch {
1393d6689ca9SLisandro Dalcin   PetscViewer     viewer;
1394d6689ca9SLisandro Dalcin   PetscMPIInt     rank;
1395d6689ca9SLisandro Dalcin   int             fileType;
1396d6689ca9SLisandro Dalcin   PetscViewerType vtype;
1397d6689ca9SLisandro Dalcin 
1398d6689ca9SLisandro Dalcin   PetscFunctionBegin;
13999566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1400d6689ca9SLisandro Dalcin 
1401d6689ca9SLisandro Dalcin   /* Determine Gmsh file type (ASCII or binary) from file header */
1402dd400576SPatrick Sanan   if (rank == 0) {
14030598e1a2SLisandro Dalcin     GmshFile gmsh[1];
1404d6689ca9SLisandro Dalcin     char     line[PETSC_MAX_PATH_LEN];
1405d6689ca9SLisandro Dalcin     int      snum;
1406d6689ca9SLisandro Dalcin     float    version;
1407a8d4e440SJunchao Zhang     int      fileFormat;
1408d6689ca9SLisandro Dalcin 
14099566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(gmsh, 1));
14109566063dSJacob Faibussowitsch     PetscCall(PetscViewerCreate(PETSC_COMM_SELF, &gmsh->viewer));
14119566063dSJacob Faibussowitsch     PetscCall(PetscViewerSetType(gmsh->viewer, PETSCVIEWERASCII));
14129566063dSJacob Faibussowitsch     PetscCall(PetscViewerFileSetMode(gmsh->viewer, FILE_MODE_READ));
14139566063dSJacob Faibussowitsch     PetscCall(PetscViewerFileSetName(gmsh->viewer, filename));
1414d6689ca9SLisandro Dalcin     /* Read only the first two lines of the Gmsh file */
14159566063dSJacob Faibussowitsch     PetscCall(GmshReadSection(gmsh, line));
14169566063dSJacob Faibussowitsch     PetscCall(GmshExpect(gmsh, "$MeshFormat", line));
14179566063dSJacob Faibussowitsch     PetscCall(GmshReadString(gmsh, line, 2));
1418d6689ca9SLisandro Dalcin     snum       = sscanf(line, "%f %d", &version, &fileType);
1419a8d4e440SJunchao Zhang     fileFormat = (int)roundf(version * 10);
142008401ef6SPierre Jolivet     PetscCheck(snum == 2, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to parse Gmsh file header: %s", line);
1421a8d4e440SJunchao Zhang     PetscCheck(fileFormat >= 22, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at least 2.2", (double)version);
14221dca8a05SBarry Smith     PetscCheck((int)version != 3, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f not supported", (double)version);
1423a8d4e440SJunchao Zhang     PetscCheck(fileFormat <= 41, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at most 4.1", (double)version);
14249566063dSJacob Faibussowitsch     PetscCall(PetscViewerDestroy(&gmsh->viewer));
1425d6689ca9SLisandro Dalcin   }
14269566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Bcast(&fileType, 1, MPI_INT, 0, comm));
1427d6689ca9SLisandro Dalcin   vtype = (fileType == 0) ? PETSCVIEWERASCII : PETSCVIEWERBINARY;
1428d6689ca9SLisandro Dalcin 
1429d6689ca9SLisandro Dalcin   /* Create appropriate viewer and build plex */
14309566063dSJacob Faibussowitsch   PetscCall(PetscViewerCreate(comm, &viewer));
14319566063dSJacob Faibussowitsch   PetscCall(PetscViewerSetType(viewer, vtype));
14329566063dSJacob Faibussowitsch   PetscCall(PetscViewerFileSetMode(viewer, FILE_MODE_READ));
14339566063dSJacob Faibussowitsch   PetscCall(PetscViewerFileSetName(viewer, filename));
14349566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateGmsh(comm, viewer, interpolate, dm));
14359566063dSJacob Faibussowitsch   PetscCall(PetscViewerDestroy(&viewer));
14363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1437d6689ca9SLisandro Dalcin }
1438d6689ca9SLisandro Dalcin 
1439331830f3SMatthew G. Knepley /*@
1440a1cb98faSBarry Smith   DMPlexCreateGmsh - Create a `DMPLEX` mesh from a Gmsh file viewer
1441331830f3SMatthew G. Knepley 
1442d083f849SBarry Smith   Collective
1443331830f3SMatthew G. Knepley 
1444331830f3SMatthew G. Knepley   Input Parameters:
1445331830f3SMatthew G. Knepley + comm        - The MPI communicator
1446a1cb98faSBarry Smith . viewer      - The `PetscViewer` associated with a Gmsh file
1447331830f3SMatthew G. Knepley - interpolate - Create faces and edges in the mesh
1448331830f3SMatthew G. Knepley 
1449331830f3SMatthew G. Knepley   Output Parameter:
1450a1cb98faSBarry Smith . dm - The `DM` object representing the mesh
1451331830f3SMatthew G. Knepley 
1452a1cb98faSBarry Smith   Options Database Keys:
1453df93260fSMatthew G. Knepley + -dm_plex_gmsh_hybrid        - Force triangular prisms to use tensor order
1454df93260fSMatthew G. Knepley . -dm_plex_gmsh_periodic      - Read Gmsh periodic section and construct a periodic Plex
1455df93260fSMatthew G. Knepley . -dm_plex_gmsh_highorder     - Generate high-order coordinates
1456df93260fSMatthew G. Knepley . -dm_plex_gmsh_project       - Project high-order coordinates to a different space, use the prefix dm_plex_gmsh_project_ to define the space
1457df93260fSMatthew G. Knepley . -dm_plex_gmsh_use_regions   - Generate labels with region names
1458df93260fSMatthew G. Knepley . -dm_plex_gmsh_mark_vertices - Add vertices to generated labels
1459df93260fSMatthew G. Knepley . -dm_plex_gmsh_multiple_tags - Allow multiple tags for default labels
1460df93260fSMatthew G. Knepley - -dm_plex_gmsh_spacedim <d>  - Embedding space dimension, if different from topological dimension
1461df93260fSMatthew G. Knepley 
1462df93260fSMatthew G. Knepley   Note:
1463df93260fSMatthew G. Knepley   The Gmsh file format is described in http://gmsh.info/doc/texinfo/gmsh.html#MSH-file-format
1464df93260fSMatthew G. Knepley 
1465df93260fSMatthew G. Knepley   By default, the "Cell Sets", "Face Sets", and "Vertex Sets" labels are created, and only insert the first tag on a point. By using -dm_plex_gmsh_multiple_tags, all tags can be inserted. Instead, -dm_plex_gmsh_use_regions creates labels based on the region names from the PhysicalNames section, and all tags are used.
1466331830f3SMatthew G. Knepley 
1467331830f3SMatthew G. Knepley   Level: beginner
1468331830f3SMatthew G. Knepley 
14691cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`
1470331830f3SMatthew G. Knepley @*/
1471d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateGmsh(MPI_Comm comm, PetscViewer viewer, PetscBool interpolate, DM *dm)
1472d71ae5a4SJacob Faibussowitsch {
14730598e1a2SLisandro Dalcin   GmshMesh    *mesh          = NULL;
147411c56cb0SLisandro Dalcin   PetscViewer  parentviewer  = NULL;
14750598e1a2SLisandro Dalcin   PetscBT      periodicVerts = NULL;
1476eae3dc7dSJacob Faibussowitsch   PetscBT     *periodicCells = NULL;
14776858538eSMatthew G. Knepley   DM           cdm, cdmCell = NULL;
14786858538eSMatthew G. Knepley   PetscSection cs, csCell   = NULL;
14796858538eSMatthew G. Knepley   Vec          coordinates, coordinatesCell;
1480a45dabc8SMatthew G. Knepley   DMLabel      cellSets = NULL, faceSets = NULL, vertSets = NULL, marker = NULL, *regionSets;
14819db5b827SMatthew G. Knepley   PetscInt     dim = 0, coordDim = -1, order = 0, maxHeight = 0;
14829db5b827SMatthew G. Knepley   PetscInt     numNodes = 0, numElems = 0, numVerts = 0, numCells = 0, vStart, vEnd;
1483066ea43fSLisandro Dalcin   PetscInt     cell, cone[8], e, n, v, d;
1484df93260fSMatthew G. Knepley   PetscBool    binary, useregions = PETSC_FALSE, markvertices = PETSC_FALSE, multipleTags = PETSC_FALSE;
14850598e1a2SLisandro Dalcin   PetscBool    hybrid = interpolate, periodic = PETSC_TRUE;
1486066ea43fSLisandro Dalcin   PetscBool    highOrder = PETSC_TRUE, highOrderSet, project = PETSC_FALSE;
1487066ea43fSLisandro Dalcin   PetscBool    isSimplex = PETSC_FALSE, isHybrid = PETSC_FALSE, hasTetra = PETSC_FALSE;
14880598e1a2SLisandro Dalcin   PetscMPIInt  rank;
1489331830f3SMatthew G. Knepley 
1490331830f3SMatthew G. Knepley   PetscFunctionBegin;
14919566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1492d0609cedSBarry Smith   PetscObjectOptionsBegin((PetscObject)viewer);
1493d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "DMPlex Gmsh options");
1494df93260fSMatthew G. Knepley   PetscCall(PetscOptionsBool("-dm_plex_gmsh_hybrid", "Force triangular prisms to use tensor order", "DMPlexCreateGmsh", hybrid, &hybrid, NULL));
14959566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_plex_gmsh_periodic", "Read Gmsh periodic section", "DMPlexCreateGmsh", periodic, &periodic, NULL));
14969566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_plex_gmsh_highorder", "Generate high-order coordinates", "DMPlexCreateGmsh", highOrder, &highOrder, &highOrderSet));
14979566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_plex_gmsh_project", "Project high-order coordinates to a different space", "DMPlexCreateGmsh", project, &project, NULL));
14989566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_plex_gmsh_use_regions", "Generate labels with region names", "DMPlexCreateGmsh", useregions, &useregions, NULL));
14999566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_plex_gmsh_mark_vertices", "Add vertices to generated labels", "DMPlexCreateGmsh", markvertices, &markvertices, NULL));
1500df93260fSMatthew G. Knepley   PetscCall(PetscOptionsBool("-dm_plex_gmsh_multiple_tags", "Allow multiple tags for default labels", "DMPlexCreateGmsh", multipleTags, &multipleTags, NULL));
15019566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBoundedInt("-dm_plex_gmsh_spacedim", "Embedding space dimension", "DMPlexCreateGmsh", coordDim, &coordDim, NULL, PETSC_DECIDE));
15029db5b827SMatthew G. Knepley   PetscCall(PetscOptionsBoundedInt("-dm_localize_height", "Localize edges and faces in addition to cells", "", maxHeight, &maxHeight, NULL, 0));
1503d0609cedSBarry Smith   PetscOptionsHeadEnd();
1504d0609cedSBarry Smith   PetscOptionsEnd();
15050598e1a2SLisandro Dalcin 
15069566063dSJacob Faibussowitsch   PetscCall(GmshCellInfoSetUp());
150711c56cb0SLisandro Dalcin 
15089566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm, dm));
15099566063dSJacob Faibussowitsch   PetscCall(DMSetType(*dm, DMPLEX));
15109566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_CreateGmsh, *dm, NULL, NULL, NULL));
151111c56cb0SLisandro Dalcin 
15129566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &binary));
151311c56cb0SLisandro Dalcin 
151411c56cb0SLisandro Dalcin   /* Binary viewers read on all ranks, get subviewer to read only in rank 0 */
15153b46f529SLisandro Dalcin   if (binary) {
151611c56cb0SLisandro Dalcin     parentviewer = viewer;
15179566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetSubViewer(parentviewer, PETSC_COMM_SELF, &viewer));
151811c56cb0SLisandro Dalcin   }
151911c56cb0SLisandro Dalcin 
1520dd400576SPatrick Sanan   if (rank == 0) {
15210598e1a2SLisandro Dalcin     GmshFile  gmsh[1];
1522698a79b9SLisandro Dalcin     char      line[PETSC_MAX_PATH_LEN];
1523698a79b9SLisandro Dalcin     PetscBool match;
1524331830f3SMatthew G. Knepley 
15259566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(gmsh, 1));
1526698a79b9SLisandro Dalcin     gmsh->viewer = viewer;
1527698a79b9SLisandro Dalcin     gmsh->binary = binary;
1528698a79b9SLisandro Dalcin 
15299566063dSJacob Faibussowitsch     PetscCall(GmshMeshCreate(&mesh));
15300598e1a2SLisandro Dalcin 
1531698a79b9SLisandro Dalcin     /* Read mesh format */
15329566063dSJacob Faibussowitsch     PetscCall(GmshReadSection(gmsh, line));
15339566063dSJacob Faibussowitsch     PetscCall(GmshExpect(gmsh, "$MeshFormat", line));
15349566063dSJacob Faibussowitsch     PetscCall(GmshReadMeshFormat(gmsh));
15359566063dSJacob Faibussowitsch     PetscCall(GmshReadEndSection(gmsh, "$EndMeshFormat", line));
153611c56cb0SLisandro Dalcin 
1537dc0ede3bSMatthew G. Knepley     /* OPTIONAL Read physical names */
15389566063dSJacob Faibussowitsch     PetscCall(GmshReadSection(gmsh, line));
15399566063dSJacob Faibussowitsch     PetscCall(GmshMatch(gmsh, "$PhysicalNames", line, &match));
1540dc0ede3bSMatthew G. Knepley     if (match) {
15419566063dSJacob Faibussowitsch       PetscCall(GmshExpect(gmsh, "$PhysicalNames", line));
15429566063dSJacob Faibussowitsch       PetscCall(GmshReadPhysicalNames(gmsh, mesh));
15439566063dSJacob Faibussowitsch       PetscCall(GmshReadEndSection(gmsh, "$EndPhysicalNames", line));
1544698a79b9SLisandro Dalcin       /* Initial read for entity section */
15459566063dSJacob Faibussowitsch       PetscCall(GmshReadSection(gmsh, line));
1546dc0ede3bSMatthew G. Knepley     }
154711c56cb0SLisandro Dalcin 
1548de78e4feSLisandro Dalcin     /* Read entities */
1549698a79b9SLisandro Dalcin     if (gmsh->fileFormat >= 40) {
15509566063dSJacob Faibussowitsch       PetscCall(GmshExpect(gmsh, "$Entities", line));
15519566063dSJacob Faibussowitsch       PetscCall(GmshReadEntities(gmsh, mesh));
15529566063dSJacob Faibussowitsch       PetscCall(GmshReadEndSection(gmsh, "$EndEntities", line));
1553698a79b9SLisandro Dalcin       /* Initial read for nodes section */
15549566063dSJacob Faibussowitsch       PetscCall(GmshReadSection(gmsh, line));
1555de78e4feSLisandro Dalcin     }
1556de78e4feSLisandro Dalcin 
1557698a79b9SLisandro Dalcin     /* Read nodes */
15589566063dSJacob Faibussowitsch     PetscCall(GmshExpect(gmsh, "$Nodes", line));
15599566063dSJacob Faibussowitsch     PetscCall(GmshReadNodes(gmsh, mesh));
15609566063dSJacob Faibussowitsch     PetscCall(GmshReadEndSection(gmsh, "$EndNodes", line));
156111c56cb0SLisandro Dalcin 
1562698a79b9SLisandro Dalcin     /* Read elements */
15639566063dSJacob Faibussowitsch     PetscCall(GmshReadSection(gmsh, line));
15649566063dSJacob Faibussowitsch     PetscCall(GmshExpect(gmsh, "$Elements", line));
15659566063dSJacob Faibussowitsch     PetscCall(GmshReadElements(gmsh, mesh));
15669566063dSJacob Faibussowitsch     PetscCall(GmshReadEndSection(gmsh, "$EndElements", line));
1567de78e4feSLisandro Dalcin 
15680598e1a2SLisandro Dalcin     /* Read periodic section (OPTIONAL) */
1569698a79b9SLisandro Dalcin     if (periodic) {
15709566063dSJacob Faibussowitsch       PetscCall(GmshReadSection(gmsh, line));
15719566063dSJacob Faibussowitsch       PetscCall(GmshMatch(gmsh, "$Periodic", line, &periodic));
1572ef12879bSLisandro Dalcin     }
1573ef12879bSLisandro Dalcin     if (periodic) {
15749566063dSJacob Faibussowitsch       PetscCall(GmshExpect(gmsh, "$Periodic", line));
15759566063dSJacob Faibussowitsch       PetscCall(GmshReadPeriodic(gmsh, mesh));
15769566063dSJacob Faibussowitsch       PetscCall(GmshReadEndSection(gmsh, "$EndPeriodic", line));
1577698a79b9SLisandro Dalcin     }
1578698a79b9SLisandro Dalcin 
15799566063dSJacob Faibussowitsch     PetscCall(PetscFree(gmsh->wbuf));
15809566063dSJacob Faibussowitsch     PetscCall(PetscFree(gmsh->sbuf));
15819566063dSJacob Faibussowitsch     PetscCall(PetscFree(gmsh->nbuf));
15820598e1a2SLisandro Dalcin 
15830598e1a2SLisandro Dalcin     dim      = mesh->dim;
1584066ea43fSLisandro Dalcin     order    = mesh->order;
15850598e1a2SLisandro Dalcin     numNodes = mesh->numNodes;
15860598e1a2SLisandro Dalcin     numElems = mesh->numElems;
15870598e1a2SLisandro Dalcin     numVerts = mesh->numVerts;
15880598e1a2SLisandro Dalcin     numCells = mesh->numCells;
1589066ea43fSLisandro Dalcin 
1590066ea43fSLisandro Dalcin     {
1591066ea43fSLisandro Dalcin       GmshElement *elemA = mesh->numCells > 0 ? mesh->elements : NULL;
1592066ea43fSLisandro Dalcin       GmshElement *elemB = elemA ? elemA + mesh->numCells - 1 : NULL;
1593066ea43fSLisandro Dalcin       int          ptA   = elemA ? GmshCellMap[elemA->cellType].polytope : -1;
1594066ea43fSLisandro Dalcin       int          ptB   = elemB ? GmshCellMap[elemB->cellType].polytope : -1;
1595066ea43fSLisandro Dalcin       isSimplex          = (ptA == GMSH_QUA || ptA == GMSH_HEX) ? PETSC_FALSE : PETSC_TRUE;
1596066ea43fSLisandro Dalcin       isHybrid           = (ptA == ptB) ? PETSC_FALSE : PETSC_TRUE;
1597066ea43fSLisandro Dalcin       hasTetra           = (ptA == GMSH_TET) ? PETSC_TRUE : PETSC_FALSE;
1598066ea43fSLisandro Dalcin     }
1599698a79b9SLisandro Dalcin   }
1600698a79b9SLisandro Dalcin 
160148a46eb9SPierre Jolivet   if (parentviewer) PetscCall(PetscViewerRestoreSubViewer(parentviewer, PETSC_COMM_SELF, &viewer));
1602698a79b9SLisandro Dalcin 
1603066ea43fSLisandro Dalcin   {
1604066ea43fSLisandro Dalcin     int buf[6];
1605698a79b9SLisandro Dalcin 
1606066ea43fSLisandro Dalcin     buf[0] = (int)dim;
1607066ea43fSLisandro Dalcin     buf[1] = (int)order;
1608066ea43fSLisandro Dalcin     buf[2] = periodic;
1609066ea43fSLisandro Dalcin     buf[3] = isSimplex;
1610066ea43fSLisandro Dalcin     buf[4] = isHybrid;
1611066ea43fSLisandro Dalcin     buf[5] = hasTetra;
1612066ea43fSLisandro Dalcin 
16139566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Bcast(buf, 6, MPI_INT, 0, comm));
1614066ea43fSLisandro Dalcin 
1615066ea43fSLisandro Dalcin     dim       = buf[0];
1616066ea43fSLisandro Dalcin     order     = buf[1];
1617066ea43fSLisandro Dalcin     periodic  = buf[2] ? PETSC_TRUE : PETSC_FALSE;
1618066ea43fSLisandro Dalcin     isSimplex = buf[3] ? PETSC_TRUE : PETSC_FALSE;
1619066ea43fSLisandro Dalcin     isHybrid  = buf[4] ? PETSC_TRUE : PETSC_FALSE;
1620066ea43fSLisandro Dalcin     hasTetra  = buf[5] ? PETSC_TRUE : PETSC_FALSE;
1621dea2a3c7SStefano Zampini   }
1622dea2a3c7SStefano Zampini 
1623066ea43fSLisandro Dalcin   if (!highOrderSet) highOrder = (order > 1) ? PETSC_TRUE : PETSC_FALSE;
162408401ef6SPierre Jolivet   PetscCheck(!highOrder || !isHybrid, comm, PETSC_ERR_SUP, "No support for discretization on hybrid meshes yet");
1625066ea43fSLisandro Dalcin 
16260598e1a2SLisandro Dalcin   /* We do not want this label automatically computed, instead we fill it here */
16279566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(*dm, "celltype"));
162811c56cb0SLisandro Dalcin 
1629a4bb7517SMichael Lange   /* Allocate the cell-vertex mesh */
16309566063dSJacob Faibussowitsch   PetscCall(DMPlexSetChart(*dm, 0, numCells + numVerts));
16310598e1a2SLisandro Dalcin   for (cell = 0; cell < numCells; ++cell) {
16320598e1a2SLisandro Dalcin     GmshElement   *elem  = mesh->elements + cell;
16330598e1a2SLisandro Dalcin     DMPolytopeType ctype = DMPolytopeTypeFromGmsh(elem->cellType);
16340598e1a2SLisandro Dalcin     if (hybrid && hasTetra && ctype == DM_POLYTOPE_TRI_PRISM) ctype = DM_POLYTOPE_TRI_PRISM_TENSOR;
16359566063dSJacob Faibussowitsch     PetscCall(DMPlexSetConeSize(*dm, cell, elem->numVerts));
16369566063dSJacob Faibussowitsch     PetscCall(DMPlexSetCellType(*dm, cell, ctype));
1637db397164SMichael Lange   }
163848a46eb9SPierre Jolivet   for (v = numCells; v < numCells + numVerts; ++v) PetscCall(DMPlexSetCellType(*dm, v, DM_POLYTOPE_POINT));
16399566063dSJacob Faibussowitsch   PetscCall(DMSetUp(*dm));
164096ca5757SLisandro Dalcin 
1641a4bb7517SMichael Lange   /* Add cell-vertex connections */
16420598e1a2SLisandro Dalcin   for (cell = 0; cell < numCells; ++cell) {
16430598e1a2SLisandro Dalcin     GmshElement *elem = mesh->elements + cell;
16440598e1a2SLisandro Dalcin     for (v = 0; v < elem->numVerts; ++v) {
16450598e1a2SLisandro Dalcin       const PetscInt nn = elem->nodes[v];
16460598e1a2SLisandro Dalcin       const PetscInt vv = mesh->vertexMap[nn];
16470598e1a2SLisandro Dalcin       cone[v]           = numCells + vv;
1648db397164SMichael Lange     }
16499566063dSJacob Faibussowitsch     PetscCall(DMPlexReorderCell(*dm, cell, cone));
16509566063dSJacob Faibussowitsch     PetscCall(DMPlexSetCone(*dm, cell, cone));
1651a4bb7517SMichael Lange   }
165296ca5757SLisandro Dalcin 
16539566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(*dm, dim));
16549566063dSJacob Faibussowitsch   PetscCall(DMPlexSymmetrize(*dm));
16559566063dSJacob Faibussowitsch   PetscCall(DMPlexStratify(*dm));
1656331830f3SMatthew G. Knepley   if (interpolate) {
16575fd9971aSMatthew G. Knepley     DM idm;
1658331830f3SMatthew G. Knepley 
16599566063dSJacob Faibussowitsch     PetscCall(DMPlexInterpolate(*dm, &idm));
16609566063dSJacob Faibussowitsch     PetscCall(DMDestroy(dm));
1661331830f3SMatthew G. Knepley     *dm = idm;
1662331830f3SMatthew G. Knepley   }
16639db5b827SMatthew G. Knepley   PetscCall(DMPlexGetDepthStratum(*dm, 0, &vStart, &vEnd));
1664917266a4SLisandro Dalcin 
1665dd400576SPatrick Sanan   if (rank == 0) {
1666a45dabc8SMatthew G. Knepley     const PetscInt Nr = useregions ? mesh->numRegions : 0;
1667d1a54cefSMatthew G. Knepley 
16689566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(Nr, &regionSets));
16690598e1a2SLisandro Dalcin     for (cell = 0, e = 0; e < numElems; ++e) {
16700598e1a2SLisandro Dalcin       GmshElement *elem = mesh->elements + e;
16716e1dd89aSLawrence Mitchell 
16726e1dd89aSLawrence Mitchell       /* Create cell sets */
16730598e1a2SLisandro Dalcin       if (elem->dim == dim && dim > 0) {
16740598e1a2SLisandro Dalcin         if (elem->numTags > 0) {
1675df93260fSMatthew G. Knepley           PetscInt Nt = elem->numTags, t, r;
1676a45dabc8SMatthew G. Knepley 
1677df93260fSMatthew G. Knepley           for (t = 0; t < Nt; ++t) {
1678df93260fSMatthew G. Knepley             const PetscInt  tag     = elem->tags[t];
1679df93260fSMatthew G. Knepley             const PetscBool generic = !Nr && (!t || multipleTags) ? PETSC_TRUE : PETSC_FALSE;
1680df93260fSMatthew G. Knepley 
1681df93260fSMatthew G. Knepley             if (generic) PetscCall(DMSetLabelValue_Fast(*dm, &cellSets, "Cell Sets", cell, tag));
1682a45dabc8SMatthew G. Knepley             for (r = 0; r < Nr; ++r) {
1683df93260fSMatthew G. Knepley               if (mesh->regionDims[r] != dim) continue;
16849566063dSJacob Faibussowitsch               if (mesh->regionTags[r] == tag) PetscCall(DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], cell, tag));
1685a45dabc8SMatthew G. Knepley             }
16866e1dd89aSLawrence Mitchell           }
1687df93260fSMatthew G. Knepley         }
1688917266a4SLisandro Dalcin         cell++;
16896e1dd89aSLawrence Mitchell       }
16900c070f12SSander Arens 
16910598e1a2SLisandro Dalcin       /* Create face sets */
16920598e1a2SLisandro Dalcin       if (interpolate && elem->dim == dim - 1) {
16930598e1a2SLisandro Dalcin         PetscInt        joinSize;
16940598e1a2SLisandro Dalcin         const PetscInt *join = NULL;
16955ad74b4fSMatthew G. Knepley         PetscInt        Nt   = elem->numTags, t, r;
1696a45dabc8SMatthew G. Knepley 
16970598e1a2SLisandro Dalcin         /* Find the relevant facet with vertex joins */
16980598e1a2SLisandro Dalcin         for (v = 0; v < elem->numVerts; ++v) {
16990598e1a2SLisandro Dalcin           const PetscInt nn = elem->nodes[v];
17000598e1a2SLisandro Dalcin           const PetscInt vv = mesh->vertexMap[nn];
17010598e1a2SLisandro Dalcin           cone[v]           = vStart + vv;
17020598e1a2SLisandro Dalcin         }
17039566063dSJacob Faibussowitsch         PetscCall(DMPlexGetFullJoin(*dm, elem->numVerts, cone, &joinSize, &join));
170463a3b9bcSJacob Faibussowitsch         PetscCheck(joinSize == 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Could not determine Plex facet for Gmsh element %" PetscInt_FMT " (Plex cell %" PetscInt_FMT ")", elem->id, e);
17055ad74b4fSMatthew G. Knepley         for (t = 0; t < Nt; ++t) {
17065ad74b4fSMatthew G. Knepley           const PetscInt  tag     = elem->tags[t];
1707df93260fSMatthew G. Knepley           const PetscBool generic = !Nr && (!t || multipleTags) ? PETSC_TRUE : PETSC_FALSE;
17085ad74b4fSMatthew G. Knepley 
1709df93260fSMatthew G. Knepley           if (generic) PetscCall(DMSetLabelValue_Fast(*dm, &faceSets, "Face Sets", join[0], tag));
1710a45dabc8SMatthew G. Knepley           for (r = 0; r < Nr; ++r) {
1711df93260fSMatthew G. Knepley             if (mesh->regionDims[r] != dim - 1) continue;
17129566063dSJacob Faibussowitsch             if (mesh->regionTags[r] == tag) PetscCall(DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], join[0], tag));
1713a45dabc8SMatthew G. Knepley           }
17145ad74b4fSMatthew G. Knepley         }
17159566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreJoin(*dm, elem->numVerts, cone, &joinSize, &join));
17160598e1a2SLisandro Dalcin       }
17170598e1a2SLisandro Dalcin 
17180c070f12SSander Arens       /* Create vertex sets */
1719df93260fSMatthew G. Knepley       if (elem->dim == 0 && markvertices) {
17200598e1a2SLisandro Dalcin         if (elem->numTags > 0) {
17210598e1a2SLisandro Dalcin           const PetscInt nn  = elem->nodes[0];
17220598e1a2SLisandro Dalcin           const PetscInt vv  = mesh->vertexMap[nn];
1723a45dabc8SMatthew G. Knepley           const PetscInt tag = elem->tags[0];
1724a45dabc8SMatthew G. Knepley           PetscInt       r;
1725a45dabc8SMatthew G. Knepley 
17269566063dSJacob Faibussowitsch           if (!Nr) PetscCall(DMSetLabelValue_Fast(*dm, &vertSets, "Vertex Sets", vStart + vv, tag));
172781a1af93SMatthew G. Knepley           for (r = 0; r < Nr; ++r) {
1728df93260fSMatthew G. Knepley             if (mesh->regionDims[r] != 0) continue;
17299566063dSJacob Faibussowitsch             if (mesh->regionTags[r] == tag) PetscCall(DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], vStart + vv, tag));
173081a1af93SMatthew G. Knepley           }
173181a1af93SMatthew G. Knepley         }
173281a1af93SMatthew G. Knepley       }
173381a1af93SMatthew G. Knepley     }
173481a1af93SMatthew G. Knepley     if (markvertices) {
173581a1af93SMatthew G. Knepley       for (v = 0; v < numNodes; ++v) {
173681a1af93SMatthew G. Knepley         const PetscInt  vv   = mesh->vertexMap[v];
17377d5b9244SMatthew G. Knepley         const PetscInt *tags = &mesh->nodelist->tag[v * GMSH_MAX_TAGS];
17387d5b9244SMatthew G. Knepley         PetscInt        r, t;
173981a1af93SMatthew G. Knepley 
17407d5b9244SMatthew G. Knepley         for (t = 0; t < GMSH_MAX_TAGS; ++t) {
17417d5b9244SMatthew G. Knepley           const PetscInt  tag     = tags[t];
1742df93260fSMatthew G. Knepley           const PetscBool generic = !Nr && (!t || multipleTags) ? PETSC_TRUE : PETSC_FALSE;
17437d5b9244SMatthew G. Knepley 
17447d5b9244SMatthew G. Knepley           if (tag == -1) continue;
1745df93260fSMatthew G. Knepley           if (generic) PetscCall(DMSetLabelValue_Fast(*dm, &vertSets, "Vertex Sets", vStart + vv, tag));
1746a45dabc8SMatthew G. Knepley           for (r = 0; r < Nr; ++r) {
17479566063dSJacob Faibussowitsch             if (mesh->regionTags[r] == tag) PetscCall(DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], vStart + vv, tag));
17480598e1a2SLisandro Dalcin           }
17490598e1a2SLisandro Dalcin         }
17500598e1a2SLisandro Dalcin       }
17510598e1a2SLisandro Dalcin     }
17529566063dSJacob Faibussowitsch     PetscCall(PetscFree(regionSets));
1753a45dabc8SMatthew G. Knepley   }
17540598e1a2SLisandro Dalcin 
17557dd454faSLisandro Dalcin   { /* Create Cell/Face/Vertex Sets labels at all processes */
17569371c9d4SSatish Balay     enum {
17579371c9d4SSatish Balay       n = 4
17589371c9d4SSatish Balay     };
17597dd454faSLisandro Dalcin     PetscBool flag[n];
17607dd454faSLisandro Dalcin 
17617dd454faSLisandro Dalcin     flag[0] = cellSets ? PETSC_TRUE : PETSC_FALSE;
17627dd454faSLisandro Dalcin     flag[1] = faceSets ? PETSC_TRUE : PETSC_FALSE;
17637dd454faSLisandro Dalcin     flag[2] = vertSets ? PETSC_TRUE : PETSC_FALSE;
17647dd454faSLisandro Dalcin     flag[3] = marker ? PETSC_TRUE : PETSC_FALSE;
17659566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Bcast(flag, n, MPIU_BOOL, 0, comm));
17669566063dSJacob Faibussowitsch     if (flag[0]) PetscCall(DMCreateLabel(*dm, "Cell Sets"));
17679566063dSJacob Faibussowitsch     if (flag[1]) PetscCall(DMCreateLabel(*dm, "Face Sets"));
17689566063dSJacob Faibussowitsch     if (flag[2]) PetscCall(DMCreateLabel(*dm, "Vertex Sets"));
17699566063dSJacob Faibussowitsch     if (flag[3]) PetscCall(DMCreateLabel(*dm, "marker"));
17707dd454faSLisandro Dalcin   }
17717dd454faSLisandro Dalcin 
17720598e1a2SLisandro Dalcin   if (periodic) {
17739566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(numVerts, &periodicVerts));
17740598e1a2SLisandro Dalcin     for (n = 0; n < numNodes; ++n) {
17750598e1a2SLisandro Dalcin       if (mesh->vertexMap[n] >= 0) {
17760598e1a2SLisandro Dalcin         if (PetscUnlikely(mesh->periodMap[n] != n)) {
17770598e1a2SLisandro Dalcin           PetscInt m = mesh->periodMap[n];
17789566063dSJacob Faibussowitsch           PetscCall(PetscBTSet(periodicVerts, mesh->vertexMap[n]));
17799566063dSJacob Faibussowitsch           PetscCall(PetscBTSet(periodicVerts, mesh->vertexMap[m]));
17800598e1a2SLisandro Dalcin         }
17810598e1a2SLisandro Dalcin       }
17820598e1a2SLisandro Dalcin     }
17839db5b827SMatthew G. Knepley     PetscCall(DMGetCoordinateDM(*dm, &cdm));
1784eae3dc7dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxHeight + 1, &periodicCells));
17859db5b827SMatthew G. Knepley     for (PetscInt h = 0; h <= maxHeight; ++h) {
17869db5b827SMatthew G. Knepley       PetscInt pStart, pEnd;
17879db5b827SMatthew G. Knepley 
17889db5b827SMatthew G. Knepley       PetscCall(DMPlexGetHeightStratum(*dm, h, &pStart, &pEnd));
17899db5b827SMatthew G. Knepley       PetscCall(PetscBTCreate(pEnd - pStart, &periodicCells[h]));
17909db5b827SMatthew G. Knepley       for (PetscInt p = pStart; p < pEnd; ++p) {
17919db5b827SMatthew G. Knepley         PetscInt *closure = NULL;
17929db5b827SMatthew G. Knepley         PetscInt  Ncl;
17939db5b827SMatthew G. Knepley 
17949db5b827SMatthew G. Knepley         PetscCall(DMPlexGetTransitiveClosure(*dm, p, PETSC_TRUE, &Ncl, &closure));
17959db5b827SMatthew G. Knepley         for (PetscInt cl = 0; cl < Ncl * 2; cl += 2) {
17969db5b827SMatthew G. Knepley           if (closure[cl] >= vStart && closure[cl] < vEnd) {
17979db5b827SMatthew G. Knepley             if (PetscUnlikely(PetscBTLookup(periodicVerts, closure[cl] - vStart))) {
17989db5b827SMatthew G. Knepley               PetscCall(PetscBTSet(periodicCells[h], p - pStart));
17999371c9d4SSatish Balay               break;
18000c070f12SSander Arens             }
18010c070f12SSander Arens           }
18020c070f12SSander Arens         }
18039db5b827SMatthew G. Knepley         PetscCall(DMPlexRestoreTransitiveClosure(*dm, p, PETSC_TRUE, &Ncl, &closure));
18049db5b827SMatthew G. Knepley       }
18059db5b827SMatthew G. Knepley     }
180616ad7e67SMichael Lange   }
180716ad7e67SMichael Lange 
1808066ea43fSLisandro Dalcin   /* Setup coordinate DM */
18090598e1a2SLisandro Dalcin   if (coordDim < 0) coordDim = dim;
18109566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinateDim(*dm, coordDim));
18119566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(*dm, &cdm));
1812066ea43fSLisandro Dalcin   if (highOrder) {
1813066ea43fSLisandro Dalcin     PetscFE         fe;
1814066ea43fSLisandro Dalcin     PetscBool       continuity = periodic ? PETSC_FALSE : PETSC_TRUE;
1815066ea43fSLisandro Dalcin     PetscDTNodeType nodeType   = PETSCDTNODES_EQUISPACED;
1816066ea43fSLisandro Dalcin 
1817066ea43fSLisandro Dalcin     if (isSimplex) continuity = PETSC_FALSE; /* XXX FIXME Requires DMPlexSetClosurePermutationLexicographic() */
1818066ea43fSLisandro Dalcin 
18199566063dSJacob Faibussowitsch     PetscCall(GmshCreateFE(comm, NULL, isSimplex, continuity, nodeType, dim, coordDim, order, &fe));
18209566063dSJacob Faibussowitsch     PetscCall(PetscFEViewFromOptions(fe, NULL, "-dm_plex_gmsh_fe_view"));
18219566063dSJacob Faibussowitsch     PetscCall(DMSetField(cdm, 0, NULL, (PetscObject)fe));
18229566063dSJacob Faibussowitsch     PetscCall(PetscFEDestroy(&fe));
18239566063dSJacob Faibussowitsch     PetscCall(DMCreateDS(cdm));
1824066ea43fSLisandro Dalcin   }
18256858538eSMatthew G. Knepley   if (periodic) {
18266858538eSMatthew G. Knepley     PetscCall(DMClone(cdm, &cdmCell));
18276858538eSMatthew G. Knepley     PetscCall(DMSetCellCoordinateDM(*dm, cdmCell));
18286858538eSMatthew G. Knepley   }
1829066ea43fSLisandro Dalcin 
1830066ea43fSLisandro Dalcin   /* Create coordinates */
1831066ea43fSLisandro Dalcin   if (highOrder) {
1832066ea43fSLisandro Dalcin     PetscInt     maxDof = GmshNumNodes_HEX(order) * coordDim;
1833066ea43fSLisandro Dalcin     double      *coords = mesh ? mesh->nodelist->xyz : NULL;
1834066ea43fSLisandro Dalcin     PetscSection section;
1835066ea43fSLisandro Dalcin     PetscScalar *cellCoords;
1836066ea43fSLisandro Dalcin 
18379566063dSJacob Faibussowitsch     PetscCall(DMSetLocalSection(cdm, NULL));
18386858538eSMatthew G. Knepley     PetscCall(DMGetLocalSection(cdm, &cs));
18396858538eSMatthew G. Knepley     PetscCall(PetscSectionClone(cs, &section));
18409566063dSJacob Faibussowitsch     PetscCall(DMPlexSetClosurePermutationTensor(cdm, 0, section)); /* XXX Implement DMPlexSetClosurePermutationLexicographic() */
1841066ea43fSLisandro Dalcin 
18429566063dSJacob Faibussowitsch     PetscCall(DMCreateLocalVector(cdm, &coordinates));
18439566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxDof, &cellCoords));
1844066ea43fSLisandro Dalcin     for (cell = 0; cell < numCells; ++cell) {
1845066ea43fSLisandro Dalcin       GmshElement *elem     = mesh->elements + cell;
1846066ea43fSLisandro Dalcin       const int   *lexorder = GmshCellMap[elem->cellType].lexorder();
1847b9bf55e5SMatthew G. Knepley       int          s        = 0;
1848066ea43fSLisandro Dalcin       for (n = 0; n < elem->numNodes; ++n) {
1849b9bf55e5SMatthew G. Knepley         while (lexorder[n + s] < 0) ++s;
1850b9bf55e5SMatthew G. Knepley         const PetscInt node = elem->nodes[lexorder[n + s]];
1851b9bf55e5SMatthew G. Knepley         for (d = 0; d < coordDim; ++d) cellCoords[(n + s) * coordDim + d] = (PetscReal)coords[node * 3 + d];
1852b9bf55e5SMatthew G. Knepley       }
1853b9bf55e5SMatthew G. Knepley       if (s) {
1854b9bf55e5SMatthew G. Knepley         /* For the coordinate mapping we weight vertices by -1/4 and edges by 1/2, which we get from Q_2 interpolation */
1855b9bf55e5SMatthew G. Knepley         PetscReal quaCenterWeights[9] = {-0.25, 0.5, -0.25, 0.5, 0.0, 0.5, -0.25, 0.5, -0.25};
1856b9bf55e5SMatthew G. Knepley         /* For the coordinate mapping we weight vertices by -1/4 and edges by 1/2, which we get from Q_2 interpolation */
18579371c9d4SSatish Balay         PetscReal   hexBottomWeights[27] = {-0.25, 0.5, -0.25, 0.5, 0.0, 0.5, -0.25, 0.5, -0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
18589371c9d4SSatish Balay         PetscReal   hexFrontWeights[27]  = {-0.25, 0.5, -0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.25, 0.5, -0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
18599371c9d4SSatish Balay         PetscReal   hexLeftWeights[27]   = {-0.25, 0.0, 0.0, 0.5, 0.0, 0.0, -0.25, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, -0.25, 0.0, 0.0, 0.5, 0.0, 0.0, -0.25, 0.0, 0.0};
18609371c9d4SSatish Balay         PetscReal   hexRightWeights[27]  = {0.0, 0.0, -0.25, 0.0, 0.0, 0.5, 0.0, 0.0, -0.25, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, -0.25, 0.0, 0.0, 0.5, 0.0, 0.0, -0.25};
18619371c9d4SSatish Balay         PetscReal   hexBackWeights[27]   = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.25, 0.5, -0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.25, 0.5, -0.25};
18629371c9d4SSatish Balay         PetscReal   hexTopWeights[27]    = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.25, 0.5, -0.25, 0.5, 0.0, 0.5, -0.25, 0.5, -0.25};
18639371c9d4SSatish Balay         PetscReal   hexCenterWeights[27] = {-0.25, 0.25, -0.25, 0.25, 0.0, 0.25, -0.25, 0.25, -0.25, 0.25, 0.0, 0.25, 0.0, 0.0, 0.0, 0.25, 0.0, 0.25, -0.25, 0.25, -0.25, 0.25, 0.0, 0.25, -0.25, 0.25, -0.25};
1864b9bf55e5SMatthew G. Knepley         PetscReal  *sdWeights2[9]        = {NULL, NULL, NULL, NULL, quaCenterWeights, NULL, NULL, NULL, NULL};
18659371c9d4SSatish Balay         PetscReal  *sdWeights3[27]       = {NULL, NULL, NULL, NULL, hexBottomWeights, NULL, NULL, NULL, NULL, NULL, hexFrontWeights, NULL, hexLeftWeights, hexCenterWeights, hexRightWeights, NULL, hexBackWeights, NULL,
1866b9bf55e5SMatthew G. Knepley                                             NULL, NULL, NULL, NULL, hexTopWeights,    NULL, NULL, NULL, NULL};
1867b9bf55e5SMatthew G. Knepley         PetscReal **sdWeights[4]         = {NULL, NULL, sdWeights2, sdWeights3};
1868b9bf55e5SMatthew G. Knepley 
1869b9bf55e5SMatthew G. Knepley         /* Missing entries in serendipity cell, only works for 8-node quad and 20-node hex */
1870b9bf55e5SMatthew G. Knepley         for (n = 0; n < elem->numNodes + s; ++n) {
1871b9bf55e5SMatthew G. Knepley           if (lexorder[n] >= 0) continue;
1872b9bf55e5SMatthew G. Knepley           for (d = 0; d < coordDim; ++d) cellCoords[n * coordDim + d] = 0.0;
1873b9bf55e5SMatthew G. Knepley           for (int bn = 0; bn < elem->numNodes + s; ++bn) {
1874b9bf55e5SMatthew G. Knepley             if (lexorder[bn] < 0) continue;
1875b9bf55e5SMatthew G. Knepley             const PetscReal *weights = sdWeights[coordDim][n];
1876b9bf55e5SMatthew G. Knepley             const PetscInt   bnode   = elem->nodes[lexorder[bn]];
1877b9bf55e5SMatthew G. Knepley             for (d = 0; d < coordDim; ++d) cellCoords[n * coordDim + d] += weights[bn] * (PetscReal)coords[bnode * 3 + d];
1878b9bf55e5SMatthew G. Knepley           }
1879b9bf55e5SMatthew G. Knepley         }
1880066ea43fSLisandro Dalcin       }
18819566063dSJacob Faibussowitsch       PetscCall(DMPlexVecSetClosure(cdm, section, coordinates, cell, cellCoords, INSERT_VALUES));
1882066ea43fSLisandro Dalcin     }
18839566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&section));
18849566063dSJacob Faibussowitsch     PetscCall(PetscFree(cellCoords));
1885066ea43fSLisandro Dalcin   } else {
1886066ea43fSLisandro Dalcin     PetscInt    *nodeMap;
1887066ea43fSLisandro Dalcin     double      *coords = mesh ? mesh->nodelist->xyz : NULL;
1888066ea43fSLisandro Dalcin     PetscScalar *pointCoords;
1889066ea43fSLisandro Dalcin 
18906858538eSMatthew G. Knepley     PetscCall(DMGetCoordinateSection(*dm, &cs));
18916858538eSMatthew G. Knepley     PetscCall(PetscSectionSetNumFields(cs, 1));
18926858538eSMatthew G. Knepley     PetscCall(PetscSectionSetFieldComponents(cs, 0, coordDim));
18936858538eSMatthew G. Knepley     PetscCall(PetscSectionSetChart(cs, numCells, numCells + numVerts));
18946858538eSMatthew G. Knepley     for (v = numCells; v < numCells + numVerts; ++v) {
18956858538eSMatthew G. Knepley       PetscCall(PetscSectionSetDof(cs, v, coordDim));
18966858538eSMatthew G. Knepley       PetscCall(PetscSectionSetFieldDof(cs, v, 0, coordDim));
1897f45c9589SStefano Zampini     }
18986858538eSMatthew G. Knepley     PetscCall(PetscSectionSetUp(cs));
18996858538eSMatthew G. Knepley 
19006858538eSMatthew G. Knepley     /* We need to localize coordinates on cells */
19010598e1a2SLisandro Dalcin     if (periodic) {
19029db5b827SMatthew G. Knepley       PetscInt newStart = PETSC_MAX_INT, newEnd = -1, pStart, pEnd;
19039db5b827SMatthew G. Knepley 
19046858538eSMatthew G. Knepley       PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)cdmCell), &csCell));
19056858538eSMatthew G. Knepley       PetscCall(PetscSectionSetNumFields(csCell, 1));
19066858538eSMatthew G. Knepley       PetscCall(PetscSectionSetFieldComponents(csCell, 0, coordDim));
19079db5b827SMatthew G. Knepley       for (PetscInt h = 0; h <= maxHeight; h++) {
19089db5b827SMatthew G. Knepley         PetscCall(DMPlexGetHeightStratum(cdmCell, h, &pStart, &pEnd));
19099db5b827SMatthew G. Knepley         newStart = PetscMin(newStart, pStart);
19109db5b827SMatthew G. Knepley         newEnd   = PetscMax(newEnd, pEnd);
19119db5b827SMatthew G. Knepley       }
19129db5b827SMatthew G. Knepley       PetscCall(PetscSectionSetChart(csCell, newStart, newEnd));
19139db5b827SMatthew G. Knepley       for (PetscInt h = 0; h <= maxHeight; h++) {
19149db5b827SMatthew G. Knepley         PetscCall(DMPlexGetHeightStratum(cdmCell, h, &pStart, &pEnd));
19159db5b827SMatthew G. Knepley         for (PetscInt p = pStart; p < pEnd; ++p) {
19169db5b827SMatthew G. Knepley           PetscInt *closure = NULL;
19179db5b827SMatthew G. Knepley           PetscInt  Ncl, Nv = 0;
19186858538eSMatthew G. Knepley 
19199db5b827SMatthew G. Knepley           if (PetscUnlikely(PetscBTLookup(periodicCells[h], p - pStart))) {
19209db5b827SMatthew G. Knepley             PetscCall(DMPlexGetTransitiveClosure(*dm, p, PETSC_TRUE, &Ncl, &closure));
19219db5b827SMatthew G. Knepley             for (PetscInt cl = 0; cl < Ncl * 2; cl += 2) {
19229db5b827SMatthew G. Knepley               if (closure[cl] >= vStart && closure[cl] < vEnd) ++Nv;
19239db5b827SMatthew G. Knepley             }
19249db5b827SMatthew G. Knepley             PetscCall(DMPlexRestoreTransitiveClosure(*dm, p, PETSC_TRUE, &Ncl, &closure));
19259db5b827SMatthew G. Knepley             PetscCall(PetscSectionSetDof(csCell, p, Nv * coordDim));
19269db5b827SMatthew G. Knepley             PetscCall(PetscSectionSetFieldDof(csCell, p, 0, Nv * coordDim));
19279db5b827SMatthew G. Knepley           }
1928f45c9589SStefano Zampini         }
1929f45c9589SStefano Zampini       }
19306858538eSMatthew G. Knepley       PetscCall(PetscSectionSetUp(csCell));
19316858538eSMatthew G. Knepley       PetscCall(DMSetCellCoordinateSection(*dm, PETSC_DETERMINE, csCell));
1932f45c9589SStefano Zampini     }
1933066ea43fSLisandro Dalcin 
19349566063dSJacob Faibussowitsch     PetscCall(DMCreateLocalVector(cdm, &coordinates));
19359566063dSJacob Faibussowitsch     PetscCall(VecGetArray(coordinates, &pointCoords));
19366858538eSMatthew G. Knepley     PetscCall(PetscMalloc1(numVerts, &nodeMap));
19376858538eSMatthew G. Knepley     for (n = 0; n < numNodes; n++)
19386858538eSMatthew G. Knepley       if (mesh->vertexMap[n] >= 0) nodeMap[mesh->vertexMap[n]] = n;
19396858538eSMatthew G. Knepley     for (v = 0; v < numVerts; ++v) {
19406858538eSMatthew G. Knepley       PetscInt off, node = nodeMap[v];
19416858538eSMatthew G. Knepley 
19426858538eSMatthew G. Knepley       PetscCall(PetscSectionGetOffset(cs, numCells + v, &off));
19436858538eSMatthew G. Knepley       for (d = 0; d < coordDim; ++d) pointCoords[off + d] = (PetscReal)coords[node * 3 + d];
19446858538eSMatthew G. Knepley     }
19456858538eSMatthew G. Knepley     PetscCall(VecRestoreArray(coordinates, &pointCoords));
19466858538eSMatthew G. Knepley 
19470598e1a2SLisandro Dalcin     if (periodic) {
19489db5b827SMatthew G. Knepley       PetscInt cStart, cEnd;
19499db5b827SMatthew G. Knepley 
19509db5b827SMatthew G. Knepley       PetscCall(DMPlexGetHeightStratum(cdmCell, 0, &cStart, &cEnd));
19516858538eSMatthew G. Knepley       PetscCall(DMCreateLocalVector(cdmCell, &coordinatesCell));
19526858538eSMatthew G. Knepley       PetscCall(VecGetArray(coordinatesCell, &pointCoords));
19539db5b827SMatthew G. Knepley       for (PetscInt c = cStart; c < cEnd; ++c) {
19549db5b827SMatthew G. Knepley         GmshElement *elem    = mesh->elements + c - cStart;
19559db5b827SMatthew G. Knepley         PetscInt    *closure = NULL;
19569db5b827SMatthew G. Knepley         PetscInt     verts[8];
19579db5b827SMatthew G. Knepley         PetscInt     Ncl, Nv = 0;
19589db5b827SMatthew G. Knepley 
19599db5b827SMatthew G. Knepley         for (PetscInt v = 0; v < elem->numVerts; ++v) cone[v] = elem->nodes[v];
19609db5b827SMatthew G. Knepley         PetscCall(DMPlexReorderCell(cdmCell, c, cone));
19619db5b827SMatthew G. Knepley         PetscCall(DMPlexGetTransitiveClosure(cdmCell, c, PETSC_TRUE, &Ncl, &closure));
19629db5b827SMatthew G. Knepley         for (PetscInt cl = 0; cl < Ncl * 2; cl += 2) {
19639db5b827SMatthew G. Knepley           if (closure[cl] >= vStart && closure[cl] < vEnd) verts[Nv++] = closure[cl];
1964331830f3SMatthew G. Knepley         }
19659db5b827SMatthew G. Knepley         PetscCheck(Nv == elem->numVerts, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of vertices %" PetscInt_FMT " in closure does not match number of vertices %" PetscInt_FMT " in Gmsh cell", Nv, elem->numVerts);
19669db5b827SMatthew G. Knepley         for (PetscInt cl = 0; cl < Ncl * 2; cl += 2) {
19679db5b827SMatthew G. Knepley           const PetscInt point = closure[cl];
19689db5b827SMatthew G. Knepley           PetscInt       hStart, h;
19699db5b827SMatthew G. Knepley 
19709db5b827SMatthew G. Knepley           PetscCall(DMPlexGetPointHeight(cdmCell, point, &h));
19719db5b827SMatthew G. Knepley           if (h > maxHeight) continue;
19729db5b827SMatthew G. Knepley           PetscCall(DMPlexGetHeightStratum(cdmCell, h, &hStart, NULL));
19739db5b827SMatthew G. Knepley           if (PetscUnlikely(PetscBTLookup(periodicCells[h], point - hStart))) {
19749db5b827SMatthew G. Knepley             PetscInt *pclosure = NULL;
19759db5b827SMatthew G. Knepley             PetscInt  Npcl, off, v;
19769db5b827SMatthew G. Knepley 
19779db5b827SMatthew G. Knepley             PetscCall(PetscSectionGetOffset(csCell, point, &off));
19789db5b827SMatthew G. Knepley             PetscCall(DMPlexGetTransitiveClosure(cdmCell, point, PETSC_TRUE, &Npcl, &pclosure));
19799db5b827SMatthew G. Knepley             for (PetscInt pcl = 0; pcl < Npcl * 2; pcl += 2) {
19809db5b827SMatthew G. Knepley               if (pclosure[pcl] >= vStart && pclosure[pcl] < vEnd) {
19819db5b827SMatthew G. Knepley                 for (v = 0; v < Nv; ++v)
19829db5b827SMatthew G. Knepley                   if (verts[v] == pclosure[pcl]) break;
19839db5b827SMatthew G. Knepley                 PetscCheck(v < Nv, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find vertex %" PetscInt_FMT " in closure of cell %" PetscInt_FMT, pclosure[pcl], c);
19849db5b827SMatthew G. Knepley                 for (PetscInt d = 0; d < coordDim; ++d) pointCoords[off++] = (PetscReal)coords[cone[v] * 3 + d];
19859db5b827SMatthew G. Knepley                 ++v;
19869db5b827SMatthew G. Knepley               }
19879db5b827SMatthew G. Knepley             }
19889db5b827SMatthew G. Knepley             PetscCall(DMPlexRestoreTransitiveClosure(cdmCell, point, PETSC_TRUE, &Npcl, &pclosure));
19899db5b827SMatthew G. Knepley           }
19909db5b827SMatthew G. Knepley         }
19919db5b827SMatthew G. Knepley         PetscCall(DMPlexRestoreTransitiveClosure(cdmCell, c, PETSC_TRUE, &Ncl, &closure));
1992331830f3SMatthew G. Knepley       }
19936858538eSMatthew G. Knepley       PetscCall(VecSetBlockSize(coordinatesCell, coordDim));
19946858538eSMatthew G. Knepley       PetscCall(VecRestoreArray(coordinatesCell, &pointCoords));
19956858538eSMatthew G. Knepley       PetscCall(DMSetCellCoordinatesLocal(*dm, coordinatesCell));
19966858538eSMatthew G. Knepley       PetscCall(VecDestroy(&coordinatesCell));
1997331830f3SMatthew G. Knepley     }
19989db5b827SMatthew G. Knepley     PetscCall(PetscFree(nodeMap));
19996858538eSMatthew G. Knepley     PetscCall(PetscSectionDestroy(&csCell));
20006858538eSMatthew G. Knepley     PetscCall(DMDestroy(&cdmCell));
2001066ea43fSLisandro Dalcin   }
2002066ea43fSLisandro Dalcin 
20039566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
20049566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(coordinates, coordDim));
20059566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinatesLocal(*dm, coordinates));
20069566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&coordinates));
200711c56cb0SLisandro Dalcin 
20089566063dSJacob Faibussowitsch   PetscCall(GmshMeshDestroy(&mesh));
20099566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&periodicVerts));
2010eae3dc7dSJacob Faibussowitsch   if (periodic) {
2011eae3dc7dSJacob Faibussowitsch     for (PetscInt h = 0; h <= maxHeight; ++h) PetscCall(PetscBTDestroy(periodicCells + h));
2012eae3dc7dSJacob Faibussowitsch     PetscCall(PetscFree(periodicCells));
2013eae3dc7dSJacob Faibussowitsch   }
201411c56cb0SLisandro Dalcin 
2015066ea43fSLisandro Dalcin   if (highOrder && project) {
2016066ea43fSLisandro Dalcin     PetscFE         fe;
2017066ea43fSLisandro Dalcin     const char      prefix[]   = "dm_plex_gmsh_project_";
2018066ea43fSLisandro Dalcin     PetscBool       continuity = periodic ? PETSC_FALSE : PETSC_TRUE;
2019066ea43fSLisandro Dalcin     PetscDTNodeType nodeType   = PETSCDTNODES_GAUSSJACOBI;
2020066ea43fSLisandro Dalcin 
2021066ea43fSLisandro Dalcin     if (isSimplex) continuity = PETSC_FALSE; /* XXX FIXME Requires DMPlexSetClosurePermutationLexicographic() */
20229566063dSJacob Faibussowitsch     PetscCall(GmshCreateFE(comm, prefix, isSimplex, continuity, nodeType, dim, coordDim, order, &fe));
20239566063dSJacob Faibussowitsch     PetscCall(PetscFEViewFromOptions(fe, NULL, "-dm_plex_gmsh_project_fe_view"));
20249566063dSJacob Faibussowitsch     PetscCall(DMProjectCoordinates(*dm, fe));
20259566063dSJacob Faibussowitsch     PetscCall(PetscFEDestroy(&fe));
2026066ea43fSLisandro Dalcin   }
2027066ea43fSLisandro Dalcin 
20289566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_CreateGmsh, *dm, NULL, NULL, NULL));
20293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2030331830f3SMatthew G. Knepley }
2031