xref: /petsc/src/dm/impls/plex/plexgmsh.c (revision 10dd146ff0f6475ab09d12db171fe38f04d2c285)
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 
120*10dd146fSPierre Jolivet // clang-format off
121*10dd146fSPierre Jolivet #define GmshCellEntry(cellType, polytope, dim, order) {cellType, GMSH_##polytope, dim, order, GmshNumNodes_##polytope(1), GmshNumNodes_##polytope(order), GmshLexOrder_##polytope##_##order}
122*10dd146fSPierre Jolivet // clang-format on
1230598e1a2SLisandro Dalcin 
1240598e1a2SLisandro Dalcin static const GmshCellInfo GmshCellTable[] = {
125066ea43fSLisandro Dalcin   GmshCellEntry(15, VTX, 0, 0),
1260598e1a2SLisandro Dalcin 
1279371c9d4SSatish Balay   GmshCellEntry(1, SEG, 1, 1),   GmshCellEntry(8, SEG, 1, 2),   GmshCellEntry(26, SEG, 1, 3),
1289371c9d4SSatish Balay   GmshCellEntry(27, SEG, 1, 4),  GmshCellEntry(28, SEG, 1, 5),  GmshCellEntry(62, SEG, 1, 6),
1299371c9d4SSatish Balay   GmshCellEntry(63, SEG, 1, 7),  GmshCellEntry(64, SEG, 1, 8),  GmshCellEntry(65, SEG, 1, 9),
130066ea43fSLisandro Dalcin   GmshCellEntry(66, SEG, 1, 10),
1310598e1a2SLisandro Dalcin 
1329371c9d4SSatish Balay   GmshCellEntry(2, TRI, 2, 1),   GmshCellEntry(9, TRI, 2, 2),   GmshCellEntry(21, TRI, 2, 3),
1339371c9d4SSatish Balay   GmshCellEntry(23, TRI, 2, 4),  GmshCellEntry(25, TRI, 2, 5),  GmshCellEntry(42, TRI, 2, 6),
1349371c9d4SSatish Balay   GmshCellEntry(43, TRI, 2, 7),  GmshCellEntry(44, TRI, 2, 8),  GmshCellEntry(45, TRI, 2, 9),
135066ea43fSLisandro Dalcin   GmshCellEntry(46, TRI, 2, 10),
1360598e1a2SLisandro Dalcin 
1379371c9d4SSatish Balay   GmshCellEntry(3, QUA, 2, 1),   GmshCellEntry(10, QUA, 2, 2),  {16, GMSH_QUA, 2, 2, 4, 8,  GmshLexOrder_QUA_2_Serendipity},
1389371c9d4SSatish Balay   GmshCellEntry(36, QUA, 2, 3),  GmshCellEntry(37, QUA, 2, 4),  GmshCellEntry(38, QUA, 2, 5),
1399371c9d4SSatish Balay   GmshCellEntry(47, QUA, 2, 6),  GmshCellEntry(48, QUA, 2, 7),  GmshCellEntry(49, QUA, 2, 8),
1409371c9d4SSatish Balay   GmshCellEntry(50, QUA, 2, 9),  GmshCellEntry(51, QUA, 2, 10),
1410598e1a2SLisandro Dalcin 
1429371c9d4SSatish Balay   GmshCellEntry(4, TET, 3, 1),   GmshCellEntry(11, TET, 3, 2),  GmshCellEntry(29, TET, 3, 3),
1439371c9d4SSatish Balay   GmshCellEntry(30, TET, 3, 4),  GmshCellEntry(31, TET, 3, 5),  GmshCellEntry(71, TET, 3, 6),
1449371c9d4SSatish Balay   GmshCellEntry(72, TET, 3, 7),  GmshCellEntry(73, TET, 3, 8),  GmshCellEntry(74, TET, 3, 9),
145066ea43fSLisandro Dalcin   GmshCellEntry(75, TET, 3, 10),
1460598e1a2SLisandro Dalcin 
1479371c9d4SSatish Balay   GmshCellEntry(5, HEX, 3, 1),   GmshCellEntry(12, HEX, 3, 2),  {17, GMSH_HEX, 3, 2, 8, 20, GmshLexOrder_HEX_2_Serendipity},
1489371c9d4SSatish Balay   GmshCellEntry(92, HEX, 3, 3),  GmshCellEntry(93, HEX, 3, 4),  GmshCellEntry(94, HEX, 3, 5),
1499371c9d4SSatish Balay   GmshCellEntry(95, HEX, 3, 6),  GmshCellEntry(96, HEX, 3, 7),  GmshCellEntry(97, HEX, 3, 8),
1509371c9d4SSatish Balay   GmshCellEntry(98, HEX, 3, 9),  GmshCellEntry(-1, HEX, 3, 10),
1510598e1a2SLisandro Dalcin 
1529371c9d4SSatish Balay   GmshCellEntry(6, PRI, 3, 1),   GmshCellEntry(13, PRI, 3, 2),  GmshCellEntry(90, PRI, 3, 3),
1539371c9d4SSatish Balay   GmshCellEntry(91, PRI, 3, 4),  GmshCellEntry(106, PRI, 3, 5), GmshCellEntry(107, PRI, 3, 6),
1549371c9d4SSatish Balay   GmshCellEntry(108, PRI, 3, 7), GmshCellEntry(109, PRI, 3, 8), GmshCellEntry(110, PRI, 3, 9),
155066ea43fSLisandro Dalcin   GmshCellEntry(-1, PRI, 3, 10),
1560598e1a2SLisandro Dalcin 
1579371c9d4SSatish Balay   GmshCellEntry(7, PYR, 3, 1),   GmshCellEntry(14, PYR, 3, 2),  GmshCellEntry(118, PYR, 3, 3),
1589371c9d4SSatish Balay   GmshCellEntry(119, PYR, 3, 4), GmshCellEntry(120, PYR, 3, 5), GmshCellEntry(121, PYR, 3, 6),
1599371c9d4SSatish Balay   GmshCellEntry(122, PYR, 3, 7), GmshCellEntry(123, PYR, 3, 8), GmshCellEntry(124, PYR, 3, 9),
160066ea43fSLisandro Dalcin   GmshCellEntry(-1, PYR, 3, 10)
1610598e1a2SLisandro Dalcin 
1620598e1a2SLisandro Dalcin #if 0
163066ea43fSLisandro Dalcin   {20, GMSH_TRI, 2, 3, 3,  9, NULL},
164066ea43fSLisandro Dalcin   {18, GMSH_PRI, 3, 2, 6, 15, NULL},
165066ea43fSLisandro Dalcin   {19, GMSH_PYR, 3, 2, 5, 13, NULL},
1660598e1a2SLisandro Dalcin #endif
1670598e1a2SLisandro Dalcin };
1680598e1a2SLisandro Dalcin 
1690598e1a2SLisandro Dalcin static GmshCellInfo GmshCellMap[150];
1700598e1a2SLisandro Dalcin 
171d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshCellInfoSetUp(void)
172d71ae5a4SJacob Faibussowitsch {
1730598e1a2SLisandro Dalcin   size_t           i, n;
1740598e1a2SLisandro Dalcin   static PetscBool called = PETSC_FALSE;
1750598e1a2SLisandro Dalcin 
1760598e1a2SLisandro Dalcin   PetscFunctionBegin;
1774d86920dSPierre Jolivet   if (called) PetscFunctionReturn(PETSC_SUCCESS);
1780598e1a2SLisandro Dalcin   called = PETSC_TRUE;
179dd39110bSPierre Jolivet   n      = PETSC_STATIC_ARRAY_LENGTH(GmshCellMap);
1800598e1a2SLisandro Dalcin   for (i = 0; i < n; ++i) {
1810598e1a2SLisandro Dalcin     GmshCellMap[i].cellType = -1;
182066ea43fSLisandro Dalcin     GmshCellMap[i].polytope = -1;
1830598e1a2SLisandro Dalcin   }
184dd39110bSPierre Jolivet   n = PETSC_STATIC_ARRAY_LENGTH(GmshCellTable);
185066ea43fSLisandro Dalcin   for (i = 0; i < n; ++i) {
186066ea43fSLisandro Dalcin     if (GmshCellTable[i].cellType <= 0) continue;
187066ea43fSLisandro Dalcin     GmshCellMap[GmshCellTable[i].cellType] = GmshCellTable[i];
188066ea43fSLisandro Dalcin   }
1893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1900598e1a2SLisandro Dalcin }
1910598e1a2SLisandro Dalcin 
1929371c9d4SSatish Balay #define GmshCellTypeCheck(ct) \
1939371c9d4SSatish 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_); \
1949371c9d4SSatish Balay                            PetscCheck(GmshCellMap[_ct_].polytope != -1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported Gmsh element type %d", _ct_);)
1950598e1a2SLisandro Dalcin 
1960598e1a2SLisandro Dalcin typedef struct {
197698a79b9SLisandro Dalcin   PetscViewer viewer;
198698a79b9SLisandro Dalcin   int         fileFormat;
199698a79b9SLisandro Dalcin   int         dataSize;
200698a79b9SLisandro Dalcin   PetscBool   binary;
201698a79b9SLisandro Dalcin   PetscBool   byteSwap;
202698a79b9SLisandro Dalcin   size_t      wlen;
203698a79b9SLisandro Dalcin   void       *wbuf;
204698a79b9SLisandro Dalcin   size_t      slen;
205698a79b9SLisandro Dalcin   void       *sbuf;
2060598e1a2SLisandro Dalcin   PetscInt   *nbuf;
2070598e1a2SLisandro Dalcin   PetscInt    nodeStart;
2080598e1a2SLisandro Dalcin   PetscInt    nodeEnd;
20933a088b6SMatthew G. Knepley   PetscInt   *nodeMap;
210698a79b9SLisandro Dalcin } GmshFile;
211de78e4feSLisandro Dalcin 
212d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshBufferGet(GmshFile *gmsh, size_t count, size_t eltsize, void *buf)
213d71ae5a4SJacob Faibussowitsch {
214de78e4feSLisandro Dalcin   size_t size = count * eltsize;
21511c56cb0SLisandro Dalcin 
21611c56cb0SLisandro Dalcin   PetscFunctionBegin;
217698a79b9SLisandro Dalcin   if (gmsh->wlen < size) {
2189566063dSJacob Faibussowitsch     PetscCall(PetscFree(gmsh->wbuf));
2199566063dSJacob Faibussowitsch     PetscCall(PetscMalloc(size, &gmsh->wbuf));
220698a79b9SLisandro Dalcin     gmsh->wlen = size;
221de78e4feSLisandro Dalcin   }
222698a79b9SLisandro Dalcin   *(void **)buf = size ? gmsh->wbuf : NULL;
2233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
224de78e4feSLisandro Dalcin }
225de78e4feSLisandro Dalcin 
226d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshBufferSizeGet(GmshFile *gmsh, size_t count, void *buf)
227d71ae5a4SJacob Faibussowitsch {
228698a79b9SLisandro Dalcin   size_t dataSize = (size_t)gmsh->dataSize;
229698a79b9SLisandro Dalcin   size_t size     = count * dataSize;
230698a79b9SLisandro Dalcin 
231698a79b9SLisandro Dalcin   PetscFunctionBegin;
232698a79b9SLisandro Dalcin   if (gmsh->slen < size) {
2339566063dSJacob Faibussowitsch     PetscCall(PetscFree(gmsh->sbuf));
2349566063dSJacob Faibussowitsch     PetscCall(PetscMalloc(size, &gmsh->sbuf));
235698a79b9SLisandro Dalcin     gmsh->slen = size;
236698a79b9SLisandro Dalcin   }
237698a79b9SLisandro Dalcin   *(void **)buf = size ? gmsh->sbuf : NULL;
2383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
239698a79b9SLisandro Dalcin }
240698a79b9SLisandro Dalcin 
241d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshRead(GmshFile *gmsh, void *buf, PetscInt count, PetscDataType dtype)
242d71ae5a4SJacob Faibussowitsch {
243de78e4feSLisandro Dalcin   PetscFunctionBegin;
2449566063dSJacob Faibussowitsch   PetscCall(PetscViewerRead(gmsh->viewer, buf, count, NULL, dtype));
2459566063dSJacob Faibussowitsch   if (gmsh->byteSwap) PetscCall(PetscByteSwap(buf, dtype, count));
2463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
247698a79b9SLisandro Dalcin }
248698a79b9SLisandro Dalcin 
249d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadString(GmshFile *gmsh, char *buf, PetscInt count)
250d71ae5a4SJacob Faibussowitsch {
251698a79b9SLisandro Dalcin   PetscFunctionBegin;
2529566063dSJacob Faibussowitsch   PetscCall(PetscViewerRead(gmsh->viewer, buf, count, NULL, PETSC_STRING));
2533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
254698a79b9SLisandro Dalcin }
255698a79b9SLisandro Dalcin 
256d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshMatch(PETSC_UNUSED GmshFile *gmsh, const char Section[], char line[PETSC_MAX_PATH_LEN], PetscBool *match)
257d71ae5a4SJacob Faibussowitsch {
258d6689ca9SLisandro Dalcin   PetscFunctionBegin;
2599566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(line, Section, match));
2603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
261d6689ca9SLisandro Dalcin }
262d6689ca9SLisandro Dalcin 
263d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshExpect(GmshFile *gmsh, const char Section[], char line[PETSC_MAX_PATH_LEN])
264d71ae5a4SJacob Faibussowitsch {
265d6689ca9SLisandro Dalcin   PetscBool match;
266d6689ca9SLisandro Dalcin 
267d6689ca9SLisandro Dalcin   PetscFunctionBegin;
2689566063dSJacob Faibussowitsch   PetscCall(GmshMatch(gmsh, Section, line, &match));
26900045ab3SPierre Jolivet   PetscCheck(match, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file, expecting %s, not %s", Section, line);
2703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
271d6689ca9SLisandro Dalcin }
272d6689ca9SLisandro Dalcin 
273d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadSection(GmshFile *gmsh, char line[PETSC_MAX_PATH_LEN])
274d71ae5a4SJacob Faibussowitsch {
275d6689ca9SLisandro Dalcin   PetscBool match;
276d6689ca9SLisandro Dalcin 
277d6689ca9SLisandro Dalcin   PetscFunctionBegin;
278d6689ca9SLisandro Dalcin   while (PETSC_TRUE) {
2799566063dSJacob Faibussowitsch     PetscCall(GmshReadString(gmsh, line, 1));
2809566063dSJacob Faibussowitsch     PetscCall(GmshMatch(gmsh, "$Comments", line, &match));
281d6689ca9SLisandro Dalcin     if (!match) break;
282d6689ca9SLisandro Dalcin     while (PETSC_TRUE) {
2839566063dSJacob Faibussowitsch       PetscCall(GmshReadString(gmsh, line, 1));
2849566063dSJacob Faibussowitsch       PetscCall(GmshMatch(gmsh, "$EndComments", line, &match));
285d6689ca9SLisandro Dalcin       if (match) break;
286d6689ca9SLisandro Dalcin     }
287d6689ca9SLisandro Dalcin   }
2883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
289d6689ca9SLisandro Dalcin }
290d6689ca9SLisandro Dalcin 
291d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadEndSection(GmshFile *gmsh, const char EndSection[], char line[PETSC_MAX_PATH_LEN])
292d71ae5a4SJacob Faibussowitsch {
293d6689ca9SLisandro Dalcin   PetscFunctionBegin;
2949566063dSJacob Faibussowitsch   PetscCall(GmshReadString(gmsh, line, 1));
2959566063dSJacob Faibussowitsch   PetscCall(GmshExpect(gmsh, EndSection, line));
2963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
297d6689ca9SLisandro Dalcin }
298d6689ca9SLisandro Dalcin 
299d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadSize(GmshFile *gmsh, PetscInt *buf, PetscInt count)
300d71ae5a4SJacob Faibussowitsch {
301698a79b9SLisandro Dalcin   PetscInt i;
302698a79b9SLisandro Dalcin   size_t   dataSize = (size_t)gmsh->dataSize;
303698a79b9SLisandro Dalcin 
304698a79b9SLisandro Dalcin   PetscFunctionBegin;
305698a79b9SLisandro Dalcin   if (dataSize == sizeof(PetscInt)) {
3069566063dSJacob Faibussowitsch     PetscCall(GmshRead(gmsh, buf, count, PETSC_INT));
307698a79b9SLisandro Dalcin   } else if (dataSize == sizeof(int)) {
308698a79b9SLisandro Dalcin     int *ibuf = NULL;
3099566063dSJacob Faibussowitsch     PetscCall(GmshBufferSizeGet(gmsh, count, &ibuf));
3109566063dSJacob Faibussowitsch     PetscCall(GmshRead(gmsh, ibuf, count, PETSC_ENUM));
311698a79b9SLisandro Dalcin     for (i = 0; i < count; ++i) buf[i] = (PetscInt)ibuf[i];
312698a79b9SLisandro Dalcin   } else if (dataSize == sizeof(long)) {
313698a79b9SLisandro Dalcin     long *ibuf = NULL;
3149566063dSJacob Faibussowitsch     PetscCall(GmshBufferSizeGet(gmsh, count, &ibuf));
3159566063dSJacob Faibussowitsch     PetscCall(GmshRead(gmsh, ibuf, count, PETSC_LONG));
316698a79b9SLisandro Dalcin     for (i = 0; i < count; ++i) buf[i] = (PetscInt)ibuf[i];
317698a79b9SLisandro Dalcin   } else if (dataSize == sizeof(PetscInt64)) {
318698a79b9SLisandro Dalcin     PetscInt64 *ibuf = NULL;
3199566063dSJacob Faibussowitsch     PetscCall(GmshBufferSizeGet(gmsh, count, &ibuf));
3209566063dSJacob Faibussowitsch     PetscCall(GmshRead(gmsh, ibuf, count, PETSC_INT64));
321698a79b9SLisandro Dalcin     for (i = 0; i < count; ++i) buf[i] = (PetscInt)ibuf[i];
322698a79b9SLisandro Dalcin   }
3233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
324698a79b9SLisandro Dalcin }
325698a79b9SLisandro Dalcin 
326d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadInt(GmshFile *gmsh, int *buf, PetscInt count)
327d71ae5a4SJacob Faibussowitsch {
328698a79b9SLisandro Dalcin   PetscFunctionBegin;
3299566063dSJacob Faibussowitsch   PetscCall(GmshRead(gmsh, buf, count, PETSC_ENUM));
3303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
331698a79b9SLisandro Dalcin }
332698a79b9SLisandro Dalcin 
333d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadDouble(GmshFile *gmsh, double *buf, PetscInt count)
334d71ae5a4SJacob Faibussowitsch {
335698a79b9SLisandro Dalcin   PetscFunctionBegin;
3369566063dSJacob Faibussowitsch   PetscCall(GmshRead(gmsh, buf, count, PETSC_DOUBLE));
3373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
338de78e4feSLisandro Dalcin }
339de78e4feSLisandro Dalcin 
3409c0edc59SMatthew G. Knepley #define GMSH_MAX_TAGS 16
3417d5b9244SMatthew G. Knepley 
342de78e4feSLisandro Dalcin typedef struct {
3430598e1a2SLisandro Dalcin   PetscInt id;                  /* Entity ID */
3440598e1a2SLisandro Dalcin   PetscInt dim;                 /* Dimension */
345de78e4feSLisandro Dalcin   double   bbox[6];             /* Bounding box */
346de78e4feSLisandro Dalcin   PetscInt numTags;             /* Size of tag array */
3477d5b9244SMatthew G. Knepley   int      tags[GMSH_MAX_TAGS]; /* Tag array */
348de78e4feSLisandro Dalcin } GmshEntity;
349de78e4feSLisandro Dalcin 
350de78e4feSLisandro Dalcin typedef struct {
351730356f6SLisandro Dalcin   GmshEntity *entity[4];
352730356f6SLisandro Dalcin   PetscHMapI  entityMap[4];
353730356f6SLisandro Dalcin } GmshEntities;
354730356f6SLisandro Dalcin 
355d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshEntitiesCreate(PetscInt count[4], GmshEntities **entities)
356d71ae5a4SJacob Faibussowitsch {
357730356f6SLisandro Dalcin   PetscInt dim;
358730356f6SLisandro Dalcin 
359730356f6SLisandro Dalcin   PetscFunctionBegin;
3609566063dSJacob Faibussowitsch   PetscCall(PetscNew(entities));
361730356f6SLisandro Dalcin   for (dim = 0; dim < 4; ++dim) {
3629566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(count[dim], &(*entities)->entity[dim]));
3639566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&(*entities)->entityMap[dim]));
364730356f6SLisandro Dalcin   }
3653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
366730356f6SLisandro Dalcin }
367730356f6SLisandro Dalcin 
368d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshEntitiesDestroy(GmshEntities **entities)
369d71ae5a4SJacob Faibussowitsch {
3700598e1a2SLisandro Dalcin   PetscInt dim;
3710598e1a2SLisandro Dalcin 
3720598e1a2SLisandro Dalcin   PetscFunctionBegin;
3733ba16761SJacob Faibussowitsch   if (!*entities) PetscFunctionReturn(PETSC_SUCCESS);
3740598e1a2SLisandro Dalcin   for (dim = 0; dim < 4; ++dim) {
3759566063dSJacob Faibussowitsch     PetscCall(PetscFree((*entities)->entity[dim]));
3769566063dSJacob Faibussowitsch     PetscCall(PetscHMapIDestroy(&(*entities)->entityMap[dim]));
3770598e1a2SLisandro Dalcin   }
378f4f49eeaSPierre Jolivet   PetscCall(PetscFree(*entities));
3793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3800598e1a2SLisandro Dalcin }
3810598e1a2SLisandro Dalcin 
382d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshEntitiesAdd(GmshEntities *entities, PetscInt index, PetscInt dim, PetscInt eid, GmshEntity **entity)
383d71ae5a4SJacob Faibussowitsch {
384730356f6SLisandro Dalcin   PetscFunctionBegin;
3859566063dSJacob Faibussowitsch   PetscCall(PetscHMapISet(entities->entityMap[dim], eid, index));
386730356f6SLisandro Dalcin   entities->entity[dim][index].dim = dim;
387730356f6SLisandro Dalcin   entities->entity[dim][index].id  = eid;
388730356f6SLisandro Dalcin   if (entity) *entity = &entities->entity[dim][index];
3893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
390730356f6SLisandro Dalcin }
391730356f6SLisandro Dalcin 
392d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshEntitiesGet(GmshEntities *entities, PetscInt dim, PetscInt eid, GmshEntity **entity)
393d71ae5a4SJacob Faibussowitsch {
394730356f6SLisandro Dalcin   PetscInt index;
395730356f6SLisandro Dalcin 
396730356f6SLisandro Dalcin   PetscFunctionBegin;
3979566063dSJacob Faibussowitsch   PetscCall(PetscHMapIGet(entities->entityMap[dim], eid, &index));
398730356f6SLisandro Dalcin   *entity = &entities->entity[dim][index];
3993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
400730356f6SLisandro Dalcin }
401730356f6SLisandro Dalcin 
4020598e1a2SLisandro Dalcin typedef struct {
4030598e1a2SLisandro Dalcin   PetscInt *id;  /* Node IDs */
4040598e1a2SLisandro Dalcin   double   *xyz; /* Coordinates */
40581a1af93SMatthew G. Knepley   PetscInt *tag; /* Physical tag */
4060598e1a2SLisandro Dalcin } GmshNodes;
4070598e1a2SLisandro Dalcin 
408d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshNodesCreate(PetscInt count, GmshNodes **nodes)
409d71ae5a4SJacob Faibussowitsch {
410730356f6SLisandro Dalcin   PetscFunctionBegin;
4119566063dSJacob Faibussowitsch   PetscCall(PetscNew(nodes));
4129566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(count * 1, &(*nodes)->id));
4139566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(count * 3, &(*nodes)->xyz));
4147d5b9244SMatthew G. Knepley   PetscCall(PetscMalloc1(count * GMSH_MAX_TAGS, &(*nodes)->tag));
4153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
416730356f6SLisandro Dalcin }
4170598e1a2SLisandro Dalcin 
418d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshNodesDestroy(GmshNodes **nodes)
419d71ae5a4SJacob Faibussowitsch {
4200598e1a2SLisandro Dalcin   PetscFunctionBegin;
4213ba16761SJacob Faibussowitsch   if (!*nodes) PetscFunctionReturn(PETSC_SUCCESS);
4229566063dSJacob Faibussowitsch   PetscCall(PetscFree((*nodes)->id));
4239566063dSJacob Faibussowitsch   PetscCall(PetscFree((*nodes)->xyz));
4249566063dSJacob Faibussowitsch   PetscCall(PetscFree((*nodes)->tag));
425f4f49eeaSPierre Jolivet   PetscCall(PetscFree(*nodes));
4263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
427730356f6SLisandro Dalcin }
428730356f6SLisandro Dalcin 
429730356f6SLisandro Dalcin typedef struct {
4300598e1a2SLisandro Dalcin   PetscInt  id;                  /* Element ID */
4310598e1a2SLisandro Dalcin   PetscInt  dim;                 /* Dimension */
432de78e4feSLisandro Dalcin   PetscInt  cellType;            /* Cell type */
4330598e1a2SLisandro Dalcin   PetscInt  numVerts;            /* Size of vertex array */
434de78e4feSLisandro Dalcin   PetscInt  numNodes;            /* Size of node array */
4350598e1a2SLisandro Dalcin   PetscInt *nodes;               /* Vertex/Node array */
43681a1af93SMatthew G. Knepley   PetscInt  numTags;             /* Size of physical tag array */
4377d5b9244SMatthew G. Knepley   int       tags[GMSH_MAX_TAGS]; /* Physical tag array */
438de78e4feSLisandro Dalcin } GmshElement;
439de78e4feSLisandro Dalcin 
440d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshElementsCreate(PetscInt count, GmshElement **elements)
441d71ae5a4SJacob Faibussowitsch {
4420598e1a2SLisandro Dalcin   PetscFunctionBegin;
4439566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(count, elements));
4443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4450598e1a2SLisandro Dalcin }
4460598e1a2SLisandro Dalcin 
447d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshElementsDestroy(GmshElement **elements)
448d71ae5a4SJacob Faibussowitsch {
4490598e1a2SLisandro Dalcin   PetscFunctionBegin;
4503ba16761SJacob Faibussowitsch   if (!*elements) PetscFunctionReturn(PETSC_SUCCESS);
4519566063dSJacob Faibussowitsch   PetscCall(PetscFree(*elements));
4523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4530598e1a2SLisandro Dalcin }
4540598e1a2SLisandro Dalcin 
4550598e1a2SLisandro Dalcin typedef struct {
4560598e1a2SLisandro Dalcin   PetscInt       dim;
457066ea43fSLisandro Dalcin   PetscInt       order;
4580598e1a2SLisandro Dalcin   GmshEntities  *entities;
4590598e1a2SLisandro Dalcin   PetscInt       numNodes;
4600598e1a2SLisandro Dalcin   GmshNodes     *nodelist;
4610598e1a2SLisandro Dalcin   PetscInt       numElems;
4620598e1a2SLisandro Dalcin   GmshElement   *elements;
4630598e1a2SLisandro Dalcin   PetscInt       numVerts;
4640598e1a2SLisandro Dalcin   PetscInt       numCells;
4650598e1a2SLisandro Dalcin   PetscInt      *periodMap;
4660598e1a2SLisandro Dalcin   PetscInt      *vertexMap;
4670598e1a2SLisandro Dalcin   PetscSegBuffer segbuf;
468a45dabc8SMatthew G. Knepley   PetscInt       numRegions;
46990d778b8SLisandro Dalcin   PetscInt      *regionDims;
470a45dabc8SMatthew G. Knepley   PetscInt      *regionTags;
471a45dabc8SMatthew G. Knepley   char         **regionNames;
4720598e1a2SLisandro Dalcin } GmshMesh;
4730598e1a2SLisandro Dalcin 
474d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshMeshCreate(GmshMesh **mesh)
475d71ae5a4SJacob Faibussowitsch {
4760598e1a2SLisandro Dalcin   PetscFunctionBegin;
4779566063dSJacob Faibussowitsch   PetscCall(PetscNew(mesh));
4789566063dSJacob Faibussowitsch   PetscCall(PetscSegBufferCreate(sizeof(PetscInt), 0, &(*mesh)->segbuf));
4793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4800598e1a2SLisandro Dalcin }
4810598e1a2SLisandro Dalcin 
482d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshMeshDestroy(GmshMesh **mesh)
483d71ae5a4SJacob Faibussowitsch {
484a45dabc8SMatthew G. Knepley   PetscInt r;
4850598e1a2SLisandro Dalcin 
4860598e1a2SLisandro Dalcin   PetscFunctionBegin;
4873ba16761SJacob Faibussowitsch   if (!*mesh) PetscFunctionReturn(PETSC_SUCCESS);
4889566063dSJacob Faibussowitsch   PetscCall(GmshEntitiesDestroy(&(*mesh)->entities));
4899566063dSJacob Faibussowitsch   PetscCall(GmshNodesDestroy(&(*mesh)->nodelist));
4909566063dSJacob Faibussowitsch   PetscCall(GmshElementsDestroy(&(*mesh)->elements));
4919566063dSJacob Faibussowitsch   PetscCall(PetscFree((*mesh)->periodMap));
4929566063dSJacob Faibussowitsch   PetscCall(PetscFree((*mesh)->vertexMap));
4939566063dSJacob Faibussowitsch   PetscCall(PetscSegBufferDestroy(&(*mesh)->segbuf));
4949566063dSJacob Faibussowitsch   for (r = 0; r < (*mesh)->numRegions; ++r) PetscCall(PetscFree((*mesh)->regionNames[r]));
49590d778b8SLisandro Dalcin   PetscCall(PetscFree3((*mesh)->regionDims, (*mesh)->regionTags, (*mesh)->regionNames));
496f4f49eeaSPierre Jolivet   PetscCall(PetscFree(*mesh));
4973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4980598e1a2SLisandro Dalcin }
4990598e1a2SLisandro Dalcin 
500d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadNodes_v22(GmshFile *gmsh, GmshMesh *mesh)
501d71ae5a4SJacob Faibussowitsch {
502698a79b9SLisandro Dalcin   PetscViewer viewer   = gmsh->viewer;
503698a79b9SLisandro Dalcin   PetscBool   byteSwap = gmsh->byteSwap;
504de78e4feSLisandro Dalcin   char        line[PETSC_MAX_PATH_LEN];
5057d5b9244SMatthew G. Knepley   int         n, t, num, nid, snum;
5060598e1a2SLisandro Dalcin   GmshNodes  *nodes;
507de78e4feSLisandro Dalcin 
508de78e4feSLisandro Dalcin   PetscFunctionBegin;
5099566063dSJacob Faibussowitsch   PetscCall(PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING));
510698a79b9SLisandro Dalcin   snum = sscanf(line, "%d", &num);
51108401ef6SPierre Jolivet   PetscCheck(snum == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
5129566063dSJacob Faibussowitsch   PetscCall(GmshNodesCreate(num, &nodes));
5130598e1a2SLisandro Dalcin   mesh->numNodes = num;
5140598e1a2SLisandro Dalcin   mesh->nodelist = nodes;
5150598e1a2SLisandro Dalcin   for (n = 0; n < num; ++n) {
5160598e1a2SLisandro Dalcin     double *xyz = nodes->xyz + n * 3;
5179566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, &nid, 1, NULL, PETSC_ENUM));
5189566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, xyz, 3, NULL, PETSC_DOUBLE));
5199566063dSJacob Faibussowitsch     if (byteSwap) PetscCall(PetscByteSwap(&nid, PETSC_ENUM, 1));
5209566063dSJacob Faibussowitsch     if (byteSwap) PetscCall(PetscByteSwap(xyz, PETSC_DOUBLE, 3));
5210598e1a2SLisandro Dalcin     nodes->id[n] = nid;
5227d5b9244SMatthew G. Knepley     for (t = 0; t < GMSH_MAX_TAGS; ++t) nodes->tag[n * GMSH_MAX_TAGS + t] = -1;
52311c56cb0SLisandro Dalcin   }
5243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
52511c56cb0SLisandro Dalcin }
52611c56cb0SLisandro Dalcin 
527de78e4feSLisandro Dalcin /* Gmsh elements can be of any dimension/co-dimension, so we need to traverse the
528de78e4feSLisandro Dalcin    file contents multiple times to figure out the true number of cells and facets
529de78e4feSLisandro Dalcin    in the given mesh. To make this more efficient we read the file contents only
530de78e4feSLisandro Dalcin    once and store them in memory, while determining the true number of cells. */
531d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadElements_v22(GmshFile *gmsh, GmshMesh *mesh)
532d71ae5a4SJacob Faibussowitsch {
533698a79b9SLisandro Dalcin   PetscViewer  viewer   = gmsh->viewer;
534698a79b9SLisandro Dalcin   PetscBool    binary   = gmsh->binary;
535698a79b9SLisandro Dalcin   PetscBool    byteSwap = gmsh->byteSwap;
536de78e4feSLisandro Dalcin   char         line[PETSC_MAX_PATH_LEN];
5370598e1a2SLisandro Dalcin   int          i, c, p, num, ibuf[1 + 4 + 1000], snum;
5380598e1a2SLisandro Dalcin   int          cellType, numElem, numVerts, numNodes, numTags;
539df032b82SMatthew G. Knepley   GmshElement *elements;
5400598e1a2SLisandro Dalcin   PetscInt    *nodeMap = gmsh->nodeMap;
541df032b82SMatthew G. Knepley 
542df032b82SMatthew G. Knepley   PetscFunctionBegin;
5439566063dSJacob Faibussowitsch   PetscCall(PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING));
544698a79b9SLisandro Dalcin   snum = sscanf(line, "%d", &num);
54508401ef6SPierre Jolivet   PetscCheck(snum == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
5469566063dSJacob Faibussowitsch   PetscCall(GmshElementsCreate(num, &elements));
5470598e1a2SLisandro Dalcin   mesh->numElems = num;
5480598e1a2SLisandro Dalcin   mesh->elements = elements;
549698a79b9SLisandro Dalcin   for (c = 0; c < num;) {
5509566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, ibuf, 3, NULL, PETSC_ENUM));
5519566063dSJacob Faibussowitsch     if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, 3));
5520598e1a2SLisandro Dalcin 
5530598e1a2SLisandro Dalcin     cellType = binary ? ibuf[0] : ibuf[1];
5540598e1a2SLisandro Dalcin     numElem  = binary ? ibuf[1] : 1;
555df032b82SMatthew G. Knepley     numTags  = ibuf[2];
5560598e1a2SLisandro Dalcin 
5579566063dSJacob Faibussowitsch     PetscCall(GmshCellTypeCheck(cellType));
5580598e1a2SLisandro Dalcin     numVerts = GmshCellMap[cellType].numVerts;
5590598e1a2SLisandro Dalcin     numNodes = GmshCellMap[cellType].numNodes;
5600598e1a2SLisandro Dalcin 
561df032b82SMatthew G. Knepley     for (i = 0; i < numElem; ++i, ++c) {
5620598e1a2SLisandro Dalcin       GmshElement *element = elements + c;
5630598e1a2SLisandro Dalcin       const int    off = binary ? 0 : 1, nint = 1 + numTags + numNodes - off;
5640598e1a2SLisandro Dalcin       const int   *id = ibuf, *nodes = ibuf + 1 + numTags, *tags = ibuf + 1;
5659566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, ibuf + off, nint, NULL, PETSC_ENUM));
5669566063dSJacob Faibussowitsch       if (byteSwap) PetscCall(PetscByteSwap(ibuf + off, PETSC_ENUM, nint));
5670598e1a2SLisandro Dalcin       element->id       = id[0];
5680598e1a2SLisandro Dalcin       element->dim      = GmshCellMap[cellType].dim;
5690598e1a2SLisandro Dalcin       element->cellType = cellType;
5700598e1a2SLisandro Dalcin       element->numVerts = numVerts;
5710598e1a2SLisandro Dalcin       element->numNodes = numNodes;
5727d5b9244SMatthew G. Knepley       element->numTags  = PetscMin(numTags, GMSH_MAX_TAGS);
5739566063dSJacob Faibussowitsch       PetscCall(PetscSegBufferGet(mesh->segbuf, (size_t)element->numNodes, &element->nodes));
5740598e1a2SLisandro Dalcin       for (p = 0; p < element->numNodes; p++) element->nodes[p] = nodeMap[nodes[p]];
5750598e1a2SLisandro Dalcin       for (p = 0; p < element->numTags; p++) element->tags[p] = tags[p];
576df032b82SMatthew G. Knepley     }
577df032b82SMatthew G. Knepley   }
5783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
579df032b82SMatthew G. Knepley }
5807d282ae0SMichael Lange 
581de78e4feSLisandro Dalcin /*
582de78e4feSLisandro Dalcin $Entities
583de78e4feSLisandro Dalcin   numPoints(unsigned long) numCurves(unsigned long)
584de78e4feSLisandro Dalcin     numSurfaces(unsigned long) numVolumes(unsigned long)
585de78e4feSLisandro Dalcin   // points
586de78e4feSLisandro Dalcin   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
587de78e4feSLisandro Dalcin     boxMaxX(double) boxMaxY(double) boxMaxZ(double)
588de78e4feSLisandro Dalcin     numPhysicals(unsigned long) phyisicalTag[...](int)
589de78e4feSLisandro Dalcin   ...
590de78e4feSLisandro Dalcin   // curves
591de78e4feSLisandro Dalcin   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
592de78e4feSLisandro Dalcin      boxMaxX(double) boxMaxY(double) boxMaxZ(double)
593de78e4feSLisandro Dalcin      numPhysicals(unsigned long) physicalTag[...](int)
594de78e4feSLisandro Dalcin      numBREPVert(unsigned long) tagBREPVert[...](int)
595de78e4feSLisandro Dalcin   ...
596de78e4feSLisandro Dalcin   // surfaces
597de78e4feSLisandro Dalcin   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
598de78e4feSLisandro Dalcin     boxMaxX(double) boxMaxY(double) boxMaxZ(double)
599de78e4feSLisandro Dalcin     numPhysicals(unsigned long) physicalTag[...](int)
600de78e4feSLisandro Dalcin     numBREPCurve(unsigned long) tagBREPCurve[...](int)
601de78e4feSLisandro Dalcin   ...
602de78e4feSLisandro Dalcin   // volumes
603de78e4feSLisandro Dalcin   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
604de78e4feSLisandro Dalcin     boxMaxX(double) boxMaxY(double) boxMaxZ(double)
605de78e4feSLisandro Dalcin     numPhysicals(unsigned long) physicalTag[...](int)
606de78e4feSLisandro Dalcin     numBREPSurfaces(unsigned long) tagBREPSurfaces[...](int)
607de78e4feSLisandro Dalcin   ...
608de78e4feSLisandro Dalcin $EndEntities
609de78e4feSLisandro Dalcin */
610d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadEntities_v40(GmshFile *gmsh, GmshMesh *mesh)
611d71ae5a4SJacob Faibussowitsch {
612698a79b9SLisandro Dalcin   PetscViewer viewer   = gmsh->viewer;
613698a79b9SLisandro Dalcin   PetscBool   byteSwap = gmsh->byteSwap;
614698a79b9SLisandro Dalcin   long        index, num, lbuf[4];
615730356f6SLisandro Dalcin   int         dim, eid, numTags, *ibuf, t;
616698a79b9SLisandro Dalcin   PetscInt    count[4], i;
617a5ba3d71SLisandro Dalcin   GmshEntity *entity = NULL;
618de78e4feSLisandro Dalcin 
619de78e4feSLisandro Dalcin   PetscFunctionBegin;
6209566063dSJacob Faibussowitsch   PetscCall(PetscViewerRead(viewer, lbuf, 4, NULL, PETSC_LONG));
6219566063dSJacob Faibussowitsch   if (byteSwap) PetscCall(PetscByteSwap(lbuf, PETSC_LONG, 4));
622698a79b9SLisandro Dalcin   for (i = 0; i < 4; ++i) count[i] = lbuf[i];
6239566063dSJacob Faibussowitsch   PetscCall(GmshEntitiesCreate(count, &mesh->entities));
624de78e4feSLisandro Dalcin   for (dim = 0; dim < 4; ++dim) {
625730356f6SLisandro Dalcin     for (index = 0; index < count[dim]; ++index) {
6269566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, &eid, 1, NULL, PETSC_ENUM));
6279566063dSJacob Faibussowitsch       if (byteSwap) PetscCall(PetscByteSwap(&eid, PETSC_ENUM, 1));
6289566063dSJacob Faibussowitsch       PetscCall(GmshEntitiesAdd(mesh->entities, (PetscInt)index, dim, eid, &entity));
6299566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, entity->bbox, 6, NULL, PETSC_DOUBLE));
6309566063dSJacob Faibussowitsch       if (byteSwap) PetscCall(PetscByteSwap(entity->bbox, PETSC_DOUBLE, 6));
6319566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, &num, 1, NULL, PETSC_LONG));
6329566063dSJacob Faibussowitsch       if (byteSwap) PetscCall(PetscByteSwap(&num, PETSC_LONG, 1));
6339566063dSJacob Faibussowitsch       PetscCall(GmshBufferGet(gmsh, num, sizeof(int), &ibuf));
6349566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, ibuf, num, NULL, PETSC_ENUM));
6359566063dSJacob Faibussowitsch       if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, num));
6367d5b9244SMatthew G. Knepley       entity->numTags = numTags = (int)PetscMin(num, GMSH_MAX_TAGS);
637de78e4feSLisandro Dalcin       for (t = 0; t < numTags; ++t) entity->tags[t] = ibuf[t];
638de78e4feSLisandro Dalcin       if (dim == 0) continue;
6399566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, &num, 1, NULL, PETSC_LONG));
6409566063dSJacob Faibussowitsch       if (byteSwap) PetscCall(PetscByteSwap(&num, PETSC_LONG, 1));
6419566063dSJacob Faibussowitsch       PetscCall(GmshBufferGet(gmsh, num, sizeof(int), &ibuf));
6429566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, ibuf, num, NULL, PETSC_ENUM));
6439566063dSJacob Faibussowitsch       if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, num));
644de78e4feSLisandro Dalcin     }
645de78e4feSLisandro Dalcin   }
6463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
647de78e4feSLisandro Dalcin }
648de78e4feSLisandro Dalcin 
649de78e4feSLisandro Dalcin /*
650de78e4feSLisandro Dalcin $Nodes
651de78e4feSLisandro Dalcin   numEntityBlocks(unsigned long) numNodes(unsigned long)
652de78e4feSLisandro Dalcin   tagEntity(int) dimEntity(int) typeNode(int) numNodes(unsigned long)
653de78e4feSLisandro Dalcin     tag(int) x(double) y(double) z(double)
654de78e4feSLisandro Dalcin     ...
655de78e4feSLisandro Dalcin   ...
656de78e4feSLisandro Dalcin $EndNodes
657de78e4feSLisandro Dalcin */
658d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadNodes_v40(GmshFile *gmsh, GmshMesh *mesh)
659d71ae5a4SJacob Faibussowitsch {
660698a79b9SLisandro Dalcin   PetscViewer viewer   = gmsh->viewer;
661698a79b9SLisandro Dalcin   PetscBool   byteSwap = gmsh->byteSwap;
6627d5b9244SMatthew G. Knepley   long        block, node, n, t, numEntityBlocks, numTotalNodes, numNodes;
663de78e4feSLisandro Dalcin   int         info[3], nid;
6640598e1a2SLisandro Dalcin   GmshNodes  *nodes;
665de78e4feSLisandro Dalcin 
666de78e4feSLisandro Dalcin   PetscFunctionBegin;
6679566063dSJacob Faibussowitsch   PetscCall(PetscViewerRead(viewer, &numEntityBlocks, 1, NULL, PETSC_LONG));
6689566063dSJacob Faibussowitsch   if (byteSwap) PetscCall(PetscByteSwap(&numEntityBlocks, PETSC_LONG, 1));
6699566063dSJacob Faibussowitsch   PetscCall(PetscViewerRead(viewer, &numTotalNodes, 1, NULL, PETSC_LONG));
6709566063dSJacob Faibussowitsch   if (byteSwap) PetscCall(PetscByteSwap(&numTotalNodes, PETSC_LONG, 1));
6719566063dSJacob Faibussowitsch   PetscCall(GmshNodesCreate(numTotalNodes, &nodes));
6720598e1a2SLisandro Dalcin   mesh->numNodes = numTotalNodes;
6730598e1a2SLisandro Dalcin   mesh->nodelist = nodes;
6740598e1a2SLisandro Dalcin   for (n = 0, block = 0; block < numEntityBlocks; ++block) {
6759566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, info, 3, NULL, PETSC_ENUM));
6769566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, &numNodes, 1, NULL, PETSC_LONG));
6779566063dSJacob Faibussowitsch     if (byteSwap) PetscCall(PetscByteSwap(&numNodes, PETSC_LONG, 1));
678698a79b9SLisandro Dalcin     if (gmsh->binary) {
679277f51e8SBarry Smith       size_t nbytes = sizeof(int) + 3 * sizeof(double);
680da81f932SPierre Jolivet       char  *cbuf   = NULL; /* dummy value to prevent warning from compiler about possible uninitialized value */
6819566063dSJacob Faibussowitsch       PetscCall(GmshBufferGet(gmsh, numNodes, nbytes, &cbuf));
6829566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, cbuf, numNodes * nbytes, NULL, PETSC_CHAR));
6830598e1a2SLisandro Dalcin       for (node = 0; node < numNodes; ++node, ++n) {
684de78e4feSLisandro Dalcin         char   *cnid = cbuf + node * nbytes, *cxyz = cnid + sizeof(int);
6850598e1a2SLisandro Dalcin         double *xyz = nodes->xyz + n * 3;
6869566063dSJacob Faibussowitsch         if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(cnid, PETSC_ENUM, 1));
6879566063dSJacob Faibussowitsch         if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(cxyz, PETSC_DOUBLE, 3));
6889566063dSJacob Faibussowitsch         PetscCall(PetscMemcpy(&nid, cnid, sizeof(int)));
6899566063dSJacob Faibussowitsch         PetscCall(PetscMemcpy(xyz, cxyz, 3 * sizeof(double)));
6909566063dSJacob Faibussowitsch         if (byteSwap) PetscCall(PetscByteSwap(&nid, PETSC_ENUM, 1));
6919566063dSJacob Faibussowitsch         if (byteSwap) PetscCall(PetscByteSwap(xyz, PETSC_DOUBLE, 3));
6920598e1a2SLisandro Dalcin         nodes->id[n] = nid;
6937d5b9244SMatthew G. Knepley         for (t = 0; t < GMSH_MAX_TAGS; ++t) nodes->tag[n * GMSH_MAX_TAGS + t] = -1;
694de78e4feSLisandro Dalcin       }
695de78e4feSLisandro Dalcin     } else {
6960598e1a2SLisandro Dalcin       for (node = 0; node < numNodes; ++node, ++n) {
6970598e1a2SLisandro Dalcin         double *xyz = nodes->xyz + n * 3;
6989566063dSJacob Faibussowitsch         PetscCall(PetscViewerRead(viewer, &nid, 1, NULL, PETSC_ENUM));
6999566063dSJacob Faibussowitsch         PetscCall(PetscViewerRead(viewer, xyz, 3, NULL, PETSC_DOUBLE));
7009566063dSJacob Faibussowitsch         if (byteSwap) PetscCall(PetscByteSwap(&nid, PETSC_ENUM, 1));
7019566063dSJacob Faibussowitsch         if (byteSwap) PetscCall(PetscByteSwap(xyz, PETSC_DOUBLE, 3));
7020598e1a2SLisandro Dalcin         nodes->id[n] = nid;
7037d5b9244SMatthew G. Knepley         for (t = 0; t < GMSH_MAX_TAGS; ++t) nodes->tag[n * GMSH_MAX_TAGS + t] = -1;
704de78e4feSLisandro Dalcin       }
705de78e4feSLisandro Dalcin     }
706de78e4feSLisandro Dalcin   }
7073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
708de78e4feSLisandro Dalcin }
709de78e4feSLisandro Dalcin 
710de78e4feSLisandro Dalcin /*
711de78e4feSLisandro Dalcin $Elements
712de78e4feSLisandro Dalcin   numEntityBlocks(unsigned long) numElements(unsigned long)
713de78e4feSLisandro Dalcin   tagEntity(int) dimEntity(int) typeEle(int) numElements(unsigned long)
714de78e4feSLisandro Dalcin     tag(int) numVert[...](int)
715de78e4feSLisandro Dalcin     ...
716de78e4feSLisandro Dalcin   ...
717de78e4feSLisandro Dalcin $EndElements
718de78e4feSLisandro Dalcin */
719d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadElements_v40(GmshFile *gmsh, GmshMesh *mesh)
720d71ae5a4SJacob Faibussowitsch {
721698a79b9SLisandro Dalcin   PetscViewer  viewer   = gmsh->viewer;
722698a79b9SLisandro Dalcin   PetscBool    byteSwap = gmsh->byteSwap;
723de78e4feSLisandro Dalcin   long         c, block, numEntityBlocks, numTotalElements, elem, numElements;
724de78e4feSLisandro Dalcin   int          p, info[3], *ibuf = NULL;
7250598e1a2SLisandro Dalcin   int          eid, dim, cellType, numVerts, numNodes, numTags;
726a5ba3d71SLisandro Dalcin   GmshEntity  *entity = NULL;
727de78e4feSLisandro Dalcin   GmshElement *elements;
7280598e1a2SLisandro Dalcin   PetscInt    *nodeMap = gmsh->nodeMap;
729de78e4feSLisandro Dalcin 
730de78e4feSLisandro Dalcin   PetscFunctionBegin;
7319566063dSJacob Faibussowitsch   PetscCall(PetscViewerRead(viewer, &numEntityBlocks, 1, NULL, PETSC_LONG));
7329566063dSJacob Faibussowitsch   if (byteSwap) PetscCall(PetscByteSwap(&numEntityBlocks, PETSC_LONG, 1));
7339566063dSJacob Faibussowitsch   PetscCall(PetscViewerRead(viewer, &numTotalElements, 1, NULL, PETSC_LONG));
7349566063dSJacob Faibussowitsch   if (byteSwap) PetscCall(PetscByteSwap(&numTotalElements, PETSC_LONG, 1));
7359566063dSJacob Faibussowitsch   PetscCall(GmshElementsCreate(numTotalElements, &elements));
7360598e1a2SLisandro Dalcin   mesh->numElems = numTotalElements;
7370598e1a2SLisandro Dalcin   mesh->elements = elements;
738de78e4feSLisandro Dalcin   for (c = 0, block = 0; block < numEntityBlocks; ++block) {
7399566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, info, 3, NULL, PETSC_ENUM));
7409566063dSJacob Faibussowitsch     if (byteSwap) PetscCall(PetscByteSwap(info, PETSC_ENUM, 3));
7419371c9d4SSatish Balay     eid      = info[0];
7429371c9d4SSatish Balay     dim      = info[1];
7439371c9d4SSatish Balay     cellType = info[2];
7449566063dSJacob Faibussowitsch     PetscCall(GmshEntitiesGet(mesh->entities, dim, eid, &entity));
7459566063dSJacob Faibussowitsch     PetscCall(GmshCellTypeCheck(cellType));
7460598e1a2SLisandro Dalcin     numVerts = GmshCellMap[cellType].numVerts;
7470598e1a2SLisandro Dalcin     numNodes = GmshCellMap[cellType].numNodes;
748730356f6SLisandro Dalcin     numTags  = entity->numTags;
7499566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, &numElements, 1, NULL, PETSC_LONG));
7509566063dSJacob Faibussowitsch     if (byteSwap) PetscCall(PetscByteSwap(&numElements, PETSC_LONG, 1));
7519566063dSJacob Faibussowitsch     PetscCall(GmshBufferGet(gmsh, (1 + numNodes) * numElements, sizeof(int), &ibuf));
7529566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, ibuf, (1 + numNodes) * numElements, NULL, PETSC_ENUM));
7539566063dSJacob Faibussowitsch     if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, (1 + numNodes) * numElements));
754de78e4feSLisandro Dalcin     for (elem = 0; elem < numElements; ++elem, ++c) {
755de78e4feSLisandro Dalcin       GmshElement *element = elements + c;
7560598e1a2SLisandro Dalcin       const int   *id = ibuf + elem * (1 + numNodes), *nodes = id + 1;
7570598e1a2SLisandro Dalcin       element->id       = id[0];
758de78e4feSLisandro Dalcin       element->dim      = dim;
759de78e4feSLisandro Dalcin       element->cellType = cellType;
7600598e1a2SLisandro Dalcin       element->numVerts = numVerts;
761de78e4feSLisandro Dalcin       element->numNodes = numNodes;
762de78e4feSLisandro Dalcin       element->numTags  = numTags;
7639566063dSJacob Faibussowitsch       PetscCall(PetscSegBufferGet(mesh->segbuf, (size_t)element->numNodes, &element->nodes));
7640598e1a2SLisandro Dalcin       for (p = 0; p < element->numNodes; p++) element->nodes[p] = nodeMap[nodes[p]];
7650598e1a2SLisandro Dalcin       for (p = 0; p < element->numTags; p++) element->tags[p] = entity->tags[p];
766de78e4feSLisandro Dalcin     }
767de78e4feSLisandro Dalcin   }
7683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
769698a79b9SLisandro Dalcin }
770698a79b9SLisandro Dalcin 
771d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadPeriodic_v40(GmshFile *gmsh, PetscInt periodicMap[])
772d71ae5a4SJacob Faibussowitsch {
773698a79b9SLisandro Dalcin   PetscViewer viewer     = gmsh->viewer;
774698a79b9SLisandro Dalcin   int         fileFormat = gmsh->fileFormat;
775698a79b9SLisandro Dalcin   PetscBool   binary     = gmsh->binary;
776698a79b9SLisandro Dalcin   PetscBool   byteSwap   = gmsh->byteSwap;
777698a79b9SLisandro Dalcin   int         numPeriodic, snum, i;
778698a79b9SLisandro Dalcin   char        line[PETSC_MAX_PATH_LEN];
7790598e1a2SLisandro Dalcin   PetscInt   *nodeMap = gmsh->nodeMap;
780698a79b9SLisandro Dalcin 
781698a79b9SLisandro Dalcin   PetscFunctionBegin;
782698a79b9SLisandro Dalcin   if (fileFormat == 22 || !binary) {
7839566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING));
784698a79b9SLisandro Dalcin     snum = sscanf(line, "%d", &numPeriodic);
78508401ef6SPierre Jolivet     PetscCheck(snum == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
786698a79b9SLisandro Dalcin   } else {
7879566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, &numPeriodic, 1, NULL, PETSC_ENUM));
7889566063dSJacob Faibussowitsch     if (byteSwap) PetscCall(PetscByteSwap(&numPeriodic, PETSC_ENUM, 1));
789698a79b9SLisandro Dalcin   }
790698a79b9SLisandro Dalcin   for (i = 0; i < numPeriodic; i++) {
7919dddd249SSatish Balay     int    ibuf[3], correspondingDim = -1, correspondingTag = -1, primaryTag = -1, correspondingNode, primaryNode;
792698a79b9SLisandro Dalcin     long   j, nNodes;
793698a79b9SLisandro Dalcin     double affine[16];
794698a79b9SLisandro Dalcin 
795698a79b9SLisandro Dalcin     if (fileFormat == 22 || !binary) {
7969566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, line, 3, NULL, PETSC_STRING));
7979dddd249SSatish Balay       snum = sscanf(line, "%d %d %d", &correspondingDim, &correspondingTag, &primaryTag);
79808401ef6SPierre Jolivet       PetscCheck(snum == 3, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
799698a79b9SLisandro Dalcin     } else {
8009566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, ibuf, 3, NULL, PETSC_ENUM));
8019566063dSJacob Faibussowitsch       if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, 3));
8029371c9d4SSatish Balay       correspondingDim = ibuf[0];
8039371c9d4SSatish Balay       correspondingTag = ibuf[1];
8049371c9d4SSatish Balay       primaryTag       = ibuf[2];
805698a79b9SLisandro Dalcin     }
8069371c9d4SSatish Balay     (void)correspondingDim;
8079371c9d4SSatish Balay     (void)correspondingTag;
8089371c9d4SSatish Balay     (void)primaryTag; /* unused */
809698a79b9SLisandro Dalcin 
810698a79b9SLisandro Dalcin     if (fileFormat == 22 || !binary) {
8119566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING));
812698a79b9SLisandro Dalcin       snum = sscanf(line, "%ld", &nNodes);
8134c500f23SPierre Jolivet       if (snum != 1) { /* discard transformation and try again */
8149566063dSJacob Faibussowitsch         PetscCall(PetscViewerRead(viewer, line, -PETSC_MAX_PATH_LEN, NULL, PETSC_STRING));
8159566063dSJacob Faibussowitsch         PetscCall(PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING));
816698a79b9SLisandro Dalcin         snum = sscanf(line, "%ld", &nNodes);
81708401ef6SPierre Jolivet         PetscCheck(snum == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
818698a79b9SLisandro Dalcin       }
819698a79b9SLisandro Dalcin     } else {
8209566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, &nNodes, 1, NULL, PETSC_LONG));
8219566063dSJacob Faibussowitsch       if (byteSwap) PetscCall(PetscByteSwap(&nNodes, PETSC_LONG, 1));
8224c500f23SPierre Jolivet       if (nNodes == -1) { /* discard transformation and try again */
8239566063dSJacob Faibussowitsch         PetscCall(PetscViewerRead(viewer, affine, 16, NULL, PETSC_DOUBLE));
8249566063dSJacob Faibussowitsch         PetscCall(PetscViewerRead(viewer, &nNodes, 1, NULL, PETSC_LONG));
8259566063dSJacob Faibussowitsch         if (byteSwap) PetscCall(PetscByteSwap(&nNodes, PETSC_LONG, 1));
826698a79b9SLisandro Dalcin       }
827698a79b9SLisandro Dalcin     }
828698a79b9SLisandro Dalcin 
829698a79b9SLisandro Dalcin     for (j = 0; j < nNodes; j++) {
830698a79b9SLisandro Dalcin       if (fileFormat == 22 || !binary) {
8319566063dSJacob Faibussowitsch         PetscCall(PetscViewerRead(viewer, line, 2, NULL, PETSC_STRING));
8329dddd249SSatish Balay         snum = sscanf(line, "%d %d", &correspondingNode, &primaryNode);
83308401ef6SPierre Jolivet         PetscCheck(snum == 2, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
834698a79b9SLisandro Dalcin       } else {
8359566063dSJacob Faibussowitsch         PetscCall(PetscViewerRead(viewer, ibuf, 2, NULL, PETSC_ENUM));
8369566063dSJacob Faibussowitsch         if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, 2));
8379371c9d4SSatish Balay         correspondingNode = ibuf[0];
8389371c9d4SSatish Balay         primaryNode       = ibuf[1];
839698a79b9SLisandro Dalcin       }
8409dddd249SSatish Balay       correspondingNode              = (int)nodeMap[correspondingNode];
8419dddd249SSatish Balay       primaryNode                    = (int)nodeMap[primaryNode];
8429dddd249SSatish Balay       periodicMap[correspondingNode] = primaryNode;
843698a79b9SLisandro Dalcin     }
844698a79b9SLisandro Dalcin   }
8453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
846698a79b9SLisandro Dalcin }
847698a79b9SLisandro Dalcin 
8480598e1a2SLisandro Dalcin /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
849698a79b9SLisandro Dalcin $Entities
850698a79b9SLisandro Dalcin   numPoints(size_t) numCurves(size_t)
851698a79b9SLisandro Dalcin     numSurfaces(size_t) numVolumes(size_t)
852698a79b9SLisandro Dalcin   pointTag(int) X(double) Y(double) Z(double)
853698a79b9SLisandro Dalcin     numPhysicalTags(size_t) physicalTag(int) ...
854698a79b9SLisandro Dalcin   ...
855698a79b9SLisandro Dalcin   curveTag(int) minX(double) minY(double) minZ(double)
856698a79b9SLisandro Dalcin     maxX(double) maxY(double) maxZ(double)
857698a79b9SLisandro Dalcin     numPhysicalTags(size_t) physicalTag(int) ...
858698a79b9SLisandro Dalcin     numBoundingPoints(size_t) pointTag(int) ...
859698a79b9SLisandro Dalcin   ...
860698a79b9SLisandro Dalcin   surfaceTag(int) minX(double) minY(double) minZ(double)
861698a79b9SLisandro Dalcin     maxX(double) maxY(double) maxZ(double)
862698a79b9SLisandro Dalcin     numPhysicalTags(size_t) physicalTag(int) ...
863698a79b9SLisandro Dalcin     numBoundingCurves(size_t) curveTag(int) ...
864698a79b9SLisandro Dalcin   ...
865698a79b9SLisandro Dalcin   volumeTag(int) minX(double) minY(double) minZ(double)
866698a79b9SLisandro Dalcin     maxX(double) maxY(double) maxZ(double)
867698a79b9SLisandro Dalcin     numPhysicalTags(size_t) physicalTag(int) ...
868698a79b9SLisandro Dalcin     numBoundngSurfaces(size_t) surfaceTag(int) ...
869698a79b9SLisandro Dalcin   ...
870698a79b9SLisandro Dalcin $EndEntities
871698a79b9SLisandro Dalcin */
872d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadEntities_v41(GmshFile *gmsh, GmshMesh *mesh)
873d71ae5a4SJacob Faibussowitsch {
874698a79b9SLisandro Dalcin   PetscInt    count[4], index, numTags, i;
875698a79b9SLisandro Dalcin   int         dim, eid, *tags = NULL;
876698a79b9SLisandro Dalcin   GmshEntity *entity = NULL;
877698a79b9SLisandro Dalcin 
878698a79b9SLisandro Dalcin   PetscFunctionBegin;
8799566063dSJacob Faibussowitsch   PetscCall(GmshReadSize(gmsh, count, 4));
8809566063dSJacob Faibussowitsch   PetscCall(GmshEntitiesCreate(count, &mesh->entities));
881698a79b9SLisandro Dalcin   for (dim = 0; dim < 4; ++dim) {
882698a79b9SLisandro Dalcin     for (index = 0; index < count[dim]; ++index) {
8839566063dSJacob Faibussowitsch       PetscCall(GmshReadInt(gmsh, &eid, 1));
8849566063dSJacob Faibussowitsch       PetscCall(GmshEntitiesAdd(mesh->entities, (PetscInt)index, dim, eid, &entity));
8859566063dSJacob Faibussowitsch       PetscCall(GmshReadDouble(gmsh, entity->bbox, (dim == 0) ? 3 : 6));
8869566063dSJacob Faibussowitsch       PetscCall(GmshReadSize(gmsh, &numTags, 1));
8879566063dSJacob Faibussowitsch       PetscCall(GmshBufferGet(gmsh, numTags, sizeof(int), &tags));
8889566063dSJacob Faibussowitsch       PetscCall(GmshReadInt(gmsh, tags, numTags));
8899c0edc59SMatthew 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);
8907d5b9244SMatthew G. Knepley       entity->numTags = numTags;
891698a79b9SLisandro Dalcin       for (i = 0; i < entity->numTags; ++i) entity->tags[i] = tags[i];
892698a79b9SLisandro Dalcin       if (dim == 0) continue;
8939566063dSJacob Faibussowitsch       PetscCall(GmshReadSize(gmsh, &numTags, 1));
8949566063dSJacob Faibussowitsch       PetscCall(GmshBufferGet(gmsh, numTags, sizeof(int), &tags));
8959566063dSJacob Faibussowitsch       PetscCall(GmshReadInt(gmsh, tags, numTags));
89681a1af93SMatthew G. Knepley       /* Currently, we do not save the ids for the bounding entities */
897698a79b9SLisandro Dalcin     }
898698a79b9SLisandro Dalcin   }
8993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
900698a79b9SLisandro Dalcin }
901698a79b9SLisandro Dalcin 
90233a088b6SMatthew G. Knepley /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
903698a79b9SLisandro Dalcin $Nodes
904698a79b9SLisandro Dalcin   numEntityBlocks(size_t) numNodes(size_t)
905698a79b9SLisandro Dalcin     minNodeTag(size_t) maxNodeTag(size_t)
906698a79b9SLisandro Dalcin   entityDim(int) entityTag(int) parametric(int; 0 or 1) numNodesBlock(size_t)
907698a79b9SLisandro Dalcin     nodeTag(size_t)
908698a79b9SLisandro Dalcin     ...
909698a79b9SLisandro Dalcin     x(double) y(double) z(double)
910698a79b9SLisandro Dalcin        < u(double; if parametric and entityDim = 1 or entityDim = 2) >
911698a79b9SLisandro Dalcin        < v(double; if parametric and entityDim = 2) >
912698a79b9SLisandro Dalcin     ...
913698a79b9SLisandro Dalcin   ...
914698a79b9SLisandro Dalcin $EndNodes
915698a79b9SLisandro Dalcin */
916d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadNodes_v41(GmshFile *gmsh, GmshMesh *mesh)
917d71ae5a4SJacob Faibussowitsch {
91881a1af93SMatthew G. Knepley   int         info[3], dim, eid, parametric;
9197d5b9244SMatthew G. Knepley   PetscInt    sizes[4], numEntityBlocks, numTags, t, numNodes, numNodesBlock = 0, block, node, n;
92081a1af93SMatthew G. Knepley   GmshEntity *entity = NULL;
9210598e1a2SLisandro Dalcin   GmshNodes  *nodes;
922698a79b9SLisandro Dalcin 
923698a79b9SLisandro Dalcin   PetscFunctionBegin;
9249566063dSJacob Faibussowitsch   PetscCall(GmshReadSize(gmsh, sizes, 4));
9259371c9d4SSatish Balay   numEntityBlocks = sizes[0];
9269371c9d4SSatish Balay   numNodes        = sizes[1];
9279566063dSJacob Faibussowitsch   PetscCall(GmshNodesCreate(numNodes, &nodes));
9280598e1a2SLisandro Dalcin   mesh->numNodes = numNodes;
9290598e1a2SLisandro Dalcin   mesh->nodelist = nodes;
930698a79b9SLisandro Dalcin   for (block = 0, node = 0; block < numEntityBlocks; ++block, node += numNodesBlock) {
9319566063dSJacob Faibussowitsch     PetscCall(GmshReadInt(gmsh, info, 3));
9329371c9d4SSatish Balay     dim        = info[0];
9339371c9d4SSatish Balay     eid        = info[1];
9349371c9d4SSatish Balay     parametric = info[2];
9359566063dSJacob Faibussowitsch     PetscCall(GmshEntitiesGet(mesh->entities, dim, eid, &entity));
9367d5b9244SMatthew G. Knepley     numTags = entity->numTags;
93781a1af93SMatthew G. Knepley     PetscCheck(!parametric, PETSC_COMM_SELF, PETSC_ERR_SUP, "Parametric coordinates not supported");
9389566063dSJacob Faibussowitsch     PetscCall(GmshReadSize(gmsh, &numNodesBlock, 1));
9399566063dSJacob Faibussowitsch     PetscCall(GmshReadSize(gmsh, nodes->id + node, numNodesBlock));
9409566063dSJacob Faibussowitsch     PetscCall(GmshReadDouble(gmsh, nodes->xyz + node * 3, numNodesBlock * 3));
9417d5b9244SMatthew G. Knepley     for (n = 0; n < numNodesBlock; ++n) {
9427d5b9244SMatthew G. Knepley       PetscInt *tags = &nodes->tag[node * GMSH_MAX_TAGS];
9437d5b9244SMatthew G. Knepley 
9447d5b9244SMatthew G. Knepley       for (t = 0; t < numTags; ++t) tags[n * GMSH_MAX_TAGS + t] = entity->tags[t];
9457d5b9244SMatthew G. Knepley       for (t = numTags; t < GMSH_MAX_TAGS; ++t) tags[n * GMSH_MAX_TAGS + t] = -1;
9467d5b9244SMatthew G. Knepley     }
947698a79b9SLisandro Dalcin   }
9480598e1a2SLisandro Dalcin   gmsh->nodeStart = sizes[2];
9490598e1a2SLisandro Dalcin   gmsh->nodeEnd   = sizes[3] + 1;
9503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
951698a79b9SLisandro Dalcin }
952698a79b9SLisandro Dalcin 
95333a088b6SMatthew G. Knepley /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
954698a79b9SLisandro Dalcin $Elements
955698a79b9SLisandro Dalcin   numEntityBlocks(size_t) numElements(size_t)
956698a79b9SLisandro Dalcin     minElementTag(size_t) maxElementTag(size_t)
957698a79b9SLisandro Dalcin   entityDim(int) entityTag(int) elementType(int; see below) numElementsBlock(size_t)
958698a79b9SLisandro Dalcin     elementTag(size_t) nodeTag(size_t) ...
959698a79b9SLisandro Dalcin     ...
960698a79b9SLisandro Dalcin   ...
961698a79b9SLisandro Dalcin $EndElements
962698a79b9SLisandro Dalcin */
963d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadElements_v41(GmshFile *gmsh, GmshMesh *mesh)
964d71ae5a4SJacob Faibussowitsch {
9650598e1a2SLisandro Dalcin   int          info[3], eid, dim, cellType;
9660598e1a2SLisandro Dalcin   PetscInt     sizes[4], *ibuf = NULL, numEntityBlocks, numElements, numBlockElements, numVerts, numNodes, numTags, block, elem, c, p;
967698a79b9SLisandro Dalcin   GmshEntity  *entity = NULL;
968698a79b9SLisandro Dalcin   GmshElement *elements;
9690598e1a2SLisandro Dalcin   PetscInt    *nodeMap = gmsh->nodeMap;
970698a79b9SLisandro Dalcin 
971698a79b9SLisandro Dalcin   PetscFunctionBegin;
9729566063dSJacob Faibussowitsch   PetscCall(GmshReadSize(gmsh, sizes, 4));
9739371c9d4SSatish Balay   numEntityBlocks = sizes[0];
9749371c9d4SSatish Balay   numElements     = sizes[1];
9759566063dSJacob Faibussowitsch   PetscCall(GmshElementsCreate(numElements, &elements));
9760598e1a2SLisandro Dalcin   mesh->numElems = numElements;
9770598e1a2SLisandro Dalcin   mesh->elements = elements;
978698a79b9SLisandro Dalcin   for (c = 0, block = 0; block < numEntityBlocks; ++block) {
9799566063dSJacob Faibussowitsch     PetscCall(GmshReadInt(gmsh, info, 3));
9809371c9d4SSatish Balay     dim      = info[0];
9819371c9d4SSatish Balay     eid      = info[1];
9829371c9d4SSatish Balay     cellType = info[2];
9839566063dSJacob Faibussowitsch     PetscCall(GmshEntitiesGet(mesh->entities, dim, eid, &entity));
9849566063dSJacob Faibussowitsch     PetscCall(GmshCellTypeCheck(cellType));
9850598e1a2SLisandro Dalcin     numVerts = GmshCellMap[cellType].numVerts;
9860598e1a2SLisandro Dalcin     numNodes = GmshCellMap[cellType].numNodes;
9877d5b9244SMatthew G. Knepley     numTags  = entity->numTags;
9889566063dSJacob Faibussowitsch     PetscCall(GmshReadSize(gmsh, &numBlockElements, 1));
9899566063dSJacob Faibussowitsch     PetscCall(GmshBufferGet(gmsh, (1 + numNodes) * numBlockElements, sizeof(PetscInt), &ibuf));
9909566063dSJacob Faibussowitsch     PetscCall(GmshReadSize(gmsh, ibuf, (1 + numNodes) * numBlockElements));
991698a79b9SLisandro Dalcin     for (elem = 0; elem < numBlockElements; ++elem, ++c) {
992698a79b9SLisandro Dalcin       GmshElement    *element = elements + c;
9930598e1a2SLisandro Dalcin       const PetscInt *id = ibuf + elem * (1 + numNodes), *nodes = id + 1;
994698a79b9SLisandro Dalcin       element->id       = id[0];
995698a79b9SLisandro Dalcin       element->dim      = dim;
996698a79b9SLisandro Dalcin       element->cellType = cellType;
9970598e1a2SLisandro Dalcin       element->numVerts = numVerts;
998698a79b9SLisandro Dalcin       element->numNodes = numNodes;
999698a79b9SLisandro Dalcin       element->numTags  = numTags;
10009566063dSJacob Faibussowitsch       PetscCall(PetscSegBufferGet(mesh->segbuf, (size_t)element->numNodes, &element->nodes));
10010598e1a2SLisandro Dalcin       for (p = 0; p < element->numNodes; p++) element->nodes[p] = nodeMap[nodes[p]];
10020598e1a2SLisandro Dalcin       for (p = 0; p < element->numTags; p++) element->tags[p] = entity->tags[p];
1003698a79b9SLisandro Dalcin     }
1004698a79b9SLisandro Dalcin   }
10053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1006698a79b9SLisandro Dalcin }
1007698a79b9SLisandro Dalcin 
10080598e1a2SLisandro Dalcin /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
1009698a79b9SLisandro Dalcin $Periodic
1010698a79b9SLisandro Dalcin   numPeriodicLinks(size_t)
10119dddd249SSatish Balay   entityDim(int) entityTag(int) entityTagPrimary(int)
1012698a79b9SLisandro Dalcin   numAffine(size_t) value(double) ...
1013698a79b9SLisandro Dalcin   numCorrespondingNodes(size_t)
10149dddd249SSatish Balay     nodeTag(size_t) nodeTagPrimary(size_t)
1015698a79b9SLisandro Dalcin     ...
1016698a79b9SLisandro Dalcin   ...
1017698a79b9SLisandro Dalcin $EndPeriodic
1018698a79b9SLisandro Dalcin */
1019d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadPeriodic_v41(GmshFile *gmsh, PetscInt periodicMap[])
1020d71ae5a4SJacob Faibussowitsch {
1021698a79b9SLisandro Dalcin   int       info[3];
1022698a79b9SLisandro Dalcin   double    dbuf[16];
10230598e1a2SLisandro Dalcin   PetscInt  numPeriodicLinks, numAffine, numCorrespondingNodes, *nodeTags = NULL, link, node;
10240598e1a2SLisandro Dalcin   PetscInt *nodeMap = gmsh->nodeMap;
1025698a79b9SLisandro Dalcin 
1026698a79b9SLisandro Dalcin   PetscFunctionBegin;
10279566063dSJacob Faibussowitsch   PetscCall(GmshReadSize(gmsh, &numPeriodicLinks, 1));
1028698a79b9SLisandro Dalcin   for (link = 0; link < numPeriodicLinks; ++link) {
10299566063dSJacob Faibussowitsch     PetscCall(GmshReadInt(gmsh, info, 3));
10309566063dSJacob Faibussowitsch     PetscCall(GmshReadSize(gmsh, &numAffine, 1));
10319566063dSJacob Faibussowitsch     PetscCall(GmshReadDouble(gmsh, dbuf, numAffine));
10329566063dSJacob Faibussowitsch     PetscCall(GmshReadSize(gmsh, &numCorrespondingNodes, 1));
10339566063dSJacob Faibussowitsch     PetscCall(GmshBufferGet(gmsh, numCorrespondingNodes, sizeof(PetscInt), &nodeTags));
10349566063dSJacob Faibussowitsch     PetscCall(GmshReadSize(gmsh, nodeTags, numCorrespondingNodes * 2));
1035698a79b9SLisandro Dalcin     for (node = 0; node < numCorrespondingNodes; ++node) {
10369dddd249SSatish Balay       PetscInt correspondingNode     = nodeMap[nodeTags[node * 2 + 0]];
10379dddd249SSatish Balay       PetscInt primaryNode           = nodeMap[nodeTags[node * 2 + 1]];
10389dddd249SSatish Balay       periodicMap[correspondingNode] = primaryNode;
1039698a79b9SLisandro Dalcin     }
1040698a79b9SLisandro Dalcin   }
10413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1042698a79b9SLisandro Dalcin }
1043698a79b9SLisandro Dalcin 
10440598e1a2SLisandro Dalcin /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
1045d6689ca9SLisandro Dalcin $MeshFormat // same as MSH version 2
1046d6689ca9SLisandro Dalcin   version(ASCII double; currently 4.1)
1047d6689ca9SLisandro Dalcin   file-type(ASCII int; 0 for ASCII mode, 1 for binary mode)
1048d6689ca9SLisandro Dalcin   data-size(ASCII int; sizeof(size_t))
1049d6689ca9SLisandro Dalcin   < int with value one; only in binary mode, to detect endianness >
1050d6689ca9SLisandro Dalcin $EndMeshFormat
1051d6689ca9SLisandro Dalcin */
1052d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadMeshFormat(GmshFile *gmsh)
1053d71ae5a4SJacob Faibussowitsch {
1054698a79b9SLisandro Dalcin   char  line[PETSC_MAX_PATH_LEN];
1055698a79b9SLisandro Dalcin   int   snum, fileType, fileFormat, dataSize, checkEndian;
1056698a79b9SLisandro Dalcin   float version;
1057698a79b9SLisandro Dalcin 
1058698a79b9SLisandro Dalcin   PetscFunctionBegin;
10599566063dSJacob Faibussowitsch   PetscCall(GmshReadString(gmsh, line, 3));
1060698a79b9SLisandro Dalcin   snum       = sscanf(line, "%f %d %d", &version, &fileType, &dataSize);
1061a8d4e440SJunchao Zhang   fileFormat = (int)roundf(version * 10);
106208401ef6SPierre Jolivet   PetscCheck(snum == 3, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to parse Gmsh file header: %s", line);
1063a8d4e440SJunchao Zhang   PetscCheck(fileFormat >= 22, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at least 2.2", (double)version);
10641dca8a05SBarry Smith   PetscCheck((int)version != 3, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f not supported", (double)version);
1065a8d4e440SJunchao Zhang   PetscCheck(fileFormat <= 41, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at most 4.1", (double)version);
106608401ef6SPierre Jolivet   PetscCheck(!gmsh->binary || fileType, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Viewer is binary but Gmsh file is ASCII");
106708401ef6SPierre Jolivet   PetscCheck(gmsh->binary || !fileType, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Viewer is ASCII but Gmsh file is binary");
10681dca8a05SBarry 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);
10691dca8a05SBarry 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);
1070698a79b9SLisandro Dalcin   gmsh->fileFormat = fileFormat;
1071698a79b9SLisandro Dalcin   gmsh->dataSize   = dataSize;
1072698a79b9SLisandro Dalcin   gmsh->byteSwap   = PETSC_FALSE;
1073698a79b9SLisandro Dalcin   if (gmsh->binary) {
10749566063dSJacob Faibussowitsch     PetscCall(GmshReadInt(gmsh, &checkEndian, 1));
1075698a79b9SLisandro Dalcin     if (checkEndian != 1) {
10769566063dSJacob Faibussowitsch       PetscCall(PetscByteSwap(&checkEndian, PETSC_ENUM, 1));
107708401ef6SPierre Jolivet       PetscCheck(checkEndian == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to detect endianness in Gmsh file header: %s", line);
1078698a79b9SLisandro Dalcin       gmsh->byteSwap = PETSC_TRUE;
1079698a79b9SLisandro Dalcin     }
1080698a79b9SLisandro Dalcin   }
10813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1082698a79b9SLisandro Dalcin }
1083698a79b9SLisandro Dalcin 
10848749820aSMatthew G. Knepley /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
10858749820aSMatthew G. Knepley Neper: https://neper.info/ adds this section
10868749820aSMatthew G. Knepley 
10878749820aSMatthew G. Knepley $MeshVersion
10888749820aSMatthew G. Knepley   <major>.<minor>,<patch>
10898749820aSMatthew G. Knepley $EndMeshVersion
10908749820aSMatthew G. Knepley */
10918749820aSMatthew G. Knepley static PetscErrorCode GmshReadMeshVersion(GmshFile *gmsh)
10928749820aSMatthew G. Knepley {
10938749820aSMatthew G. Knepley   char line[PETSC_MAX_PATH_LEN];
10948749820aSMatthew G. Knepley   int  snum, major, minor, patch;
10958749820aSMatthew G. Knepley 
10968749820aSMatthew G. Knepley   PetscFunctionBegin;
10978749820aSMatthew G. Knepley   PetscCall(GmshReadString(gmsh, line, 1));
10988749820aSMatthew G. Knepley   snum = sscanf(line, "%d.%d.%d", &major, &minor, &patch);
10998749820aSMatthew G. Knepley   PetscCheck(snum == 3, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to parse Gmsh file header: %s", line);
11008749820aSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
11018749820aSMatthew G. Knepley }
11028749820aSMatthew G. Knepley 
11038749820aSMatthew G. Knepley /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
11048749820aSMatthew G. Knepley Neper: https://neper.info/ adds this section
11058749820aSMatthew G. Knepley 
11068749820aSMatthew G. Knepley $Domain
11078749820aSMatthew G. Knepley   <shape>
11088749820aSMatthew G. Knepley $EndDomain
11098749820aSMatthew G. Knepley */
11108749820aSMatthew G. Knepley static PetscErrorCode GmshReadMeshDomain(GmshFile *gmsh)
11118749820aSMatthew G. Knepley {
11128749820aSMatthew G. Knepley   char line[PETSC_MAX_PATH_LEN];
11138749820aSMatthew G. Knepley 
11148749820aSMatthew G. Knepley   PetscFunctionBegin;
11158749820aSMatthew G. Knepley   PetscCall(GmshReadString(gmsh, line, 1));
11168749820aSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
11178749820aSMatthew G. Knepley }
11188749820aSMatthew G. Knepley 
11191f643af3SLisandro Dalcin /*
11201f643af3SLisandro Dalcin PhysicalNames
11211f643af3SLisandro Dalcin   numPhysicalNames(ASCII int)
11221f643af3SLisandro Dalcin   dimension(ASCII int) physicalTag(ASCII int) "name"(127 characters max)
11231f643af3SLisandro Dalcin   ...
11241f643af3SLisandro Dalcin $EndPhysicalNames
11251f643af3SLisandro Dalcin */
1126d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadPhysicalNames(GmshFile *gmsh, GmshMesh *mesh)
1127d71ae5a4SJacob Faibussowitsch {
1128bbcf679cSJacob Faibussowitsch   char line[PETSC_MAX_PATH_LEN], name[128 + 2], *p = NULL, *q = NULL, *r = NULL;
1129a45dabc8SMatthew G. Knepley   int  snum, region, dim, tag;
1130698a79b9SLisandro Dalcin 
1131698a79b9SLisandro Dalcin   PetscFunctionBegin;
11329566063dSJacob Faibussowitsch   PetscCall(GmshReadString(gmsh, line, 1));
1133a45dabc8SMatthew G. Knepley   snum             = sscanf(line, "%d", &region);
1134a45dabc8SMatthew G. Knepley   mesh->numRegions = region;
113508401ef6SPierre Jolivet   PetscCheck(snum == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
113690d778b8SLisandro Dalcin   PetscCall(PetscMalloc3(mesh->numRegions, &mesh->regionDims, mesh->numRegions, &mesh->regionTags, mesh->numRegions, &mesh->regionNames));
1137a45dabc8SMatthew G. Knepley   for (region = 0; region < mesh->numRegions; ++region) {
11389566063dSJacob Faibussowitsch     PetscCall(GmshReadString(gmsh, line, 2));
11391f643af3SLisandro Dalcin     snum = sscanf(line, "%d %d", &dim, &tag);
114008401ef6SPierre Jolivet     PetscCheck(snum == 2, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
11419566063dSJacob Faibussowitsch     PetscCall(GmshReadString(gmsh, line, -(PetscInt)sizeof(line)));
11429566063dSJacob Faibussowitsch     PetscCall(PetscStrchr(line, '"', &p));
114328b400f6SJacob Faibussowitsch     PetscCheck(p, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
11449566063dSJacob Faibussowitsch     PetscCall(PetscStrrchr(line, '"', &q));
114508401ef6SPierre Jolivet     PetscCheck(q != p, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
11465f5cd6d5SMatthew G. Knepley     PetscCall(PetscStrrchr(line, ':', &r));
11475f5cd6d5SMatthew G. Knepley     if (p != r) q = r;
11489566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(name, p + 1, (size_t)(q - p - 1)));
114990d778b8SLisandro Dalcin     mesh->regionDims[region] = dim;
1150a45dabc8SMatthew G. Knepley     mesh->regionTags[region] = tag;
11519566063dSJacob Faibussowitsch     PetscCall(PetscStrallocpy(name, &mesh->regionNames[region]));
1152698a79b9SLisandro Dalcin   }
11533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1154de78e4feSLisandro Dalcin }
1155de78e4feSLisandro Dalcin 
1156d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadEntities(GmshFile *gmsh, GmshMesh *mesh)
1157d71ae5a4SJacob Faibussowitsch {
11580598e1a2SLisandro Dalcin   PetscFunctionBegin;
11590598e1a2SLisandro Dalcin   switch (gmsh->fileFormat) {
1160d71ae5a4SJacob Faibussowitsch   case 41:
1161d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadEntities_v41(gmsh, mesh));
1162d71ae5a4SJacob Faibussowitsch     break;
1163d71ae5a4SJacob Faibussowitsch   default:
1164d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadEntities_v40(gmsh, mesh));
1165d71ae5a4SJacob Faibussowitsch     break;
116696ca5757SLisandro Dalcin   }
11673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
11680598e1a2SLisandro Dalcin }
11690598e1a2SLisandro Dalcin 
1170d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadNodes(GmshFile *gmsh, GmshMesh *mesh)
1171d71ae5a4SJacob Faibussowitsch {
11720598e1a2SLisandro Dalcin   PetscFunctionBegin;
11730598e1a2SLisandro Dalcin   switch (gmsh->fileFormat) {
1174d71ae5a4SJacob Faibussowitsch   case 41:
1175d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadNodes_v41(gmsh, mesh));
1176d71ae5a4SJacob Faibussowitsch     break;
1177d71ae5a4SJacob Faibussowitsch   case 40:
1178d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadNodes_v40(gmsh, mesh));
1179d71ae5a4SJacob Faibussowitsch     break;
1180d71ae5a4SJacob Faibussowitsch   default:
1181d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadNodes_v22(gmsh, mesh));
1182d71ae5a4SJacob Faibussowitsch     break;
11830598e1a2SLisandro Dalcin   }
11840598e1a2SLisandro Dalcin 
11850598e1a2SLisandro Dalcin   { /* Gmsh v2.2/v4.0 does not provide min/max node tags */
11860598e1a2SLisandro Dalcin     if (mesh->numNodes > 0 && gmsh->nodeEnd >= gmsh->nodeStart) {
11870598e1a2SLisandro Dalcin       PetscInt   tagMin = PETSC_MAX_INT, tagMax = PETSC_MIN_INT, n;
11880598e1a2SLisandro Dalcin       GmshNodes *nodes = mesh->nodelist;
11890598e1a2SLisandro Dalcin       for (n = 0; n < mesh->numNodes; ++n) {
11900598e1a2SLisandro Dalcin         const PetscInt tag = nodes->id[n];
11910598e1a2SLisandro Dalcin         tagMin             = PetscMin(tag, tagMin);
11920598e1a2SLisandro Dalcin         tagMax             = PetscMax(tag, tagMax);
11930598e1a2SLisandro Dalcin       }
11940598e1a2SLisandro Dalcin       gmsh->nodeStart = tagMin;
11950598e1a2SLisandro Dalcin       gmsh->nodeEnd   = tagMax + 1;
11960598e1a2SLisandro Dalcin     }
11970598e1a2SLisandro Dalcin   }
11980598e1a2SLisandro Dalcin 
11990598e1a2SLisandro Dalcin   { /* Support for sparse node tags */
12000598e1a2SLisandro Dalcin     PetscInt   n, t;
12010598e1a2SLisandro Dalcin     GmshNodes *nodes = mesh->nodelist;
12029566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(gmsh->nodeEnd - gmsh->nodeStart, &gmsh->nbuf));
12030598e1a2SLisandro Dalcin     for (t = 0; t < gmsh->nodeEnd - gmsh->nodeStart; ++t) gmsh->nbuf[t] = PETSC_MIN_INT;
12040598e1a2SLisandro Dalcin     gmsh->nodeMap = gmsh->nbuf - gmsh->nodeStart;
12050598e1a2SLisandro Dalcin     for (n = 0; n < mesh->numNodes; ++n) {
12060598e1a2SLisandro Dalcin       const PetscInt tag = nodes->id[n];
120763a3b9bcSJacob Faibussowitsch       PetscCheck(gmsh->nodeMap[tag] < 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Repeated node tag %" PetscInt_FMT, tag);
12080598e1a2SLisandro Dalcin       gmsh->nodeMap[tag] = n;
12090598e1a2SLisandro Dalcin     }
12100598e1a2SLisandro Dalcin   }
12113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12120598e1a2SLisandro Dalcin }
12130598e1a2SLisandro Dalcin 
1214d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadElements(GmshFile *gmsh, GmshMesh *mesh)
1215d71ae5a4SJacob Faibussowitsch {
12160598e1a2SLisandro Dalcin   PetscFunctionBegin;
12170598e1a2SLisandro Dalcin   switch (gmsh->fileFormat) {
1218d71ae5a4SJacob Faibussowitsch   case 41:
1219d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadElements_v41(gmsh, mesh));
1220d71ae5a4SJacob Faibussowitsch     break;
1221d71ae5a4SJacob Faibussowitsch   case 40:
1222d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadElements_v40(gmsh, mesh));
1223d71ae5a4SJacob Faibussowitsch     break;
1224d71ae5a4SJacob Faibussowitsch   default:
1225d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadElements_v22(gmsh, mesh));
1226d71ae5a4SJacob Faibussowitsch     break;
12270598e1a2SLisandro Dalcin   }
12280598e1a2SLisandro Dalcin 
12290598e1a2SLisandro Dalcin   { /* Reorder elements by codimension and polytope type */
12300598e1a2SLisandro Dalcin     PetscInt     ne       = mesh->numElems;
12310598e1a2SLisandro Dalcin     GmshElement *elements = mesh->elements;
1232066ea43fSLisandro Dalcin     PetscInt     keymap[GMSH_NUM_POLYTOPES], nk = 0;
1233066ea43fSLisandro Dalcin     PetscInt     offset[GMSH_NUM_POLYTOPES + 1], e, k;
12340598e1a2SLisandro Dalcin 
1235066ea43fSLisandro Dalcin     for (k = 0; k < GMSH_NUM_POLYTOPES; ++k) keymap[k] = PETSC_MIN_INT;
12369566063dSJacob Faibussowitsch     PetscCall(PetscMemzero(offset, sizeof(offset)));
12370598e1a2SLisandro Dalcin 
1238066ea43fSLisandro Dalcin     keymap[GMSH_TET] = nk++;
1239066ea43fSLisandro Dalcin     keymap[GMSH_HEX] = nk++;
1240066ea43fSLisandro Dalcin     keymap[GMSH_PRI] = nk++;
1241066ea43fSLisandro Dalcin     keymap[GMSH_PYR] = nk++;
1242066ea43fSLisandro Dalcin     keymap[GMSH_TRI] = nk++;
1243066ea43fSLisandro Dalcin     keymap[GMSH_QUA] = nk++;
1244066ea43fSLisandro Dalcin     keymap[GMSH_SEG] = nk++;
1245066ea43fSLisandro Dalcin     keymap[GMSH_VTX] = nk++;
12460598e1a2SLisandro Dalcin 
12479566063dSJacob Faibussowitsch     PetscCall(GmshElementsCreate(mesh->numElems, &mesh->elements));
12484ad8454bSPierre Jolivet #define key(eid) keymap[GmshCellMap[elements[eid].cellType].polytope]
12490598e1a2SLisandro Dalcin     for (e = 0; e < ne; ++e) offset[1 + key(e)]++;
12500598e1a2SLisandro Dalcin     for (k = 1; k < nk; ++k) offset[k] += offset[k - 1];
12510598e1a2SLisandro Dalcin     for (e = 0; e < ne; ++e) mesh->elements[offset[key(e)]++] = elements[e];
12520598e1a2SLisandro Dalcin #undef key
12539566063dSJacob Faibussowitsch     PetscCall(GmshElementsDestroy(&elements));
1254066ea43fSLisandro Dalcin   }
12550598e1a2SLisandro Dalcin 
1256066ea43fSLisandro Dalcin   { /* Mesh dimension and order */
1257066ea43fSLisandro Dalcin     GmshElement *elem = mesh->numElems ? mesh->elements : NULL;
1258066ea43fSLisandro Dalcin     mesh->dim         = elem ? GmshCellMap[elem->cellType].dim : 0;
1259066ea43fSLisandro Dalcin     mesh->order       = elem ? GmshCellMap[elem->cellType].order : 0;
12600598e1a2SLisandro Dalcin   }
12610598e1a2SLisandro Dalcin 
12620598e1a2SLisandro Dalcin   {
12630598e1a2SLisandro Dalcin     PetscBT  vtx;
12640598e1a2SLisandro Dalcin     PetscInt dim = mesh->dim, e, n, v;
12650598e1a2SLisandro Dalcin 
12669566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(mesh->numNodes, &vtx));
12670598e1a2SLisandro Dalcin 
12680598e1a2SLisandro Dalcin     /* Compute number of cells and set of vertices */
12690598e1a2SLisandro Dalcin     mesh->numCells = 0;
12700598e1a2SLisandro Dalcin     for (e = 0; e < mesh->numElems; ++e) {
12710598e1a2SLisandro Dalcin       GmshElement *elem = mesh->elements + e;
12720598e1a2SLisandro Dalcin       if (elem->dim == dim && dim > 0) mesh->numCells++;
127348a46eb9SPierre Jolivet       for (v = 0; v < elem->numVerts; v++) PetscCall(PetscBTSet(vtx, elem->nodes[v]));
12740598e1a2SLisandro Dalcin     }
12750598e1a2SLisandro Dalcin 
12760598e1a2SLisandro Dalcin     /* Compute numbering for vertices */
12770598e1a2SLisandro Dalcin     mesh->numVerts = 0;
12789566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(mesh->numNodes, &mesh->vertexMap));
12799371c9d4SSatish Balay     for (n = 0; n < mesh->numNodes; ++n) mesh->vertexMap[n] = PetscBTLookup(vtx, n) ? mesh->numVerts++ : PETSC_MIN_INT;
12800598e1a2SLisandro Dalcin 
12819566063dSJacob Faibussowitsch     PetscCall(PetscBTDestroy(&vtx));
12820598e1a2SLisandro Dalcin   }
12833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12840598e1a2SLisandro Dalcin }
12850598e1a2SLisandro Dalcin 
1286d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadPeriodic(GmshFile *gmsh, GmshMesh *mesh)
1287d71ae5a4SJacob Faibussowitsch {
12880598e1a2SLisandro Dalcin   PetscInt n;
12890598e1a2SLisandro Dalcin 
12900598e1a2SLisandro Dalcin   PetscFunctionBegin;
12919566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(mesh->numNodes, &mesh->periodMap));
12920598e1a2SLisandro Dalcin   for (n = 0; n < mesh->numNodes; ++n) mesh->periodMap[n] = n;
12930598e1a2SLisandro Dalcin   switch (gmsh->fileFormat) {
1294d71ae5a4SJacob Faibussowitsch   case 41:
1295d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadPeriodic_v41(gmsh, mesh->periodMap));
1296d71ae5a4SJacob Faibussowitsch     break;
1297d71ae5a4SJacob Faibussowitsch   default:
1298d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadPeriodic_v40(gmsh, mesh->periodMap));
1299d71ae5a4SJacob Faibussowitsch     break;
13000598e1a2SLisandro Dalcin   }
13010598e1a2SLisandro Dalcin 
13029dddd249SSatish Balay   /* Find canonical primary nodes */
13030598e1a2SLisandro Dalcin   for (n = 0; n < mesh->numNodes; ++n)
13049371c9d4SSatish Balay     while (mesh->periodMap[n] != mesh->periodMap[mesh->periodMap[n]]) mesh->periodMap[n] = mesh->periodMap[mesh->periodMap[n]];
13050598e1a2SLisandro Dalcin 
13069dddd249SSatish Balay   /* Renumber vertices (filter out correspondings) */
13070598e1a2SLisandro Dalcin   mesh->numVerts = 0;
13080598e1a2SLisandro Dalcin   for (n = 0; n < mesh->numNodes; ++n)
13090598e1a2SLisandro Dalcin     if (mesh->vertexMap[n] >= 0)   /* is vertex */
13109dddd249SSatish Balay       if (mesh->periodMap[n] == n) /* is primary */
13110598e1a2SLisandro Dalcin         mesh->vertexMap[n] = mesh->numVerts++;
13120598e1a2SLisandro Dalcin   for (n = 0; n < mesh->numNodes; ++n)
13130598e1a2SLisandro Dalcin     if (mesh->vertexMap[n] >= 0)   /* is vertex */
13149dddd249SSatish Balay       if (mesh->periodMap[n] != n) /* is corresponding  */
13150598e1a2SLisandro Dalcin         mesh->vertexMap[n] = mesh->vertexMap[mesh->periodMap[n]];
13163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13170598e1a2SLisandro Dalcin }
13180598e1a2SLisandro Dalcin 
1319066ea43fSLisandro Dalcin #define DM_POLYTOPE_VERTEX DM_POLYTOPE_POINT
1320066ea43fSLisandro Dalcin static const DMPolytopeType DMPolytopeMap[] = {
1321066ea43fSLisandro Dalcin   /* GMSH_VTX */ DM_POLYTOPE_VERTEX,
1322066ea43fSLisandro Dalcin   /* GMSH_SEG */ DM_POLYTOPE_SEGMENT,
1323066ea43fSLisandro Dalcin   /* GMSH_TRI */ DM_POLYTOPE_TRIANGLE,
1324066ea43fSLisandro Dalcin   /* GMSH_QUA */ DM_POLYTOPE_QUADRILATERAL,
1325066ea43fSLisandro Dalcin   /* GMSH_TET */ DM_POLYTOPE_TETRAHEDRON,
1326066ea43fSLisandro Dalcin   /* GMSH_HEX */ DM_POLYTOPE_HEXAHEDRON,
1327066ea43fSLisandro Dalcin   /* GMSH_PRI */ DM_POLYTOPE_TRI_PRISM,
13289371c9d4SSatish Balay   /* GMSH_PYR */ DM_POLYTOPE_PYRAMID,       DM_POLYTOPE_UNKNOWN};
13290598e1a2SLisandro Dalcin 
1330d71ae5a4SJacob Faibussowitsch static inline DMPolytopeType DMPolytopeTypeFromGmsh(PetscInt cellType)
1331d71ae5a4SJacob Faibussowitsch {
1332066ea43fSLisandro Dalcin   return DMPolytopeMap[GmshCellMap[cellType].polytope];
1333066ea43fSLisandro Dalcin }
1334066ea43fSLisandro Dalcin 
1335d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshCreateFE(MPI_Comm comm, const char prefix[], PetscBool isSimplex, PetscBool continuity, PetscDTNodeType nodeType, PetscInt dim, PetscInt Nc, PetscInt k, PetscFE *fem)
1336d71ae5a4SJacob Faibussowitsch {
1337066ea43fSLisandro Dalcin   DM              K;
1338066ea43fSLisandro Dalcin   PetscSpace      P;
1339066ea43fSLisandro Dalcin   PetscDualSpace  Q;
1340066ea43fSLisandro Dalcin   PetscQuadrature q, fq;
1341066ea43fSLisandro Dalcin   PetscBool       isTensor = isSimplex ? PETSC_FALSE : PETSC_TRUE;
1342066ea43fSLisandro Dalcin   PetscBool       endpoint = PETSC_TRUE;
1343066ea43fSLisandro Dalcin   char            name[32];
1344066ea43fSLisandro Dalcin 
1345066ea43fSLisandro Dalcin   PetscFunctionBegin;
1346066ea43fSLisandro Dalcin   /* Create space */
13479566063dSJacob Faibussowitsch   PetscCall(PetscSpaceCreate(comm, &P));
13489566063dSJacob Faibussowitsch   PetscCall(PetscSpaceSetType(P, PETSCSPACEPOLYNOMIAL));
13499566063dSJacob Faibussowitsch   PetscCall(PetscSpacePolynomialSetTensor(P, isTensor));
13509566063dSJacob Faibussowitsch   PetscCall(PetscSpaceSetNumComponents(P, Nc));
13519566063dSJacob Faibussowitsch   PetscCall(PetscSpaceSetNumVariables(P, dim));
13529566063dSJacob Faibussowitsch   PetscCall(PetscSpaceSetDegree(P, k, PETSC_DETERMINE));
1353066ea43fSLisandro Dalcin   if (prefix) {
13549566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)P, prefix));
13559566063dSJacob Faibussowitsch     PetscCall(PetscSpaceSetFromOptions(P));
13569566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)P, NULL));
13579566063dSJacob Faibussowitsch     PetscCall(PetscSpaceGetDegree(P, &k, NULL));
1358066ea43fSLisandro Dalcin   }
13599566063dSJacob Faibussowitsch   PetscCall(PetscSpaceSetUp(P));
1360066ea43fSLisandro Dalcin   /* Create dual space */
13619566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceCreate(comm, &Q));
13629566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetType(Q, PETSCDUALSPACELAGRANGE));
13639566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceLagrangeSetTensor(Q, isTensor));
13649566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceLagrangeSetContinuity(Q, continuity));
13659566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceLagrangeSetNodeType(Q, nodeType, endpoint, 0));
13669566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetNumComponents(Q, Nc));
13679566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetOrder(Q, k));
13689566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceCell(PETSC_COMM_SELF, DMPolytopeTypeSimpleShape(dim, isSimplex), &K));
13699566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetDM(Q, K));
13709566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&K));
1371066ea43fSLisandro Dalcin   if (prefix) {
13729566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)Q, prefix));
13739566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceSetFromOptions(Q));
13749566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)Q, NULL));
1375066ea43fSLisandro Dalcin   }
13769566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetUp(Q));
1377066ea43fSLisandro Dalcin   /* Create quadrature */
1378066ea43fSLisandro Dalcin   if (isSimplex) {
13799566063dSJacob Faibussowitsch     PetscCall(PetscDTStroudConicalQuadrature(dim, 1, k + 1, -1, +1, &q));
13809566063dSJacob Faibussowitsch     PetscCall(PetscDTStroudConicalQuadrature(dim - 1, 1, k + 1, -1, +1, &fq));
1381066ea43fSLisandro Dalcin   } else {
13829566063dSJacob Faibussowitsch     PetscCall(PetscDTGaussTensorQuadrature(dim, 1, k + 1, -1, +1, &q));
13839566063dSJacob Faibussowitsch     PetscCall(PetscDTGaussTensorQuadrature(dim - 1, 1, k + 1, -1, +1, &fq));
1384066ea43fSLisandro Dalcin   }
1385066ea43fSLisandro Dalcin   /* Create finite element */
13869566063dSJacob Faibussowitsch   PetscCall(PetscFECreate(comm, fem));
13879566063dSJacob Faibussowitsch   PetscCall(PetscFESetType(*fem, PETSCFEBASIC));
13889566063dSJacob Faibussowitsch   PetscCall(PetscFESetNumComponents(*fem, Nc));
13899566063dSJacob Faibussowitsch   PetscCall(PetscFESetBasisSpace(*fem, P));
13909566063dSJacob Faibussowitsch   PetscCall(PetscFESetDualSpace(*fem, Q));
13919566063dSJacob Faibussowitsch   PetscCall(PetscFESetQuadrature(*fem, q));
13929566063dSJacob Faibussowitsch   PetscCall(PetscFESetFaceQuadrature(*fem, fq));
1393066ea43fSLisandro Dalcin   if (prefix) {
13949566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*fem, prefix));
13959566063dSJacob Faibussowitsch     PetscCall(PetscFESetFromOptions(*fem));
13969566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*fem, NULL));
1397066ea43fSLisandro Dalcin   }
13989566063dSJacob Faibussowitsch   PetscCall(PetscFESetUp(*fem));
1399066ea43fSLisandro Dalcin   /* Cleanup */
14009566063dSJacob Faibussowitsch   PetscCall(PetscSpaceDestroy(&P));
14019566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceDestroy(&Q));
14029566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureDestroy(&q));
14039566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureDestroy(&fq));
1404066ea43fSLisandro Dalcin   /* Set finite element name */
140563a3b9bcSJacob Faibussowitsch   PetscCall(PetscSNPrintf(name, sizeof(name), "%s%" PetscInt_FMT, isSimplex ? "P" : "Q", k));
14069566063dSJacob Faibussowitsch   PetscCall(PetscFESetName(*fem, name));
14073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
140896ca5757SLisandro Dalcin }
140996ca5757SLisandro Dalcin 
1410d6689ca9SLisandro Dalcin /*@C
1411a1cb98faSBarry Smith   DMPlexCreateGmshFromFile - Create a `DMPLEX` mesh from a Gmsh file
1412d6689ca9SLisandro Dalcin 
1413a4e35b19SJacob Faibussowitsch   Input Parameters:
1414d6689ca9SLisandro Dalcin + comm        - The MPI communicator
1415d6689ca9SLisandro Dalcin . filename    - Name of the Gmsh file
1416d6689ca9SLisandro Dalcin - interpolate - Create faces and edges in the mesh
1417d6689ca9SLisandro Dalcin 
1418d6689ca9SLisandro Dalcin   Output Parameter:
1419a1cb98faSBarry Smith . dm - The `DM` object representing the mesh
1420d6689ca9SLisandro Dalcin 
1421d6689ca9SLisandro Dalcin   Level: beginner
1422d6689ca9SLisandro Dalcin 
14231cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromFile()`, `DMPlexCreateGmsh()`, `DMPlexCreate()`
1424d6689ca9SLisandro Dalcin @*/
1425d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateGmshFromFile(MPI_Comm comm, const char filename[], PetscBool interpolate, DM *dm)
1426d71ae5a4SJacob Faibussowitsch {
1427d6689ca9SLisandro Dalcin   PetscViewer     viewer;
1428d6689ca9SLisandro Dalcin   PetscMPIInt     rank;
1429d6689ca9SLisandro Dalcin   int             fileType;
1430d6689ca9SLisandro Dalcin   PetscViewerType vtype;
1431d6689ca9SLisandro Dalcin 
1432d6689ca9SLisandro Dalcin   PetscFunctionBegin;
14339566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1434d6689ca9SLisandro Dalcin 
1435d6689ca9SLisandro Dalcin   /* Determine Gmsh file type (ASCII or binary) from file header */
1436dd400576SPatrick Sanan   if (rank == 0) {
14370598e1a2SLisandro Dalcin     GmshFile gmsh[1];
1438d6689ca9SLisandro Dalcin     char     line[PETSC_MAX_PATH_LEN];
1439d6689ca9SLisandro Dalcin     int      snum;
1440d6689ca9SLisandro Dalcin     float    version;
1441a8d4e440SJunchao Zhang     int      fileFormat;
1442d6689ca9SLisandro Dalcin 
14439566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(gmsh, 1));
14449566063dSJacob Faibussowitsch     PetscCall(PetscViewerCreate(PETSC_COMM_SELF, &gmsh->viewer));
14459566063dSJacob Faibussowitsch     PetscCall(PetscViewerSetType(gmsh->viewer, PETSCVIEWERASCII));
14469566063dSJacob Faibussowitsch     PetscCall(PetscViewerFileSetMode(gmsh->viewer, FILE_MODE_READ));
14479566063dSJacob Faibussowitsch     PetscCall(PetscViewerFileSetName(gmsh->viewer, filename));
1448d6689ca9SLisandro Dalcin     /* Read only the first two lines of the Gmsh file */
14499566063dSJacob Faibussowitsch     PetscCall(GmshReadSection(gmsh, line));
14509566063dSJacob Faibussowitsch     PetscCall(GmshExpect(gmsh, "$MeshFormat", line));
14519566063dSJacob Faibussowitsch     PetscCall(GmshReadString(gmsh, line, 2));
1452d6689ca9SLisandro Dalcin     snum       = sscanf(line, "%f %d", &version, &fileType);
1453a8d4e440SJunchao Zhang     fileFormat = (int)roundf(version * 10);
145408401ef6SPierre Jolivet     PetscCheck(snum == 2, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to parse Gmsh file header: %s", line);
1455a8d4e440SJunchao Zhang     PetscCheck(fileFormat >= 22, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at least 2.2", (double)version);
14561dca8a05SBarry Smith     PetscCheck((int)version != 3, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f not supported", (double)version);
1457a8d4e440SJunchao Zhang     PetscCheck(fileFormat <= 41, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at most 4.1", (double)version);
14589566063dSJacob Faibussowitsch     PetscCall(PetscViewerDestroy(&gmsh->viewer));
1459d6689ca9SLisandro Dalcin   }
14609566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Bcast(&fileType, 1, MPI_INT, 0, comm));
1461d6689ca9SLisandro Dalcin   vtype = (fileType == 0) ? PETSCVIEWERASCII : PETSCVIEWERBINARY;
1462d6689ca9SLisandro Dalcin 
1463d6689ca9SLisandro Dalcin   /* Create appropriate viewer and build plex */
14649566063dSJacob Faibussowitsch   PetscCall(PetscViewerCreate(comm, &viewer));
14659566063dSJacob Faibussowitsch   PetscCall(PetscViewerSetType(viewer, vtype));
14669566063dSJacob Faibussowitsch   PetscCall(PetscViewerFileSetMode(viewer, FILE_MODE_READ));
14679566063dSJacob Faibussowitsch   PetscCall(PetscViewerFileSetName(viewer, filename));
14689566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateGmsh(comm, viewer, interpolate, dm));
14699566063dSJacob Faibussowitsch   PetscCall(PetscViewerDestroy(&viewer));
14703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1471d6689ca9SLisandro Dalcin }
1472d6689ca9SLisandro Dalcin 
1473331830f3SMatthew G. Knepley /*@
1474a1cb98faSBarry Smith   DMPlexCreateGmsh - Create a `DMPLEX` mesh from a Gmsh file viewer
1475331830f3SMatthew G. Knepley 
1476d083f849SBarry Smith   Collective
1477331830f3SMatthew G. Knepley 
1478331830f3SMatthew G. Knepley   Input Parameters:
1479331830f3SMatthew G. Knepley + comm        - The MPI communicator
1480a1cb98faSBarry Smith . viewer      - The `PetscViewer` associated with a Gmsh file
1481331830f3SMatthew G. Knepley - interpolate - Create faces and edges in the mesh
1482331830f3SMatthew G. Knepley 
1483331830f3SMatthew G. Knepley   Output Parameter:
1484a1cb98faSBarry Smith . dm - The `DM` object representing the mesh
1485331830f3SMatthew G. Knepley 
1486a1cb98faSBarry Smith   Options Database Keys:
1487df93260fSMatthew G. Knepley + -dm_plex_gmsh_hybrid        - Force triangular prisms to use tensor order
1488df93260fSMatthew G. Knepley . -dm_plex_gmsh_periodic      - Read Gmsh periodic section and construct a periodic Plex
1489df93260fSMatthew G. Knepley . -dm_plex_gmsh_highorder     - Generate high-order coordinates
1490df93260fSMatthew 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
14912b205333SMatthew G. Knepley . -dm_plex_gmsh_use_generic   - Generate generic labels, i.e. Cell Sets, Face Sets, etc.
1492df93260fSMatthew G. Knepley . -dm_plex_gmsh_use_regions   - Generate labels with region names
1493df93260fSMatthew G. Knepley . -dm_plex_gmsh_mark_vertices - Add vertices to generated labels
1494df93260fSMatthew G. Knepley . -dm_plex_gmsh_multiple_tags - Allow multiple tags for default labels
1495df93260fSMatthew G. Knepley - -dm_plex_gmsh_spacedim <d>  - Embedding space dimension, if different from topological dimension
1496df93260fSMatthew G. Knepley 
14971d27aa22SBarry Smith   Level: beginner
14981d27aa22SBarry Smith 
14991d27aa22SBarry Smith   Notes:
15001d27aa22SBarry Smith   The Gmsh file format is described in <http://gmsh.info/doc/texinfo/gmsh.html#MSH-file-format>
1501df93260fSMatthew G. Knepley 
15022b205333SMatthew 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. Alternatively, -dm_plex_gmsh_use_regions creates labels based on the region names from the PhysicalNames section, and all tags are used, but you can retain the generic labels using -dm_plex_gmsh_use_generic.
1503331830f3SMatthew G. Knepley 
15041cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`
1505331830f3SMatthew G. Knepley @*/
1506d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateGmsh(MPI_Comm comm, PetscViewer viewer, PetscBool interpolate, DM *dm)
1507d71ae5a4SJacob Faibussowitsch {
15080598e1a2SLisandro Dalcin   GmshMesh    *mesh          = NULL;
150911c56cb0SLisandro Dalcin   PetscViewer  parentviewer  = NULL;
15100598e1a2SLisandro Dalcin   PetscBT      periodicVerts = NULL;
1511eae3dc7dSJacob Faibussowitsch   PetscBT     *periodicCells = NULL;
15126858538eSMatthew G. Knepley   DM           cdm, cdmCell = NULL;
15136858538eSMatthew G. Knepley   PetscSection cs, csCell   = NULL;
15146858538eSMatthew G. Knepley   Vec          coordinates, coordinatesCell;
15150444adf6SMatthew G. Knepley   DMLabel      cellSets = NULL, faceSets = NULL, edgeSets = NULL, vertSets = NULL, marker = NULL, *regionSets;
15169db5b827SMatthew G. Knepley   PetscInt     dim = 0, coordDim = -1, order = 0, maxHeight = 0;
15179db5b827SMatthew G. Knepley   PetscInt     numNodes = 0, numElems = 0, numVerts = 0, numCells = 0, vStart, vEnd;
1518066ea43fSLisandro Dalcin   PetscInt     cell, cone[8], e, n, v, d;
15192b205333SMatthew G. Knepley   PetscBool    usegeneric = PETSC_TRUE, useregions = PETSC_FALSE, markvertices = PETSC_FALSE, multipleTags = PETSC_FALSE;
15202b205333SMatthew G. Knepley   PetscBool    flg, binary, hybrid = interpolate, periodic = PETSC_TRUE;
1521066ea43fSLisandro Dalcin   PetscBool    highOrder = PETSC_TRUE, highOrderSet, project = PETSC_FALSE;
1522066ea43fSLisandro Dalcin   PetscBool    isSimplex = PETSC_FALSE, isHybrid = PETSC_FALSE, hasTetra = PETSC_FALSE;
15230598e1a2SLisandro Dalcin   PetscMPIInt  rank;
1524331830f3SMatthew G. Knepley 
1525331830f3SMatthew G. Knepley   PetscFunctionBegin;
15269566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1527d0609cedSBarry Smith   PetscObjectOptionsBegin((PetscObject)viewer);
1528d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "DMPlex Gmsh options");
1529df93260fSMatthew G. Knepley   PetscCall(PetscOptionsBool("-dm_plex_gmsh_hybrid", "Force triangular prisms to use tensor order", "DMPlexCreateGmsh", hybrid, &hybrid, NULL));
15309566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_plex_gmsh_periodic", "Read Gmsh periodic section", "DMPlexCreateGmsh", periodic, &periodic, NULL));
15319566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_plex_gmsh_highorder", "Generate high-order coordinates", "DMPlexCreateGmsh", highOrder, &highOrder, &highOrderSet));
15329566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_plex_gmsh_project", "Project high-order coordinates to a different space", "DMPlexCreateGmsh", project, &project, NULL));
15339566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_plex_gmsh_use_regions", "Generate labels with region names", "DMPlexCreateGmsh", useregions, &useregions, NULL));
15342b205333SMatthew G. Knepley   PetscCall(PetscOptionsBool("-dm_plex_gmsh_use_generic", "Generate generic labels, i.e. Cell Sets, Face Sets, etc", "DMPlexCreateGmsh", usegeneric, &usegeneric, &flg));
15352b205333SMatthew G. Knepley   if (!flg && useregions) usegeneric = PETSC_FALSE;
15369566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_plex_gmsh_mark_vertices", "Add vertices to generated labels", "DMPlexCreateGmsh", markvertices, &markvertices, NULL));
1537df93260fSMatthew G. Knepley   PetscCall(PetscOptionsBool("-dm_plex_gmsh_multiple_tags", "Allow multiple tags for default labels", "DMPlexCreateGmsh", multipleTags, &multipleTags, NULL));
15389566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBoundedInt("-dm_plex_gmsh_spacedim", "Embedding space dimension", "DMPlexCreateGmsh", coordDim, &coordDim, NULL, PETSC_DECIDE));
15399db5b827SMatthew G. Knepley   PetscCall(PetscOptionsBoundedInt("-dm_localize_height", "Localize edges and faces in addition to cells", "", maxHeight, &maxHeight, NULL, 0));
1540d0609cedSBarry Smith   PetscOptionsHeadEnd();
1541d0609cedSBarry Smith   PetscOptionsEnd();
15420598e1a2SLisandro Dalcin 
15439566063dSJacob Faibussowitsch   PetscCall(GmshCellInfoSetUp());
154411c56cb0SLisandro Dalcin 
15459566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm, dm));
15469566063dSJacob Faibussowitsch   PetscCall(DMSetType(*dm, DMPLEX));
15479566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_CreateGmsh, *dm, NULL, NULL, NULL));
154811c56cb0SLisandro Dalcin 
15499566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &binary));
155011c56cb0SLisandro Dalcin 
155111c56cb0SLisandro Dalcin   /* Binary viewers read on all ranks, get subviewer to read only in rank 0 */
15523b46f529SLisandro Dalcin   if (binary) {
155311c56cb0SLisandro Dalcin     parentviewer = viewer;
15549566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetSubViewer(parentviewer, PETSC_COMM_SELF, &viewer));
155511c56cb0SLisandro Dalcin   }
155611c56cb0SLisandro Dalcin 
1557dd400576SPatrick Sanan   if (rank == 0) {
15580598e1a2SLisandro Dalcin     GmshFile  gmsh[1];
1559698a79b9SLisandro Dalcin     char      line[PETSC_MAX_PATH_LEN];
1560698a79b9SLisandro Dalcin     PetscBool match;
1561331830f3SMatthew G. Knepley 
15629566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(gmsh, 1));
1563698a79b9SLisandro Dalcin     gmsh->viewer = viewer;
1564698a79b9SLisandro Dalcin     gmsh->binary = binary;
1565698a79b9SLisandro Dalcin 
15669566063dSJacob Faibussowitsch     PetscCall(GmshMeshCreate(&mesh));
15670598e1a2SLisandro Dalcin 
1568698a79b9SLisandro Dalcin     /* Read mesh format */
15699566063dSJacob Faibussowitsch     PetscCall(GmshReadSection(gmsh, line));
15709566063dSJacob Faibussowitsch     PetscCall(GmshExpect(gmsh, "$MeshFormat", line));
15719566063dSJacob Faibussowitsch     PetscCall(GmshReadMeshFormat(gmsh));
15729566063dSJacob Faibussowitsch     PetscCall(GmshReadEndSection(gmsh, "$EndMeshFormat", line));
157311c56cb0SLisandro Dalcin 
15748749820aSMatthew G. Knepley     /* OPTIONAL Read mesh version (Neper only) */
15759566063dSJacob Faibussowitsch     PetscCall(GmshReadSection(gmsh, line));
15768749820aSMatthew G. Knepley     PetscCall(GmshMatch(gmsh, "$MeshVersion", line, &match));
15778749820aSMatthew G. Knepley     if (match) {
15788749820aSMatthew G. Knepley       PetscCall(GmshExpect(gmsh, "$MeshVersion", line));
15798749820aSMatthew G. Knepley       PetscCall(GmshReadMeshVersion(gmsh));
15808749820aSMatthew G. Knepley       PetscCall(GmshReadEndSection(gmsh, "$EndMeshVersion", line));
15818749820aSMatthew G. Knepley       /* Initial read for entity section */
15828749820aSMatthew G. Knepley       PetscCall(GmshReadSection(gmsh, line));
15838749820aSMatthew G. Knepley     }
15848749820aSMatthew G. Knepley 
15858749820aSMatthew G. Knepley     /* OPTIONAL Read mesh domain (Neper only) */
15868749820aSMatthew G. Knepley     PetscCall(GmshMatch(gmsh, "$Domain", line, &match));
15878749820aSMatthew G. Knepley     if (match) {
15888749820aSMatthew G. Knepley       PetscCall(GmshExpect(gmsh, "$Domain", line));
15898749820aSMatthew G. Knepley       PetscCall(GmshReadMeshDomain(gmsh));
15908749820aSMatthew G. Knepley       PetscCall(GmshReadEndSection(gmsh, "$EndDomain", line));
15918749820aSMatthew G. Knepley       /* Initial read for entity section */
15928749820aSMatthew G. Knepley       PetscCall(GmshReadSection(gmsh, line));
15938749820aSMatthew G. Knepley     }
15948749820aSMatthew G. Knepley 
15958749820aSMatthew G. Knepley     /* OPTIONAL Read physical names */
15969566063dSJacob Faibussowitsch     PetscCall(GmshMatch(gmsh, "$PhysicalNames", line, &match));
1597dc0ede3bSMatthew G. Knepley     if (match) {
15989566063dSJacob Faibussowitsch       PetscCall(GmshExpect(gmsh, "$PhysicalNames", line));
15999566063dSJacob Faibussowitsch       PetscCall(GmshReadPhysicalNames(gmsh, mesh));
16009566063dSJacob Faibussowitsch       PetscCall(GmshReadEndSection(gmsh, "$EndPhysicalNames", line));
1601698a79b9SLisandro Dalcin       /* Initial read for entity section */
16029566063dSJacob Faibussowitsch       PetscCall(GmshReadSection(gmsh, line));
1603dc0ede3bSMatthew G. Knepley     }
160411c56cb0SLisandro Dalcin 
1605de78e4feSLisandro Dalcin     /* Read entities */
1606698a79b9SLisandro Dalcin     if (gmsh->fileFormat >= 40) {
16079566063dSJacob Faibussowitsch       PetscCall(GmshExpect(gmsh, "$Entities", line));
16089566063dSJacob Faibussowitsch       PetscCall(GmshReadEntities(gmsh, mesh));
16099566063dSJacob Faibussowitsch       PetscCall(GmshReadEndSection(gmsh, "$EndEntities", line));
1610698a79b9SLisandro Dalcin       /* Initial read for nodes section */
16119566063dSJacob Faibussowitsch       PetscCall(GmshReadSection(gmsh, line));
1612de78e4feSLisandro Dalcin     }
1613de78e4feSLisandro Dalcin 
1614698a79b9SLisandro Dalcin     /* Read nodes */
16159566063dSJacob Faibussowitsch     PetscCall(GmshExpect(gmsh, "$Nodes", line));
16169566063dSJacob Faibussowitsch     PetscCall(GmshReadNodes(gmsh, mesh));
16179566063dSJacob Faibussowitsch     PetscCall(GmshReadEndSection(gmsh, "$EndNodes", line));
161811c56cb0SLisandro Dalcin 
1619698a79b9SLisandro Dalcin     /* Read elements */
16209566063dSJacob Faibussowitsch     PetscCall(GmshReadSection(gmsh, line));
16219566063dSJacob Faibussowitsch     PetscCall(GmshExpect(gmsh, "$Elements", line));
16229566063dSJacob Faibussowitsch     PetscCall(GmshReadElements(gmsh, mesh));
16239566063dSJacob Faibussowitsch     PetscCall(GmshReadEndSection(gmsh, "$EndElements", line));
1624de78e4feSLisandro Dalcin 
16250598e1a2SLisandro Dalcin     /* Read periodic section (OPTIONAL) */
1626698a79b9SLisandro Dalcin     if (periodic) {
16279566063dSJacob Faibussowitsch       PetscCall(GmshReadSection(gmsh, line));
16289566063dSJacob Faibussowitsch       PetscCall(GmshMatch(gmsh, "$Periodic", line, &periodic));
1629ef12879bSLisandro Dalcin     }
1630ef12879bSLisandro Dalcin     if (periodic) {
16319566063dSJacob Faibussowitsch       PetscCall(GmshExpect(gmsh, "$Periodic", line));
16329566063dSJacob Faibussowitsch       PetscCall(GmshReadPeriodic(gmsh, mesh));
16339566063dSJacob Faibussowitsch       PetscCall(GmshReadEndSection(gmsh, "$EndPeriodic", line));
1634698a79b9SLisandro Dalcin     }
1635698a79b9SLisandro Dalcin 
16369566063dSJacob Faibussowitsch     PetscCall(PetscFree(gmsh->wbuf));
16379566063dSJacob Faibussowitsch     PetscCall(PetscFree(gmsh->sbuf));
16389566063dSJacob Faibussowitsch     PetscCall(PetscFree(gmsh->nbuf));
16390598e1a2SLisandro Dalcin 
16400598e1a2SLisandro Dalcin     dim      = mesh->dim;
1641066ea43fSLisandro Dalcin     order    = mesh->order;
16420598e1a2SLisandro Dalcin     numNodes = mesh->numNodes;
16430598e1a2SLisandro Dalcin     numElems = mesh->numElems;
16440598e1a2SLisandro Dalcin     numVerts = mesh->numVerts;
16450598e1a2SLisandro Dalcin     numCells = mesh->numCells;
1646066ea43fSLisandro Dalcin 
1647066ea43fSLisandro Dalcin     {
1648066ea43fSLisandro Dalcin       GmshElement *elemA = mesh->numCells > 0 ? mesh->elements : NULL;
16498e3a54c0SPierre Jolivet       GmshElement *elemB = PetscSafePointerPlusOffset(elemA, mesh->numCells - 1);
1650066ea43fSLisandro Dalcin       int          ptA   = elemA ? GmshCellMap[elemA->cellType].polytope : -1;
1651066ea43fSLisandro Dalcin       int          ptB   = elemB ? GmshCellMap[elemB->cellType].polytope : -1;
1652066ea43fSLisandro Dalcin       isSimplex          = (ptA == GMSH_QUA || ptA == GMSH_HEX) ? PETSC_FALSE : PETSC_TRUE;
1653066ea43fSLisandro Dalcin       isHybrid           = (ptA == ptB) ? PETSC_FALSE : PETSC_TRUE;
1654066ea43fSLisandro Dalcin       hasTetra           = (ptA == GMSH_TET) ? PETSC_TRUE : PETSC_FALSE;
1655066ea43fSLisandro Dalcin     }
1656698a79b9SLisandro Dalcin   }
1657698a79b9SLisandro Dalcin 
165848a46eb9SPierre Jolivet   if (parentviewer) PetscCall(PetscViewerRestoreSubViewer(parentviewer, PETSC_COMM_SELF, &viewer));
1659698a79b9SLisandro Dalcin 
1660066ea43fSLisandro Dalcin   {
1661066ea43fSLisandro Dalcin     int buf[6];
1662698a79b9SLisandro Dalcin 
1663066ea43fSLisandro Dalcin     buf[0] = (int)dim;
1664066ea43fSLisandro Dalcin     buf[1] = (int)order;
1665066ea43fSLisandro Dalcin     buf[2] = periodic;
1666066ea43fSLisandro Dalcin     buf[3] = isSimplex;
1667066ea43fSLisandro Dalcin     buf[4] = isHybrid;
1668066ea43fSLisandro Dalcin     buf[5] = hasTetra;
1669066ea43fSLisandro Dalcin 
16709566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Bcast(buf, 6, MPI_INT, 0, comm));
1671066ea43fSLisandro Dalcin 
1672066ea43fSLisandro Dalcin     dim       = buf[0];
1673066ea43fSLisandro Dalcin     order     = buf[1];
1674066ea43fSLisandro Dalcin     periodic  = buf[2] ? PETSC_TRUE : PETSC_FALSE;
1675066ea43fSLisandro Dalcin     isSimplex = buf[3] ? PETSC_TRUE : PETSC_FALSE;
1676066ea43fSLisandro Dalcin     isHybrid  = buf[4] ? PETSC_TRUE : PETSC_FALSE;
1677066ea43fSLisandro Dalcin     hasTetra  = buf[5] ? PETSC_TRUE : PETSC_FALSE;
1678dea2a3c7SStefano Zampini   }
1679dea2a3c7SStefano Zampini 
1680066ea43fSLisandro Dalcin   if (!highOrderSet) highOrder = (order > 1) ? PETSC_TRUE : PETSC_FALSE;
168108401ef6SPierre Jolivet   PetscCheck(!highOrder || !isHybrid, comm, PETSC_ERR_SUP, "No support for discretization on hybrid meshes yet");
1682066ea43fSLisandro Dalcin 
16830598e1a2SLisandro Dalcin   /* We do not want this label automatically computed, instead we fill it here */
16849566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(*dm, "celltype"));
168511c56cb0SLisandro Dalcin 
1686a4bb7517SMichael Lange   /* Allocate the cell-vertex mesh */
16879566063dSJacob Faibussowitsch   PetscCall(DMPlexSetChart(*dm, 0, numCells + numVerts));
16880598e1a2SLisandro Dalcin   for (cell = 0; cell < numCells; ++cell) {
16890598e1a2SLisandro Dalcin     GmshElement   *elem  = mesh->elements + cell;
16900598e1a2SLisandro Dalcin     DMPolytopeType ctype = DMPolytopeTypeFromGmsh(elem->cellType);
16910598e1a2SLisandro Dalcin     if (hybrid && hasTetra && ctype == DM_POLYTOPE_TRI_PRISM) ctype = DM_POLYTOPE_TRI_PRISM_TENSOR;
16929566063dSJacob Faibussowitsch     PetscCall(DMPlexSetConeSize(*dm, cell, elem->numVerts));
16939566063dSJacob Faibussowitsch     PetscCall(DMPlexSetCellType(*dm, cell, ctype));
1694db397164SMichael Lange   }
169548a46eb9SPierre Jolivet   for (v = numCells; v < numCells + numVerts; ++v) PetscCall(DMPlexSetCellType(*dm, v, DM_POLYTOPE_POINT));
16969566063dSJacob Faibussowitsch   PetscCall(DMSetUp(*dm));
169796ca5757SLisandro Dalcin 
1698a4bb7517SMichael Lange   /* Add cell-vertex connections */
16990598e1a2SLisandro Dalcin   for (cell = 0; cell < numCells; ++cell) {
17000598e1a2SLisandro Dalcin     GmshElement *elem = mesh->elements + cell;
17010598e1a2SLisandro Dalcin     for (v = 0; v < elem->numVerts; ++v) {
17020598e1a2SLisandro Dalcin       const PetscInt nn = elem->nodes[v];
17030598e1a2SLisandro Dalcin       const PetscInt vv = mesh->vertexMap[nn];
17040598e1a2SLisandro Dalcin       cone[v]           = numCells + vv;
1705db397164SMichael Lange     }
17069566063dSJacob Faibussowitsch     PetscCall(DMPlexReorderCell(*dm, cell, cone));
17079566063dSJacob Faibussowitsch     PetscCall(DMPlexSetCone(*dm, cell, cone));
1708a4bb7517SMichael Lange   }
170996ca5757SLisandro Dalcin 
17109566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(*dm, dim));
17119566063dSJacob Faibussowitsch   PetscCall(DMPlexSymmetrize(*dm));
17129566063dSJacob Faibussowitsch   PetscCall(DMPlexStratify(*dm));
1713331830f3SMatthew G. Knepley   if (interpolate) {
17145fd9971aSMatthew G. Knepley     DM idm;
1715331830f3SMatthew G. Knepley 
17169566063dSJacob Faibussowitsch     PetscCall(DMPlexInterpolate(*dm, &idm));
17179566063dSJacob Faibussowitsch     PetscCall(DMDestroy(dm));
1718331830f3SMatthew G. Knepley     *dm = idm;
1719331830f3SMatthew G. Knepley   }
17209db5b827SMatthew G. Knepley   PetscCall(DMPlexGetDepthStratum(*dm, 0, &vStart, &vEnd));
1721917266a4SLisandro Dalcin 
1722dd400576SPatrick Sanan   if (rank == 0) {
1723a45dabc8SMatthew G. Knepley     const PetscInt Nr = useregions ? mesh->numRegions : 0;
1724d1a54cefSMatthew G. Knepley 
17259566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(Nr, &regionSets));
17260598e1a2SLisandro Dalcin     for (cell = 0, e = 0; e < numElems; ++e) {
17270598e1a2SLisandro Dalcin       GmshElement *elem = mesh->elements + e;
17286e1dd89aSLawrence Mitchell 
17296e1dd89aSLawrence Mitchell       /* Create cell sets */
17300598e1a2SLisandro Dalcin       if (elem->dim == dim && dim > 0) {
17310598e1a2SLisandro Dalcin         if (elem->numTags > 0) {
1732df93260fSMatthew G. Knepley           PetscInt Nt = elem->numTags, t, r;
1733a45dabc8SMatthew G. Knepley 
1734df93260fSMatthew G. Knepley           for (t = 0; t < Nt; ++t) {
1735df93260fSMatthew G. Knepley             const PetscInt  tag     = elem->tags[t];
17362b205333SMatthew G. Knepley             const PetscBool generic = usegeneric && (!t || multipleTags) ? PETSC_TRUE : PETSC_FALSE;
1737df93260fSMatthew G. Knepley 
1738df93260fSMatthew G. Knepley             if (generic) PetscCall(DMSetLabelValue_Fast(*dm, &cellSets, "Cell Sets", cell, tag));
1739a45dabc8SMatthew G. Knepley             for (r = 0; r < Nr; ++r) {
1740df93260fSMatthew G. Knepley               if (mesh->regionDims[r] != dim) continue;
17419566063dSJacob Faibussowitsch               if (mesh->regionTags[r] == tag) PetscCall(DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], cell, tag));
1742a45dabc8SMatthew G. Knepley             }
17436e1dd89aSLawrence Mitchell           }
1744df93260fSMatthew G. Knepley         }
1745917266a4SLisandro Dalcin         cell++;
17466e1dd89aSLawrence Mitchell       }
17470c070f12SSander Arens 
17480598e1a2SLisandro Dalcin       /* Create face sets */
1749aec57b10SMatthew G. Knepley       if (elem->numTags && interpolate && elem->dim == dim - 1) {
17500598e1a2SLisandro Dalcin         PetscInt        joinSize;
17510598e1a2SLisandro Dalcin         const PetscInt *join = NULL;
17520444adf6SMatthew G. Knepley         PetscInt        Nt   = elem->numTags, pdepth;
1753a45dabc8SMatthew G. Knepley 
17540598e1a2SLisandro Dalcin         /* Find the relevant facet with vertex joins */
17550598e1a2SLisandro Dalcin         for (v = 0; v < elem->numVerts; ++v) {
17560598e1a2SLisandro Dalcin           const PetscInt nn = elem->nodes[v];
17570598e1a2SLisandro Dalcin           const PetscInt vv = mesh->vertexMap[nn];
17580598e1a2SLisandro Dalcin           cone[v]           = vStart + vv;
17590598e1a2SLisandro Dalcin         }
17609566063dSJacob Faibussowitsch         PetscCall(DMPlexGetFullJoin(*dm, elem->numVerts, cone, &joinSize, &join));
176163a3b9bcSJacob 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);
17620444adf6SMatthew G. Knepley         PetscCall(DMPlexGetPointDepth(*dm, join[0], &pdepth));
17630444adf6SMatthew G. Knepley         PetscCheck(pdepth == dim - 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Plex facet %" PetscInt_FMT " for Gmsh element %" PetscInt_FMT " had depth %" PetscInt_FMT " != %" PetscInt_FMT, join[0], elem->id, pdepth, dim - 1);
17640444adf6SMatthew G. Knepley         for (PetscInt t = 0; t < Nt; ++t) {
17655ad74b4fSMatthew G. Knepley           const PetscInt  tag     = elem->tags[t];
17662b205333SMatthew G. Knepley           const PetscBool generic = usegeneric && (!t || multipleTags) ? PETSC_TRUE : PETSC_FALSE;
17675ad74b4fSMatthew G. Knepley 
1768df93260fSMatthew G. Knepley           if (generic) PetscCall(DMSetLabelValue_Fast(*dm, &faceSets, "Face Sets", join[0], tag));
17690444adf6SMatthew G. Knepley           for (PetscInt r = 0; r < Nr; ++r) {
1770df93260fSMatthew G. Knepley             if (mesh->regionDims[r] != dim - 1) continue;
17719566063dSJacob Faibussowitsch             if (mesh->regionTags[r] == tag) PetscCall(DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], join[0], tag));
1772a45dabc8SMatthew G. Knepley           }
17735ad74b4fSMatthew G. Knepley         }
17749566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreJoin(*dm, elem->numVerts, cone, &joinSize, &join));
17750598e1a2SLisandro Dalcin       }
17760598e1a2SLisandro Dalcin 
1777aec57b10SMatthew G. Knepley       /* Create edge sets */
1778aec57b10SMatthew G. Knepley       if (elem->numTags && interpolate && dim > 2 && elem->dim == 1) {
1779aec57b10SMatthew G. Knepley         PetscInt        joinSize;
1780aec57b10SMatthew G. Knepley         const PetscInt *join = NULL;
1781aec57b10SMatthew G. Knepley         PetscInt        Nt   = elem->numTags, t, r;
1782aec57b10SMatthew G. Knepley 
1783aec57b10SMatthew G. Knepley         /* Find the relevant edge with vertex joins */
1784aec57b10SMatthew G. Knepley         for (v = 0; v < elem->numVerts; ++v) {
1785aec57b10SMatthew G. Knepley           const PetscInt nn = elem->nodes[v];
1786aec57b10SMatthew G. Knepley           const PetscInt vv = mesh->vertexMap[nn];
1787aec57b10SMatthew G. Knepley           cone[v]           = vStart + vv;
1788aec57b10SMatthew G. Knepley         }
1789aec57b10SMatthew G. Knepley         PetscCall(DMPlexGetJoin(*dm, elem->numVerts, cone, &joinSize, &join));
1790aec57b10SMatthew G. Knepley         PetscCheck(joinSize == 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Could not determine Plex edge for Gmsh element %" PetscInt_FMT " (Plex cell %" PetscInt_FMT ")", elem->id, e);
1791aec57b10SMatthew G. Knepley         for (t = 0; t < Nt; ++t) {
1792aec57b10SMatthew G. Knepley           const PetscInt  tag     = elem->tags[t];
17932b205333SMatthew G. Knepley           const PetscBool generic = usegeneric && (!t || multipleTags) ? PETSC_TRUE : PETSC_FALSE;
1794aec57b10SMatthew G. Knepley 
17950444adf6SMatthew G. Knepley           if (generic) PetscCall(DMSetLabelValue_Fast(*dm, &edgeSets, "Edge Sets", join[0], tag));
1796aec57b10SMatthew G. Knepley           for (r = 0; r < Nr; ++r) {
1797aec57b10SMatthew G. Knepley             if (mesh->regionDims[r] != 1) continue;
1798aec57b10SMatthew G. Knepley             if (mesh->regionTags[r] == tag) PetscCall(DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], join[0], tag));
1799aec57b10SMatthew G. Knepley           }
1800aec57b10SMatthew G. Knepley         }
1801aec57b10SMatthew G. Knepley         PetscCall(DMPlexRestoreJoin(*dm, elem->numVerts, cone, &joinSize, &join));
1802aec57b10SMatthew G. Knepley       }
1803aec57b10SMatthew G. Knepley 
18040c070f12SSander Arens       /* Create vertex sets */
1805aec57b10SMatthew G. Knepley       if (elem->numTags && elem->dim == 0 && markvertices) {
18060598e1a2SLisandro Dalcin         const PetscInt nn  = elem->nodes[0];
18070598e1a2SLisandro Dalcin         const PetscInt vv  = mesh->vertexMap[nn];
1808a45dabc8SMatthew G. Knepley         const PetscInt tag = elem->tags[0];
1809a45dabc8SMatthew G. Knepley         PetscInt       r;
1810a45dabc8SMatthew G. Knepley 
18118a3d9825SMatthew G. Knepley         if (vv < 0) continue;
18122b205333SMatthew G. Knepley         if (usegeneric) PetscCall(DMSetLabelValue_Fast(*dm, &vertSets, "Vertex Sets", vStart + vv, tag));
181381a1af93SMatthew G. Knepley         for (r = 0; r < Nr; ++r) {
1814df93260fSMatthew G. Knepley           if (mesh->regionDims[r] != 0) continue;
18159566063dSJacob Faibussowitsch           if (mesh->regionTags[r] == tag) PetscCall(DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], vStart + vv, tag));
181681a1af93SMatthew G. Knepley         }
181781a1af93SMatthew G. Knepley       }
181881a1af93SMatthew G. Knepley     }
181981a1af93SMatthew G. Knepley     if (markvertices) {
182081a1af93SMatthew G. Knepley       for (v = 0; v < numNodes; ++v) {
182181a1af93SMatthew G. Knepley         const PetscInt  vv   = mesh->vertexMap[v];
18227d5b9244SMatthew G. Knepley         const PetscInt *tags = &mesh->nodelist->tag[v * GMSH_MAX_TAGS];
18237d5b9244SMatthew G. Knepley         PetscInt        r, t;
182481a1af93SMatthew G. Knepley 
18258a3d9825SMatthew G. Knepley         if (vv < 0) continue;
18267d5b9244SMatthew G. Knepley         for (t = 0; t < GMSH_MAX_TAGS; ++t) {
18277d5b9244SMatthew G. Knepley           const PetscInt  tag     = tags[t];
18282b205333SMatthew G. Knepley           const PetscBool generic = usegeneric && (!t || multipleTags) ? PETSC_TRUE : PETSC_FALSE;
18297d5b9244SMatthew G. Knepley 
18307d5b9244SMatthew G. Knepley           if (tag == -1) continue;
1831df93260fSMatthew G. Knepley           if (generic) PetscCall(DMSetLabelValue_Fast(*dm, &vertSets, "Vertex Sets", vStart + vv, tag));
1832a45dabc8SMatthew G. Knepley           for (r = 0; r < Nr; ++r) {
18339566063dSJacob Faibussowitsch             if (mesh->regionTags[r] == tag) PetscCall(DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], vStart + vv, tag));
18340598e1a2SLisandro Dalcin           }
18350598e1a2SLisandro Dalcin         }
18360598e1a2SLisandro Dalcin       }
18370598e1a2SLisandro Dalcin     }
18389566063dSJacob Faibussowitsch     PetscCall(PetscFree(regionSets));
1839a45dabc8SMatthew G. Knepley   }
18400598e1a2SLisandro Dalcin 
18410444adf6SMatthew G. Knepley   { /* Create Cell/Face/Edge/Vertex Sets labels at all processes */
18429371c9d4SSatish Balay     enum {
18430444adf6SMatthew G. Knepley       n = 5
18449371c9d4SSatish Balay     };
18457dd454faSLisandro Dalcin     PetscBool flag[n];
18467dd454faSLisandro Dalcin 
18477dd454faSLisandro Dalcin     flag[0] = cellSets ? PETSC_TRUE : PETSC_FALSE;
18487dd454faSLisandro Dalcin     flag[1] = faceSets ? PETSC_TRUE : PETSC_FALSE;
18490444adf6SMatthew G. Knepley     flag[2] = edgeSets ? PETSC_TRUE : PETSC_FALSE;
18500444adf6SMatthew G. Knepley     flag[3] = vertSets ? PETSC_TRUE : PETSC_FALSE;
18510444adf6SMatthew G. Knepley     flag[4] = marker ? PETSC_TRUE : PETSC_FALSE;
18529566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Bcast(flag, n, MPIU_BOOL, 0, comm));
18539566063dSJacob Faibussowitsch     if (flag[0]) PetscCall(DMCreateLabel(*dm, "Cell Sets"));
18549566063dSJacob Faibussowitsch     if (flag[1]) PetscCall(DMCreateLabel(*dm, "Face Sets"));
18550444adf6SMatthew G. Knepley     if (flag[2]) PetscCall(DMCreateLabel(*dm, "Edge Sets"));
18560444adf6SMatthew G. Knepley     if (flag[3]) PetscCall(DMCreateLabel(*dm, "Vertex Sets"));
18570444adf6SMatthew G. Knepley     if (flag[4]) PetscCall(DMCreateLabel(*dm, "marker"));
18587dd454faSLisandro Dalcin   }
18597dd454faSLisandro Dalcin 
18600598e1a2SLisandro Dalcin   if (periodic) {
18619566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(numVerts, &periodicVerts));
18620598e1a2SLisandro Dalcin     for (n = 0; n < numNodes; ++n) {
18630598e1a2SLisandro Dalcin       if (mesh->vertexMap[n] >= 0) {
18640598e1a2SLisandro Dalcin         if (PetscUnlikely(mesh->periodMap[n] != n)) {
18650598e1a2SLisandro Dalcin           PetscInt m = mesh->periodMap[n];
18669566063dSJacob Faibussowitsch           PetscCall(PetscBTSet(periodicVerts, mesh->vertexMap[n]));
18679566063dSJacob Faibussowitsch           PetscCall(PetscBTSet(periodicVerts, mesh->vertexMap[m]));
18680598e1a2SLisandro Dalcin         }
18690598e1a2SLisandro Dalcin       }
18700598e1a2SLisandro Dalcin     }
18719db5b827SMatthew G. Knepley     PetscCall(DMGetCoordinateDM(*dm, &cdm));
1872eae3dc7dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxHeight + 1, &periodicCells));
18739db5b827SMatthew G. Knepley     for (PetscInt h = 0; h <= maxHeight; ++h) {
18749db5b827SMatthew G. Knepley       PetscInt pStart, pEnd;
18759db5b827SMatthew G. Knepley 
18769db5b827SMatthew G. Knepley       PetscCall(DMPlexGetHeightStratum(*dm, h, &pStart, &pEnd));
18779db5b827SMatthew G. Knepley       PetscCall(PetscBTCreate(pEnd - pStart, &periodicCells[h]));
18789db5b827SMatthew G. Knepley       for (PetscInt p = pStart; p < pEnd; ++p) {
18799db5b827SMatthew G. Knepley         PetscInt *closure = NULL;
18809db5b827SMatthew G. Knepley         PetscInt  Ncl;
18819db5b827SMatthew G. Knepley 
18829db5b827SMatthew G. Knepley         PetscCall(DMPlexGetTransitiveClosure(*dm, p, PETSC_TRUE, &Ncl, &closure));
18839db5b827SMatthew G. Knepley         for (PetscInt cl = 0; cl < Ncl * 2; cl += 2) {
18849db5b827SMatthew G. Knepley           if (closure[cl] >= vStart && closure[cl] < vEnd) {
18859db5b827SMatthew G. Knepley             if (PetscUnlikely(PetscBTLookup(periodicVerts, closure[cl] - vStart))) {
18869db5b827SMatthew G. Knepley               PetscCall(PetscBTSet(periodicCells[h], p - pStart));
18879371c9d4SSatish Balay               break;
18880c070f12SSander Arens             }
18890c070f12SSander Arens           }
18900c070f12SSander Arens         }
18919db5b827SMatthew G. Knepley         PetscCall(DMPlexRestoreTransitiveClosure(*dm, p, PETSC_TRUE, &Ncl, &closure));
18929db5b827SMatthew G. Knepley       }
18939db5b827SMatthew G. Knepley     }
189416ad7e67SMichael Lange   }
189516ad7e67SMichael Lange 
1896066ea43fSLisandro Dalcin   /* Setup coordinate DM */
18970598e1a2SLisandro Dalcin   if (coordDim < 0) coordDim = dim;
18989566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinateDim(*dm, coordDim));
18999566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(*dm, &cdm));
1900066ea43fSLisandro Dalcin   if (highOrder) {
1901066ea43fSLisandro Dalcin     PetscFE         fe;
1902066ea43fSLisandro Dalcin     PetscBool       continuity = periodic ? PETSC_FALSE : PETSC_TRUE;
1903066ea43fSLisandro Dalcin     PetscDTNodeType nodeType   = PETSCDTNODES_EQUISPACED;
1904066ea43fSLisandro Dalcin 
1905066ea43fSLisandro Dalcin     if (isSimplex) continuity = PETSC_FALSE; /* XXX FIXME Requires DMPlexSetClosurePermutationLexicographic() */
1906066ea43fSLisandro Dalcin 
19079566063dSJacob Faibussowitsch     PetscCall(GmshCreateFE(comm, NULL, isSimplex, continuity, nodeType, dim, coordDim, order, &fe));
19089566063dSJacob Faibussowitsch     PetscCall(PetscFEViewFromOptions(fe, NULL, "-dm_plex_gmsh_fe_view"));
19099566063dSJacob Faibussowitsch     PetscCall(DMSetField(cdm, 0, NULL, (PetscObject)fe));
19109566063dSJacob Faibussowitsch     PetscCall(PetscFEDestroy(&fe));
19119566063dSJacob Faibussowitsch     PetscCall(DMCreateDS(cdm));
1912066ea43fSLisandro Dalcin   }
19136858538eSMatthew G. Knepley   if (periodic) {
19146858538eSMatthew G. Knepley     PetscCall(DMClone(cdm, &cdmCell));
19156858538eSMatthew G. Knepley     PetscCall(DMSetCellCoordinateDM(*dm, cdmCell));
19166858538eSMatthew G. Knepley   }
1917066ea43fSLisandro Dalcin 
1918066ea43fSLisandro Dalcin   /* Create coordinates */
1919066ea43fSLisandro Dalcin   if (highOrder) {
1920066ea43fSLisandro Dalcin     PetscInt     maxDof = GmshNumNodes_HEX(order) * coordDim;
1921066ea43fSLisandro Dalcin     double      *coords = mesh ? mesh->nodelist->xyz : NULL;
1922066ea43fSLisandro Dalcin     PetscSection section;
1923066ea43fSLisandro Dalcin     PetscScalar *cellCoords;
1924066ea43fSLisandro Dalcin 
19259566063dSJacob Faibussowitsch     PetscCall(DMSetLocalSection(cdm, NULL));
19266858538eSMatthew G. Knepley     PetscCall(DMGetLocalSection(cdm, &cs));
19276858538eSMatthew G. Knepley     PetscCall(PetscSectionClone(cs, &section));
19289566063dSJacob Faibussowitsch     PetscCall(DMPlexSetClosurePermutationTensor(cdm, 0, section)); /* XXX Implement DMPlexSetClosurePermutationLexicographic() */
1929066ea43fSLisandro Dalcin 
19309566063dSJacob Faibussowitsch     PetscCall(DMCreateLocalVector(cdm, &coordinates));
19319566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxDof, &cellCoords));
1932066ea43fSLisandro Dalcin     for (cell = 0; cell < numCells; ++cell) {
1933066ea43fSLisandro Dalcin       GmshElement *elem     = mesh->elements + cell;
1934066ea43fSLisandro Dalcin       const int   *lexorder = GmshCellMap[elem->cellType].lexorder();
1935b9bf55e5SMatthew G. Knepley       int          s        = 0;
1936066ea43fSLisandro Dalcin       for (n = 0; n < elem->numNodes; ++n) {
1937b9bf55e5SMatthew G. Knepley         while (lexorder[n + s] < 0) ++s;
1938b9bf55e5SMatthew G. Knepley         const PetscInt node = elem->nodes[lexorder[n + s]];
1939b9bf55e5SMatthew G. Knepley         for (d = 0; d < coordDim; ++d) cellCoords[(n + s) * coordDim + d] = (PetscReal)coords[node * 3 + d];
1940b9bf55e5SMatthew G. Knepley       }
1941b9bf55e5SMatthew G. Knepley       if (s) {
1942b9bf55e5SMatthew G. Knepley         /* For the coordinate mapping we weight vertices by -1/4 and edges by 1/2, which we get from Q_2 interpolation */
1943b9bf55e5SMatthew G. Knepley         PetscReal quaCenterWeights[9] = {-0.25, 0.5, -0.25, 0.5, 0.0, 0.5, -0.25, 0.5, -0.25};
1944b9bf55e5SMatthew G. Knepley         /* For the coordinate mapping we weight vertices by -1/4 and edges by 1/2, which we get from Q_2 interpolation */
19459371c9d4SSatish 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};
19469371c9d4SSatish 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};
19479371c9d4SSatish 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};
19489371c9d4SSatish 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};
19499371c9d4SSatish 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};
19509371c9d4SSatish 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};
19519371c9d4SSatish 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};
1952b9bf55e5SMatthew G. Knepley         PetscReal  *sdWeights2[9]        = {NULL, NULL, NULL, NULL, quaCenterWeights, NULL, NULL, NULL, NULL};
19539371c9d4SSatish Balay         PetscReal  *sdWeights3[27]       = {NULL, NULL, NULL, NULL, hexBottomWeights, NULL, NULL, NULL, NULL, NULL, hexFrontWeights, NULL, hexLeftWeights, hexCenterWeights, hexRightWeights, NULL, hexBackWeights, NULL,
1954b9bf55e5SMatthew G. Knepley                                             NULL, NULL, NULL, NULL, hexTopWeights,    NULL, NULL, NULL, NULL};
1955b9bf55e5SMatthew G. Knepley         PetscReal **sdWeights[4]         = {NULL, NULL, sdWeights2, sdWeights3};
1956b9bf55e5SMatthew G. Knepley 
1957b9bf55e5SMatthew G. Knepley         /* Missing entries in serendipity cell, only works for 8-node quad and 20-node hex */
1958b9bf55e5SMatthew G. Knepley         for (n = 0; n < elem->numNodes + s; ++n) {
1959b9bf55e5SMatthew G. Knepley           if (lexorder[n] >= 0) continue;
1960b9bf55e5SMatthew G. Knepley           for (d = 0; d < coordDim; ++d) cellCoords[n * coordDim + d] = 0.0;
1961b9bf55e5SMatthew G. Knepley           for (int bn = 0; bn < elem->numNodes + s; ++bn) {
1962b9bf55e5SMatthew G. Knepley             if (lexorder[bn] < 0) continue;
1963b9bf55e5SMatthew G. Knepley             const PetscReal *weights = sdWeights[coordDim][n];
1964b9bf55e5SMatthew G. Knepley             const PetscInt   bnode   = elem->nodes[lexorder[bn]];
1965b9bf55e5SMatthew G. Knepley             for (d = 0; d < coordDim; ++d) cellCoords[n * coordDim + d] += weights[bn] * (PetscReal)coords[bnode * 3 + d];
1966b9bf55e5SMatthew G. Knepley           }
1967b9bf55e5SMatthew G. Knepley         }
1968066ea43fSLisandro Dalcin       }
19699566063dSJacob Faibussowitsch       PetscCall(DMPlexVecSetClosure(cdm, section, coordinates, cell, cellCoords, INSERT_VALUES));
1970066ea43fSLisandro Dalcin     }
19719566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&section));
19729566063dSJacob Faibussowitsch     PetscCall(PetscFree(cellCoords));
1973066ea43fSLisandro Dalcin   } else {
1974066ea43fSLisandro Dalcin     PetscInt    *nodeMap;
1975066ea43fSLisandro Dalcin     double      *coords = mesh ? mesh->nodelist->xyz : NULL;
1976066ea43fSLisandro Dalcin     PetscScalar *pointCoords;
1977066ea43fSLisandro Dalcin 
19786858538eSMatthew G. Knepley     PetscCall(DMGetCoordinateSection(*dm, &cs));
19796858538eSMatthew G. Knepley     PetscCall(PetscSectionSetNumFields(cs, 1));
19806858538eSMatthew G. Knepley     PetscCall(PetscSectionSetFieldComponents(cs, 0, coordDim));
19816858538eSMatthew G. Knepley     PetscCall(PetscSectionSetChart(cs, numCells, numCells + numVerts));
19826858538eSMatthew G. Knepley     for (v = numCells; v < numCells + numVerts; ++v) {
19836858538eSMatthew G. Knepley       PetscCall(PetscSectionSetDof(cs, v, coordDim));
19846858538eSMatthew G. Knepley       PetscCall(PetscSectionSetFieldDof(cs, v, 0, coordDim));
1985f45c9589SStefano Zampini     }
19866858538eSMatthew G. Knepley     PetscCall(PetscSectionSetUp(cs));
19876858538eSMatthew G. Knepley 
19886858538eSMatthew G. Knepley     /* We need to localize coordinates on cells */
19890598e1a2SLisandro Dalcin     if (periodic) {
19909db5b827SMatthew G. Knepley       PetscInt newStart = PETSC_MAX_INT, newEnd = -1, pStart, pEnd;
19919db5b827SMatthew G. Knepley 
19926858538eSMatthew G. Knepley       PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)cdmCell), &csCell));
19936858538eSMatthew G. Knepley       PetscCall(PetscSectionSetNumFields(csCell, 1));
19946858538eSMatthew G. Knepley       PetscCall(PetscSectionSetFieldComponents(csCell, 0, coordDim));
19959db5b827SMatthew G. Knepley       for (PetscInt h = 0; h <= maxHeight; h++) {
19969db5b827SMatthew G. Knepley         PetscCall(DMPlexGetHeightStratum(cdmCell, h, &pStart, &pEnd));
19979db5b827SMatthew G. Knepley         newStart = PetscMin(newStart, pStart);
19989db5b827SMatthew G. Knepley         newEnd   = PetscMax(newEnd, pEnd);
19999db5b827SMatthew G. Knepley       }
20009db5b827SMatthew G. Knepley       PetscCall(PetscSectionSetChart(csCell, newStart, newEnd));
20019db5b827SMatthew G. Knepley       for (PetscInt h = 0; h <= maxHeight; h++) {
20029db5b827SMatthew G. Knepley         PetscCall(DMPlexGetHeightStratum(cdmCell, h, &pStart, &pEnd));
20039db5b827SMatthew G. Knepley         for (PetscInt p = pStart; p < pEnd; ++p) {
20049db5b827SMatthew G. Knepley           PetscInt *closure = NULL;
20059db5b827SMatthew G. Knepley           PetscInt  Ncl, Nv = 0;
20066858538eSMatthew G. Knepley 
20079db5b827SMatthew G. Knepley           if (PetscUnlikely(PetscBTLookup(periodicCells[h], p - pStart))) {
20089db5b827SMatthew G. Knepley             PetscCall(DMPlexGetTransitiveClosure(*dm, p, PETSC_TRUE, &Ncl, &closure));
20099db5b827SMatthew G. Knepley             for (PetscInt cl = 0; cl < Ncl * 2; cl += 2) {
20109db5b827SMatthew G. Knepley               if (closure[cl] >= vStart && closure[cl] < vEnd) ++Nv;
20119db5b827SMatthew G. Knepley             }
20129db5b827SMatthew G. Knepley             PetscCall(DMPlexRestoreTransitiveClosure(*dm, p, PETSC_TRUE, &Ncl, &closure));
20139db5b827SMatthew G. Knepley             PetscCall(PetscSectionSetDof(csCell, p, Nv * coordDim));
20149db5b827SMatthew G. Knepley             PetscCall(PetscSectionSetFieldDof(csCell, p, 0, Nv * coordDim));
20159db5b827SMatthew G. Knepley           }
2016f45c9589SStefano Zampini         }
2017f45c9589SStefano Zampini       }
20186858538eSMatthew G. Knepley       PetscCall(PetscSectionSetUp(csCell));
20196858538eSMatthew G. Knepley       PetscCall(DMSetCellCoordinateSection(*dm, PETSC_DETERMINE, csCell));
2020f45c9589SStefano Zampini     }
2021066ea43fSLisandro Dalcin 
20229566063dSJacob Faibussowitsch     PetscCall(DMCreateLocalVector(cdm, &coordinates));
20239566063dSJacob Faibussowitsch     PetscCall(VecGetArray(coordinates, &pointCoords));
20246858538eSMatthew G. Knepley     PetscCall(PetscMalloc1(numVerts, &nodeMap));
20256858538eSMatthew G. Knepley     for (n = 0; n < numNodes; n++)
20266858538eSMatthew G. Knepley       if (mesh->vertexMap[n] >= 0) nodeMap[mesh->vertexMap[n]] = n;
20276858538eSMatthew G. Knepley     for (v = 0; v < numVerts; ++v) {
20286858538eSMatthew G. Knepley       PetscInt off, node = nodeMap[v];
20296858538eSMatthew G. Knepley 
20306858538eSMatthew G. Knepley       PetscCall(PetscSectionGetOffset(cs, numCells + v, &off));
20316858538eSMatthew G. Knepley       for (d = 0; d < coordDim; ++d) pointCoords[off + d] = (PetscReal)coords[node * 3 + d];
20326858538eSMatthew G. Knepley     }
20336858538eSMatthew G. Knepley     PetscCall(VecRestoreArray(coordinates, &pointCoords));
20346858538eSMatthew G. Knepley 
20350598e1a2SLisandro Dalcin     if (periodic) {
20369db5b827SMatthew G. Knepley       PetscInt cStart, cEnd;
20379db5b827SMatthew G. Knepley 
20389db5b827SMatthew G. Knepley       PetscCall(DMPlexGetHeightStratum(cdmCell, 0, &cStart, &cEnd));
20396858538eSMatthew G. Knepley       PetscCall(DMCreateLocalVector(cdmCell, &coordinatesCell));
20406858538eSMatthew G. Knepley       PetscCall(VecGetArray(coordinatesCell, &pointCoords));
20419db5b827SMatthew G. Knepley       for (PetscInt c = cStart; c < cEnd; ++c) {
20429db5b827SMatthew G. Knepley         GmshElement *elem    = mesh->elements + c - cStart;
20439db5b827SMatthew G. Knepley         PetscInt    *closure = NULL;
20449db5b827SMatthew G. Knepley         PetscInt     verts[8];
20459db5b827SMatthew G. Knepley         PetscInt     Ncl, Nv = 0;
20469db5b827SMatthew G. Knepley 
20479db5b827SMatthew G. Knepley         for (PetscInt v = 0; v < elem->numVerts; ++v) cone[v] = elem->nodes[v];
20489db5b827SMatthew G. Knepley         PetscCall(DMPlexReorderCell(cdmCell, c, cone));
20499db5b827SMatthew G. Knepley         PetscCall(DMPlexGetTransitiveClosure(cdmCell, c, PETSC_TRUE, &Ncl, &closure));
20509db5b827SMatthew G. Knepley         for (PetscInt cl = 0; cl < Ncl * 2; cl += 2) {
20519db5b827SMatthew G. Knepley           if (closure[cl] >= vStart && closure[cl] < vEnd) verts[Nv++] = closure[cl];
2052331830f3SMatthew G. Knepley         }
20539db5b827SMatthew 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);
20549db5b827SMatthew G. Knepley         for (PetscInt cl = 0; cl < Ncl * 2; cl += 2) {
20559db5b827SMatthew G. Knepley           const PetscInt point = closure[cl];
20569db5b827SMatthew G. Knepley           PetscInt       hStart, h;
20579db5b827SMatthew G. Knepley 
20589db5b827SMatthew G. Knepley           PetscCall(DMPlexGetPointHeight(cdmCell, point, &h));
20599db5b827SMatthew G. Knepley           if (h > maxHeight) continue;
20609db5b827SMatthew G. Knepley           PetscCall(DMPlexGetHeightStratum(cdmCell, h, &hStart, NULL));
20619db5b827SMatthew G. Knepley           if (PetscUnlikely(PetscBTLookup(periodicCells[h], point - hStart))) {
20629db5b827SMatthew G. Knepley             PetscInt *pclosure = NULL;
20639db5b827SMatthew G. Knepley             PetscInt  Npcl, off, v;
20649db5b827SMatthew G. Knepley 
20659db5b827SMatthew G. Knepley             PetscCall(PetscSectionGetOffset(csCell, point, &off));
20669db5b827SMatthew G. Knepley             PetscCall(DMPlexGetTransitiveClosure(cdmCell, point, PETSC_TRUE, &Npcl, &pclosure));
20679db5b827SMatthew G. Knepley             for (PetscInt pcl = 0; pcl < Npcl * 2; pcl += 2) {
20689db5b827SMatthew G. Knepley               if (pclosure[pcl] >= vStart && pclosure[pcl] < vEnd) {
20699db5b827SMatthew G. Knepley                 for (v = 0; v < Nv; ++v)
20709db5b827SMatthew G. Knepley                   if (verts[v] == pclosure[pcl]) break;
20719db5b827SMatthew 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);
20729db5b827SMatthew G. Knepley                 for (PetscInt d = 0; d < coordDim; ++d) pointCoords[off++] = (PetscReal)coords[cone[v] * 3 + d];
20739db5b827SMatthew G. Knepley                 ++v;
20749db5b827SMatthew G. Knepley               }
20759db5b827SMatthew G. Knepley             }
20769db5b827SMatthew G. Knepley             PetscCall(DMPlexRestoreTransitiveClosure(cdmCell, point, PETSC_TRUE, &Npcl, &pclosure));
20779db5b827SMatthew G. Knepley           }
20789db5b827SMatthew G. Knepley         }
20799db5b827SMatthew G. Knepley         PetscCall(DMPlexRestoreTransitiveClosure(cdmCell, c, PETSC_TRUE, &Ncl, &closure));
2080331830f3SMatthew G. Knepley       }
20816858538eSMatthew G. Knepley       PetscCall(VecSetBlockSize(coordinatesCell, coordDim));
20826858538eSMatthew G. Knepley       PetscCall(VecRestoreArray(coordinatesCell, &pointCoords));
20836858538eSMatthew G. Knepley       PetscCall(DMSetCellCoordinatesLocal(*dm, coordinatesCell));
20846858538eSMatthew G. Knepley       PetscCall(VecDestroy(&coordinatesCell));
2085331830f3SMatthew G. Knepley     }
20869db5b827SMatthew G. Knepley     PetscCall(PetscFree(nodeMap));
20876858538eSMatthew G. Knepley     PetscCall(PetscSectionDestroy(&csCell));
20886858538eSMatthew G. Knepley     PetscCall(DMDestroy(&cdmCell));
2089066ea43fSLisandro Dalcin   }
2090066ea43fSLisandro Dalcin 
20919566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
20929566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(coordinates, coordDim));
20939566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinatesLocal(*dm, coordinates));
20949566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&coordinates));
209511c56cb0SLisandro Dalcin 
20969566063dSJacob Faibussowitsch   PetscCall(GmshMeshDestroy(&mesh));
20979566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&periodicVerts));
2098eae3dc7dSJacob Faibussowitsch   if (periodic) {
2099eae3dc7dSJacob Faibussowitsch     for (PetscInt h = 0; h <= maxHeight; ++h) PetscCall(PetscBTDestroy(periodicCells + h));
2100eae3dc7dSJacob Faibussowitsch     PetscCall(PetscFree(periodicCells));
2101eae3dc7dSJacob Faibussowitsch   }
210211c56cb0SLisandro Dalcin 
2103066ea43fSLisandro Dalcin   if (highOrder && project) {
2104066ea43fSLisandro Dalcin     PetscFE         fe;
2105066ea43fSLisandro Dalcin     const char      prefix[]   = "dm_plex_gmsh_project_";
2106066ea43fSLisandro Dalcin     PetscBool       continuity = periodic ? PETSC_FALSE : PETSC_TRUE;
2107066ea43fSLisandro Dalcin     PetscDTNodeType nodeType   = PETSCDTNODES_GAUSSJACOBI;
2108066ea43fSLisandro Dalcin 
2109066ea43fSLisandro Dalcin     if (isSimplex) continuity = PETSC_FALSE; /* XXX FIXME Requires DMPlexSetClosurePermutationLexicographic() */
21109566063dSJacob Faibussowitsch     PetscCall(GmshCreateFE(comm, prefix, isSimplex, continuity, nodeType, dim, coordDim, order, &fe));
21119566063dSJacob Faibussowitsch     PetscCall(PetscFEViewFromOptions(fe, NULL, "-dm_plex_gmsh_project_fe_view"));
2112e44f6aebSMatthew G. Knepley     PetscCall(DMSetCoordinateDisc(*dm, fe, PETSC_TRUE));
21139566063dSJacob Faibussowitsch     PetscCall(PetscFEDestroy(&fe));
2114066ea43fSLisandro Dalcin   }
2115066ea43fSLisandro Dalcin 
21169566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_CreateGmsh, *dm, NULL, NULL, NULL));
21173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2118331830f3SMatthew G. Knepley }
2119