xref: /petsc/src/dm/impls/plex/plexgmsh.c (revision 1690c2ae071c7584458d4e437df7b47bc4686b3c)
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 
12010dd146fSPierre Jolivet // clang-format off
12110dd146fSPierre Jolivet #define GmshCellEntry(cellType, polytope, dim, order) {cellType, GMSH_##polytope, dim, order, GmshNumNodes_##polytope(1), GmshNumNodes_##polytope(order), GmshLexOrder_##polytope##_##order}
12210dd146fSPierre 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 
2126497c311SBarry Smith /*
2136497c311SBarry Smith    Returns an array of count items each with a sizeof(eltsize)
2146497c311SBarry Smith */
2156497c311SBarry Smith static PetscErrorCode GmshBufferGet(GmshFile *gmsh, PetscCount count, size_t eltsize, void *buf)
216d71ae5a4SJacob Faibussowitsch {
217de78e4feSLisandro Dalcin   size_t size = count * eltsize;
21811c56cb0SLisandro Dalcin 
21911c56cb0SLisandro Dalcin   PetscFunctionBegin;
220698a79b9SLisandro Dalcin   if (gmsh->wlen < size) {
2219566063dSJacob Faibussowitsch     PetscCall(PetscFree(gmsh->wbuf));
2229566063dSJacob Faibussowitsch     PetscCall(PetscMalloc(size, &gmsh->wbuf));
223698a79b9SLisandro Dalcin     gmsh->wlen = size;
224de78e4feSLisandro Dalcin   }
225698a79b9SLisandro Dalcin   *(void **)buf = size ? gmsh->wbuf : NULL;
2263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
227de78e4feSLisandro Dalcin }
228de78e4feSLisandro Dalcin 
2296497c311SBarry Smith /*
2306497c311SBarry Smith     Returns an array of count items each with the size determined by the GmshFile
2316497c311SBarry Smith */
2326497c311SBarry Smith static PetscErrorCode GmshBufferSizeGet(GmshFile *gmsh, PetscCount count, void *buf)
233d71ae5a4SJacob Faibussowitsch {
234698a79b9SLisandro Dalcin   size_t dataSize = (size_t)gmsh->dataSize;
235698a79b9SLisandro Dalcin   size_t size     = count * dataSize;
236698a79b9SLisandro Dalcin 
237698a79b9SLisandro Dalcin   PetscFunctionBegin;
238698a79b9SLisandro Dalcin   if (gmsh->slen < size) {
2399566063dSJacob Faibussowitsch     PetscCall(PetscFree(gmsh->sbuf));
2409566063dSJacob Faibussowitsch     PetscCall(PetscMalloc(size, &gmsh->sbuf));
241698a79b9SLisandro Dalcin     gmsh->slen = size;
242698a79b9SLisandro Dalcin   }
243698a79b9SLisandro Dalcin   *(void **)buf = size ? gmsh->sbuf : NULL;
2443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
245698a79b9SLisandro Dalcin }
246698a79b9SLisandro Dalcin 
2476497c311SBarry Smith /*
2486497c311SBarry Smith     Reads an array of count items each with the size determined by the PetscDataType
2496497c311SBarry Smith */
2506497c311SBarry Smith static PetscErrorCode GmshRead(GmshFile *gmsh, void *buf, PetscCount count, PetscDataType dtype)
251d71ae5a4SJacob Faibussowitsch {
2526497c311SBarry Smith   PetscInt icount;
2536497c311SBarry Smith 
254de78e4feSLisandro Dalcin   PetscFunctionBegin;
2556497c311SBarry Smith   PetscCall(PetscIntCast(count, &icount));
2566497c311SBarry Smith   PetscCall(PetscViewerRead(gmsh->viewer, buf, icount, NULL, dtype));
2576497c311SBarry Smith   if (gmsh->byteSwap) PetscCall(PetscByteSwap(buf, dtype, icount));
2583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
259698a79b9SLisandro Dalcin }
260698a79b9SLisandro Dalcin 
2616497c311SBarry Smith static PetscErrorCode GmshReadString(GmshFile *gmsh, char *buf, PetscCount count)
262d71ae5a4SJacob Faibussowitsch {
2636497c311SBarry Smith   PetscInt icount;
2646497c311SBarry Smith 
265698a79b9SLisandro Dalcin   PetscFunctionBegin;
2666497c311SBarry Smith   PetscCall(PetscIntCast(count, &icount));
2676497c311SBarry Smith   PetscCall(PetscViewerRead(gmsh->viewer, buf, icount, NULL, PETSC_STRING));
2683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
269698a79b9SLisandro Dalcin }
270698a79b9SLisandro Dalcin 
271d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshMatch(PETSC_UNUSED GmshFile *gmsh, const char Section[], char line[PETSC_MAX_PATH_LEN], PetscBool *match)
272d71ae5a4SJacob Faibussowitsch {
273d6689ca9SLisandro Dalcin   PetscFunctionBegin;
2749566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(line, Section, match));
2753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
276d6689ca9SLisandro Dalcin }
277d6689ca9SLisandro Dalcin 
278d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshExpect(GmshFile *gmsh, const char Section[], char line[PETSC_MAX_PATH_LEN])
279d71ae5a4SJacob Faibussowitsch {
280d6689ca9SLisandro Dalcin   PetscBool match;
281d6689ca9SLisandro Dalcin 
282d6689ca9SLisandro Dalcin   PetscFunctionBegin;
2839566063dSJacob Faibussowitsch   PetscCall(GmshMatch(gmsh, Section, line, &match));
28400045ab3SPierre Jolivet   PetscCheck(match, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file, expecting %s, not %s", Section, line);
2853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
286d6689ca9SLisandro Dalcin }
287d6689ca9SLisandro Dalcin 
288d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadSection(GmshFile *gmsh, char line[PETSC_MAX_PATH_LEN])
289d71ae5a4SJacob Faibussowitsch {
290d6689ca9SLisandro Dalcin   PetscBool match;
291d6689ca9SLisandro Dalcin 
292d6689ca9SLisandro Dalcin   PetscFunctionBegin;
293d6689ca9SLisandro Dalcin   while (PETSC_TRUE) {
2949566063dSJacob Faibussowitsch     PetscCall(GmshReadString(gmsh, line, 1));
2959566063dSJacob Faibussowitsch     PetscCall(GmshMatch(gmsh, "$Comments", line, &match));
296d6689ca9SLisandro Dalcin     if (!match) break;
297d6689ca9SLisandro Dalcin     while (PETSC_TRUE) {
2989566063dSJacob Faibussowitsch       PetscCall(GmshReadString(gmsh, line, 1));
2999566063dSJacob Faibussowitsch       PetscCall(GmshMatch(gmsh, "$EndComments", line, &match));
300d6689ca9SLisandro Dalcin       if (match) break;
301d6689ca9SLisandro Dalcin     }
302d6689ca9SLisandro Dalcin   }
3033ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
304d6689ca9SLisandro Dalcin }
305d6689ca9SLisandro Dalcin 
306d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadEndSection(GmshFile *gmsh, const char EndSection[], char line[PETSC_MAX_PATH_LEN])
307d71ae5a4SJacob Faibussowitsch {
308d6689ca9SLisandro Dalcin   PetscFunctionBegin;
3099566063dSJacob Faibussowitsch   PetscCall(GmshReadString(gmsh, line, 1));
3109566063dSJacob Faibussowitsch   PetscCall(GmshExpect(gmsh, EndSection, line));
3113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
312d6689ca9SLisandro Dalcin }
313d6689ca9SLisandro Dalcin 
3146497c311SBarry Smith /*
3156497c311SBarry Smith      Read into buf[] count number of PetscInt integers (the file storage size may be different than PetscInt)
3166497c311SBarry Smith */
3176497c311SBarry Smith static PetscErrorCode GmshReadPetscInt(GmshFile *gmsh, PetscInt *buf, PetscCount count)
318d71ae5a4SJacob Faibussowitsch {
3196497c311SBarry Smith   PetscCount i;
320698a79b9SLisandro Dalcin   size_t     dataSize = (size_t)gmsh->dataSize;
321698a79b9SLisandro Dalcin 
322698a79b9SLisandro Dalcin   PetscFunctionBegin;
323698a79b9SLisandro Dalcin   if (dataSize == sizeof(PetscInt)) {
3249566063dSJacob Faibussowitsch     PetscCall(GmshRead(gmsh, buf, count, PETSC_INT));
325698a79b9SLisandro Dalcin   } else if (dataSize == sizeof(int)) {
326698a79b9SLisandro Dalcin     int *ibuf = NULL;
3279566063dSJacob Faibussowitsch     PetscCall(GmshBufferSizeGet(gmsh, count, &ibuf));
3289566063dSJacob Faibussowitsch     PetscCall(GmshRead(gmsh, ibuf, count, PETSC_ENUM));
329698a79b9SLisandro Dalcin     for (i = 0; i < count; ++i) buf[i] = (PetscInt)ibuf[i];
330698a79b9SLisandro Dalcin   } else if (dataSize == sizeof(long)) {
331698a79b9SLisandro Dalcin     long *ibuf = NULL;
3329566063dSJacob Faibussowitsch     PetscCall(GmshBufferSizeGet(gmsh, count, &ibuf));
3339566063dSJacob Faibussowitsch     PetscCall(GmshRead(gmsh, ibuf, count, PETSC_LONG));
334698a79b9SLisandro Dalcin     for (i = 0; i < count; ++i) buf[i] = (PetscInt)ibuf[i];
335698a79b9SLisandro Dalcin   } else if (dataSize == sizeof(PetscInt64)) {
336698a79b9SLisandro Dalcin     PetscInt64 *ibuf = NULL;
3379566063dSJacob Faibussowitsch     PetscCall(GmshBufferSizeGet(gmsh, count, &ibuf));
3389566063dSJacob Faibussowitsch     PetscCall(GmshRead(gmsh, ibuf, count, PETSC_INT64));
339698a79b9SLisandro Dalcin     for (i = 0; i < count; ++i) buf[i] = (PetscInt)ibuf[i];
340698a79b9SLisandro Dalcin   }
3413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
342698a79b9SLisandro Dalcin }
343698a79b9SLisandro Dalcin 
3446497c311SBarry Smith /*
3456497c311SBarry Smith      Read into buf[] count number of PetscCount integers  (the file storage size may be different than PetscCount)
3466497c311SBarry Smith */
3476497c311SBarry Smith static PetscErrorCode GmshReadPetscCount(GmshFile *gmsh, PetscCount *buf, PetscCount count)
3486497c311SBarry Smith {
3496497c311SBarry Smith   PetscCount i;
3506497c311SBarry Smith   size_t     dataSize = (size_t)gmsh->dataSize;
3516497c311SBarry Smith 
3526497c311SBarry Smith   PetscFunctionBegin;
3536497c311SBarry Smith   if (dataSize == sizeof(PetscCount)) {
3546497c311SBarry Smith     PetscCall(GmshRead(gmsh, buf, count, PETSC_COUNT));
3556497c311SBarry Smith   } else if (dataSize == sizeof(int)) {
3566497c311SBarry Smith     int *ibuf = NULL;
3576497c311SBarry Smith     PetscCall(GmshBufferSizeGet(gmsh, count, &ibuf));
3586497c311SBarry Smith     PetscCall(GmshRead(gmsh, ibuf, count, PETSC_ENUM));
3596497c311SBarry Smith     for (i = 0; i < count; ++i) buf[i] = (PetscCount)ibuf[i];
3606497c311SBarry Smith   } else if (dataSize == sizeof(long)) {
3616497c311SBarry Smith     long *ibuf = NULL;
3626497c311SBarry Smith     PetscCall(GmshBufferSizeGet(gmsh, count, &ibuf));
3636497c311SBarry Smith     PetscCall(GmshRead(gmsh, ibuf, count, PETSC_LONG));
3646497c311SBarry Smith     for (i = 0; i < count; ++i) buf[i] = (PetscCount)ibuf[i];
3656497c311SBarry Smith   } else if (dataSize == sizeof(PetscInt64)) {
3666497c311SBarry Smith     PetscInt64 *ibuf = NULL;
3676497c311SBarry Smith     PetscCall(GmshBufferSizeGet(gmsh, count, &ibuf));
3686497c311SBarry Smith     PetscCall(GmshRead(gmsh, ibuf, count, PETSC_INT64));
3696497c311SBarry Smith     for (i = 0; i < count; ++i) buf[i] = (PetscCount)ibuf[i];
3706497c311SBarry Smith   }
3716497c311SBarry Smith   PetscFunctionReturn(PETSC_SUCCESS);
3726497c311SBarry Smith }
3736497c311SBarry Smith 
3746497c311SBarry Smith /*
3756497c311SBarry Smith      Read into buf[] count number of PetscEnum integers
3766497c311SBarry Smith */
3776497c311SBarry Smith static PetscErrorCode GmshReadInt(GmshFile *gmsh, int *buf, PetscCount count)
378d71ae5a4SJacob Faibussowitsch {
379698a79b9SLisandro Dalcin   PetscFunctionBegin;
3809566063dSJacob Faibussowitsch   PetscCall(GmshRead(gmsh, buf, count, PETSC_ENUM));
3813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
382698a79b9SLisandro Dalcin }
383698a79b9SLisandro Dalcin 
3846497c311SBarry Smith /*
3856497c311SBarry Smith      Read into buf[] count number of double
3866497c311SBarry Smith */
3876497c311SBarry Smith static PetscErrorCode GmshReadDouble(GmshFile *gmsh, double *buf, PetscCount count)
388d71ae5a4SJacob Faibussowitsch {
389698a79b9SLisandro Dalcin   PetscFunctionBegin;
3909566063dSJacob Faibussowitsch   PetscCall(GmshRead(gmsh, buf, count, PETSC_DOUBLE));
3913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
392de78e4feSLisandro Dalcin }
393de78e4feSLisandro Dalcin 
3949c0edc59SMatthew G. Knepley #define GMSH_MAX_TAGS 16
3957d5b9244SMatthew G. Knepley 
396de78e4feSLisandro Dalcin typedef struct {
3970598e1a2SLisandro Dalcin   PetscInt id;                  /* Entity ID */
3980598e1a2SLisandro Dalcin   PetscInt dim;                 /* Dimension */
399de78e4feSLisandro Dalcin   double   bbox[6];             /* Bounding box */
400de78e4feSLisandro Dalcin   PetscInt numTags;             /* Size of tag array */
4017d5b9244SMatthew G. Knepley   int      tags[GMSH_MAX_TAGS]; /* Tag array */
402de78e4feSLisandro Dalcin } GmshEntity;
403de78e4feSLisandro Dalcin 
404de78e4feSLisandro Dalcin typedef struct {
405730356f6SLisandro Dalcin   GmshEntity *entity[4];
406730356f6SLisandro Dalcin   PetscHMapI  entityMap[4];
407730356f6SLisandro Dalcin } GmshEntities;
408730356f6SLisandro Dalcin 
4096497c311SBarry Smith static PetscErrorCode GmshEntitiesCreate(PetscCount count[4], GmshEntities **entities)
410d71ae5a4SJacob Faibussowitsch {
411730356f6SLisandro Dalcin   PetscFunctionBegin;
4129566063dSJacob Faibussowitsch   PetscCall(PetscNew(entities));
4136497c311SBarry Smith   for (PetscInt dim = 0; dim < 4; ++dim) {
4149566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(count[dim], &(*entities)->entity[dim]));
4159566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&(*entities)->entityMap[dim]));
416730356f6SLisandro Dalcin   }
4173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
418730356f6SLisandro Dalcin }
419730356f6SLisandro Dalcin 
420d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshEntitiesDestroy(GmshEntities **entities)
421d71ae5a4SJacob Faibussowitsch {
4220598e1a2SLisandro Dalcin   PetscInt dim;
4230598e1a2SLisandro Dalcin 
4240598e1a2SLisandro Dalcin   PetscFunctionBegin;
4253ba16761SJacob Faibussowitsch   if (!*entities) PetscFunctionReturn(PETSC_SUCCESS);
4260598e1a2SLisandro Dalcin   for (dim = 0; dim < 4; ++dim) {
4279566063dSJacob Faibussowitsch     PetscCall(PetscFree((*entities)->entity[dim]));
4289566063dSJacob Faibussowitsch     PetscCall(PetscHMapIDestroy(&(*entities)->entityMap[dim]));
4290598e1a2SLisandro Dalcin   }
430f4f49eeaSPierre Jolivet   PetscCall(PetscFree(*entities));
4313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4320598e1a2SLisandro Dalcin }
4330598e1a2SLisandro Dalcin 
434d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshEntitiesAdd(GmshEntities *entities, PetscInt index, PetscInt dim, PetscInt eid, GmshEntity **entity)
435d71ae5a4SJacob Faibussowitsch {
436730356f6SLisandro Dalcin   PetscFunctionBegin;
4379566063dSJacob Faibussowitsch   PetscCall(PetscHMapISet(entities->entityMap[dim], eid, index));
438730356f6SLisandro Dalcin   entities->entity[dim][index].dim = dim;
439730356f6SLisandro Dalcin   entities->entity[dim][index].id  = eid;
440730356f6SLisandro Dalcin   if (entity) *entity = &entities->entity[dim][index];
4413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
442730356f6SLisandro Dalcin }
443730356f6SLisandro Dalcin 
444d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshEntitiesGet(GmshEntities *entities, PetscInt dim, PetscInt eid, GmshEntity **entity)
445d71ae5a4SJacob Faibussowitsch {
446730356f6SLisandro Dalcin   PetscInt index;
447730356f6SLisandro Dalcin 
448730356f6SLisandro Dalcin   PetscFunctionBegin;
4499566063dSJacob Faibussowitsch   PetscCall(PetscHMapIGet(entities->entityMap[dim], eid, &index));
450730356f6SLisandro Dalcin   *entity = &entities->entity[dim][index];
4513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
452730356f6SLisandro Dalcin }
453730356f6SLisandro Dalcin 
4540598e1a2SLisandro Dalcin typedef struct {
4550598e1a2SLisandro Dalcin   PetscInt *id;  /* Node IDs */
4560598e1a2SLisandro Dalcin   double   *xyz; /* Coordinates */
45781a1af93SMatthew G. Knepley   PetscInt *tag; /* Physical tag */
4580598e1a2SLisandro Dalcin } GmshNodes;
4590598e1a2SLisandro Dalcin 
4606497c311SBarry Smith static PetscErrorCode GmshNodesCreate(PetscCount count, GmshNodes **nodes)
461d71ae5a4SJacob Faibussowitsch {
462730356f6SLisandro Dalcin   PetscFunctionBegin;
4639566063dSJacob Faibussowitsch   PetscCall(PetscNew(nodes));
4649566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(count * 1, &(*nodes)->id));
4659566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(count * 3, &(*nodes)->xyz));
4667d5b9244SMatthew G. Knepley   PetscCall(PetscMalloc1(count * GMSH_MAX_TAGS, &(*nodes)->tag));
4673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
468730356f6SLisandro Dalcin }
4690598e1a2SLisandro Dalcin 
470d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshNodesDestroy(GmshNodes **nodes)
471d71ae5a4SJacob Faibussowitsch {
4720598e1a2SLisandro Dalcin   PetscFunctionBegin;
4733ba16761SJacob Faibussowitsch   if (!*nodes) PetscFunctionReturn(PETSC_SUCCESS);
4749566063dSJacob Faibussowitsch   PetscCall(PetscFree((*nodes)->id));
4759566063dSJacob Faibussowitsch   PetscCall(PetscFree((*nodes)->xyz));
4769566063dSJacob Faibussowitsch   PetscCall(PetscFree((*nodes)->tag));
477f4f49eeaSPierre Jolivet   PetscCall(PetscFree(*nodes));
4783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
479730356f6SLisandro Dalcin }
480730356f6SLisandro Dalcin 
481730356f6SLisandro Dalcin typedef struct {
4820598e1a2SLisandro Dalcin   PetscInt  id;                  /* Element ID */
4830598e1a2SLisandro Dalcin   PetscInt  dim;                 /* Dimension */
484de78e4feSLisandro Dalcin   PetscInt  cellType;            /* Cell type */
4850598e1a2SLisandro Dalcin   PetscInt  numVerts;            /* Size of vertex array */
486de78e4feSLisandro Dalcin   PetscInt  numNodes;            /* Size of node array */
4870598e1a2SLisandro Dalcin   PetscInt *nodes;               /* Vertex/Node array */
48881a1af93SMatthew G. Knepley   PetscInt  numTags;             /* Size of physical tag array */
4897d5b9244SMatthew G. Knepley   int       tags[GMSH_MAX_TAGS]; /* Physical tag array */
490de78e4feSLisandro Dalcin } GmshElement;
491de78e4feSLisandro Dalcin 
4926497c311SBarry Smith static PetscErrorCode GmshElementsCreate(PetscCount count, GmshElement **elements)
493d71ae5a4SJacob Faibussowitsch {
4940598e1a2SLisandro Dalcin   PetscFunctionBegin;
4959566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(count, elements));
4963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4970598e1a2SLisandro Dalcin }
4980598e1a2SLisandro Dalcin 
499d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshElementsDestroy(GmshElement **elements)
500d71ae5a4SJacob Faibussowitsch {
5010598e1a2SLisandro Dalcin   PetscFunctionBegin;
5023ba16761SJacob Faibussowitsch   if (!*elements) PetscFunctionReturn(PETSC_SUCCESS);
5039566063dSJacob Faibussowitsch   PetscCall(PetscFree(*elements));
5043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5050598e1a2SLisandro Dalcin }
5060598e1a2SLisandro Dalcin 
5070598e1a2SLisandro Dalcin typedef struct {
5080598e1a2SLisandro Dalcin   PetscInt       dim;
509066ea43fSLisandro Dalcin   PetscInt       order;
5100598e1a2SLisandro Dalcin   GmshEntities  *entities;
5110598e1a2SLisandro Dalcin   PetscInt       numNodes;
5120598e1a2SLisandro Dalcin   GmshNodes     *nodelist;
5130598e1a2SLisandro Dalcin   PetscInt       numElems;
5140598e1a2SLisandro Dalcin   GmshElement   *elements;
5150598e1a2SLisandro Dalcin   PetscInt       numVerts;
5160598e1a2SLisandro Dalcin   PetscInt       numCells;
5170598e1a2SLisandro Dalcin   PetscInt      *periodMap;
5180598e1a2SLisandro Dalcin   PetscInt      *vertexMap;
5190598e1a2SLisandro Dalcin   PetscSegBuffer segbuf;
520a45dabc8SMatthew G. Knepley   PetscInt       numRegions;
52190d778b8SLisandro Dalcin   PetscInt      *regionDims;
522a45dabc8SMatthew G. Knepley   PetscInt      *regionTags;
523a45dabc8SMatthew G. Knepley   char         **regionNames;
5240598e1a2SLisandro Dalcin } GmshMesh;
5250598e1a2SLisandro Dalcin 
526d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshMeshCreate(GmshMesh **mesh)
527d71ae5a4SJacob Faibussowitsch {
5280598e1a2SLisandro Dalcin   PetscFunctionBegin;
5299566063dSJacob Faibussowitsch   PetscCall(PetscNew(mesh));
5309566063dSJacob Faibussowitsch   PetscCall(PetscSegBufferCreate(sizeof(PetscInt), 0, &(*mesh)->segbuf));
5313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5320598e1a2SLisandro Dalcin }
5330598e1a2SLisandro Dalcin 
534d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshMeshDestroy(GmshMesh **mesh)
535d71ae5a4SJacob Faibussowitsch {
536a45dabc8SMatthew G. Knepley   PetscInt r;
5370598e1a2SLisandro Dalcin 
5380598e1a2SLisandro Dalcin   PetscFunctionBegin;
5393ba16761SJacob Faibussowitsch   if (!*mesh) PetscFunctionReturn(PETSC_SUCCESS);
5409566063dSJacob Faibussowitsch   PetscCall(GmshEntitiesDestroy(&(*mesh)->entities));
5419566063dSJacob Faibussowitsch   PetscCall(GmshNodesDestroy(&(*mesh)->nodelist));
5429566063dSJacob Faibussowitsch   PetscCall(GmshElementsDestroy(&(*mesh)->elements));
5439566063dSJacob Faibussowitsch   PetscCall(PetscFree((*mesh)->periodMap));
5449566063dSJacob Faibussowitsch   PetscCall(PetscFree((*mesh)->vertexMap));
5459566063dSJacob Faibussowitsch   PetscCall(PetscSegBufferDestroy(&(*mesh)->segbuf));
5469566063dSJacob Faibussowitsch   for (r = 0; r < (*mesh)->numRegions; ++r) PetscCall(PetscFree((*mesh)->regionNames[r]));
54790d778b8SLisandro Dalcin   PetscCall(PetscFree3((*mesh)->regionDims, (*mesh)->regionTags, (*mesh)->regionNames));
548f4f49eeaSPierre Jolivet   PetscCall(PetscFree(*mesh));
5493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5500598e1a2SLisandro Dalcin }
5510598e1a2SLisandro Dalcin 
552d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadNodes_v22(GmshFile *gmsh, GmshMesh *mesh)
553d71ae5a4SJacob Faibussowitsch {
554698a79b9SLisandro Dalcin   PetscViewer viewer   = gmsh->viewer;
555698a79b9SLisandro Dalcin   PetscBool   byteSwap = gmsh->byteSwap;
556de78e4feSLisandro Dalcin   char        line[PETSC_MAX_PATH_LEN];
5577d5b9244SMatthew G. Knepley   int         n, t, num, nid, snum;
5580598e1a2SLisandro Dalcin   GmshNodes  *nodes;
559de78e4feSLisandro Dalcin 
560de78e4feSLisandro Dalcin   PetscFunctionBegin;
5619566063dSJacob Faibussowitsch   PetscCall(PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING));
562698a79b9SLisandro Dalcin   snum = sscanf(line, "%d", &num);
56308401ef6SPierre Jolivet   PetscCheck(snum == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
5649566063dSJacob Faibussowitsch   PetscCall(GmshNodesCreate(num, &nodes));
5650598e1a2SLisandro Dalcin   mesh->numNodes = num;
5660598e1a2SLisandro Dalcin   mesh->nodelist = nodes;
5670598e1a2SLisandro Dalcin   for (n = 0; n < num; ++n) {
5680598e1a2SLisandro Dalcin     double *xyz = nodes->xyz + n * 3;
5699566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, &nid, 1, NULL, PETSC_ENUM));
5709566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, xyz, 3, NULL, PETSC_DOUBLE));
5719566063dSJacob Faibussowitsch     if (byteSwap) PetscCall(PetscByteSwap(&nid, PETSC_ENUM, 1));
5729566063dSJacob Faibussowitsch     if (byteSwap) PetscCall(PetscByteSwap(xyz, PETSC_DOUBLE, 3));
5730598e1a2SLisandro Dalcin     nodes->id[n] = nid;
5747d5b9244SMatthew G. Knepley     for (t = 0; t < GMSH_MAX_TAGS; ++t) nodes->tag[n * GMSH_MAX_TAGS + t] = -1;
57511c56cb0SLisandro Dalcin   }
5763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
57711c56cb0SLisandro Dalcin }
57811c56cb0SLisandro Dalcin 
579de78e4feSLisandro Dalcin /* Gmsh elements can be of any dimension/co-dimension, so we need to traverse the
580de78e4feSLisandro Dalcin    file contents multiple times to figure out the true number of cells and facets
581de78e4feSLisandro Dalcin    in the given mesh. To make this more efficient we read the file contents only
582de78e4feSLisandro Dalcin    once and store them in memory, while determining the true number of cells. */
583d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadElements_v22(GmshFile *gmsh, GmshMesh *mesh)
584d71ae5a4SJacob Faibussowitsch {
585698a79b9SLisandro Dalcin   PetscViewer  viewer   = gmsh->viewer;
586698a79b9SLisandro Dalcin   PetscBool    binary   = gmsh->binary;
587698a79b9SLisandro Dalcin   PetscBool    byteSwap = gmsh->byteSwap;
588de78e4feSLisandro Dalcin   char         line[PETSC_MAX_PATH_LEN];
5890598e1a2SLisandro Dalcin   int          i, c, p, num, ibuf[1 + 4 + 1000], snum;
5900598e1a2SLisandro Dalcin   int          cellType, numElem, numVerts, numNodes, numTags;
591df032b82SMatthew G. Knepley   GmshElement *elements;
5920598e1a2SLisandro Dalcin   PetscInt    *nodeMap = gmsh->nodeMap;
593df032b82SMatthew G. Knepley 
594df032b82SMatthew G. Knepley   PetscFunctionBegin;
5959566063dSJacob Faibussowitsch   PetscCall(PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING));
596698a79b9SLisandro Dalcin   snum = sscanf(line, "%d", &num);
59708401ef6SPierre Jolivet   PetscCheck(snum == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
5989566063dSJacob Faibussowitsch   PetscCall(GmshElementsCreate(num, &elements));
5990598e1a2SLisandro Dalcin   mesh->numElems = num;
6000598e1a2SLisandro Dalcin   mesh->elements = elements;
601698a79b9SLisandro Dalcin   for (c = 0; c < num;) {
6029566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, ibuf, 3, NULL, PETSC_ENUM));
6039566063dSJacob Faibussowitsch     if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, 3));
6040598e1a2SLisandro Dalcin 
6050598e1a2SLisandro Dalcin     cellType = binary ? ibuf[0] : ibuf[1];
6060598e1a2SLisandro Dalcin     numElem  = binary ? ibuf[1] : 1;
607df032b82SMatthew G. Knepley     numTags  = ibuf[2];
6080598e1a2SLisandro Dalcin 
6099566063dSJacob Faibussowitsch     PetscCall(GmshCellTypeCheck(cellType));
6100598e1a2SLisandro Dalcin     numVerts = GmshCellMap[cellType].numVerts;
6110598e1a2SLisandro Dalcin     numNodes = GmshCellMap[cellType].numNodes;
6120598e1a2SLisandro Dalcin 
613df032b82SMatthew G. Knepley     for (i = 0; i < numElem; ++i, ++c) {
6140598e1a2SLisandro Dalcin       GmshElement *element = elements + c;
6150598e1a2SLisandro Dalcin       const int    off = binary ? 0 : 1, nint = 1 + numTags + numNodes - off;
6160598e1a2SLisandro Dalcin       const int   *id = ibuf, *nodes = ibuf + 1 + numTags, *tags = ibuf + 1;
6179566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, ibuf + off, nint, NULL, PETSC_ENUM));
6189566063dSJacob Faibussowitsch       if (byteSwap) PetscCall(PetscByteSwap(ibuf + off, PETSC_ENUM, nint));
6190598e1a2SLisandro Dalcin       element->id       = id[0];
6200598e1a2SLisandro Dalcin       element->dim      = GmshCellMap[cellType].dim;
6210598e1a2SLisandro Dalcin       element->cellType = cellType;
6220598e1a2SLisandro Dalcin       element->numVerts = numVerts;
6230598e1a2SLisandro Dalcin       element->numNodes = numNodes;
6247d5b9244SMatthew G. Knepley       element->numTags  = PetscMin(numTags, GMSH_MAX_TAGS);
6259566063dSJacob Faibussowitsch       PetscCall(PetscSegBufferGet(mesh->segbuf, (size_t)element->numNodes, &element->nodes));
6260598e1a2SLisandro Dalcin       for (p = 0; p < element->numNodes; p++) element->nodes[p] = nodeMap[nodes[p]];
6270598e1a2SLisandro Dalcin       for (p = 0; p < element->numTags; p++) element->tags[p] = tags[p];
628df032b82SMatthew G. Knepley     }
629df032b82SMatthew G. Knepley   }
6303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
631df032b82SMatthew G. Knepley }
6327d282ae0SMichael Lange 
633de78e4feSLisandro Dalcin /*
634de78e4feSLisandro Dalcin $Entities
635de78e4feSLisandro Dalcin   numPoints(unsigned long) numCurves(unsigned long)
636de78e4feSLisandro Dalcin     numSurfaces(unsigned long) numVolumes(unsigned long)
637de78e4feSLisandro Dalcin   // points
638de78e4feSLisandro Dalcin   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
639de78e4feSLisandro Dalcin     boxMaxX(double) boxMaxY(double) boxMaxZ(double)
640de78e4feSLisandro Dalcin     numPhysicals(unsigned long) phyisicalTag[...](int)
641de78e4feSLisandro Dalcin   ...
642de78e4feSLisandro Dalcin   // curves
643de78e4feSLisandro Dalcin   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
644de78e4feSLisandro Dalcin      boxMaxX(double) boxMaxY(double) boxMaxZ(double)
645de78e4feSLisandro Dalcin      numPhysicals(unsigned long) physicalTag[...](int)
646de78e4feSLisandro Dalcin      numBREPVert(unsigned long) tagBREPVert[...](int)
647de78e4feSLisandro Dalcin   ...
648de78e4feSLisandro Dalcin   // surfaces
649de78e4feSLisandro Dalcin   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
650de78e4feSLisandro Dalcin     boxMaxX(double) boxMaxY(double) boxMaxZ(double)
651de78e4feSLisandro Dalcin     numPhysicals(unsigned long) physicalTag[...](int)
652de78e4feSLisandro Dalcin     numBREPCurve(unsigned long) tagBREPCurve[...](int)
653de78e4feSLisandro Dalcin   ...
654de78e4feSLisandro Dalcin   // volumes
655de78e4feSLisandro Dalcin   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
656de78e4feSLisandro Dalcin     boxMaxX(double) boxMaxY(double) boxMaxZ(double)
657de78e4feSLisandro Dalcin     numPhysicals(unsigned long) physicalTag[...](int)
658de78e4feSLisandro Dalcin     numBREPSurfaces(unsigned long) tagBREPSurfaces[...](int)
659de78e4feSLisandro Dalcin   ...
660de78e4feSLisandro Dalcin $EndEntities
661de78e4feSLisandro Dalcin */
662d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadEntities_v40(GmshFile *gmsh, GmshMesh *mesh)
663d71ae5a4SJacob Faibussowitsch {
664698a79b9SLisandro Dalcin   PetscViewer viewer   = gmsh->viewer;
665698a79b9SLisandro Dalcin   PetscBool   byteSwap = gmsh->byteSwap;
6666497c311SBarry Smith   long        lnum, lbuf[4];
667730356f6SLisandro Dalcin   int         dim, eid, numTags, *ibuf, t;
6686497c311SBarry Smith   PetscCount  index, count[4];
6696497c311SBarry Smith   PetscInt    i, num;
670a5ba3d71SLisandro Dalcin   GmshEntity *entity = NULL;
671de78e4feSLisandro Dalcin 
672de78e4feSLisandro Dalcin   PetscFunctionBegin;
6739566063dSJacob Faibussowitsch   PetscCall(PetscViewerRead(viewer, lbuf, 4, NULL, PETSC_LONG));
6749566063dSJacob Faibussowitsch   if (byteSwap) PetscCall(PetscByteSwap(lbuf, PETSC_LONG, 4));
6756497c311SBarry Smith   for (i = 0; i < 4; ++i) count[i] = (PetscCount)lbuf[i];
6769566063dSJacob Faibussowitsch   PetscCall(GmshEntitiesCreate(count, &mesh->entities));
677de78e4feSLisandro Dalcin   for (dim = 0; dim < 4; ++dim) {
678730356f6SLisandro Dalcin     for (index = 0; index < count[dim]; ++index) {
6799566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, &eid, 1, NULL, PETSC_ENUM));
6809566063dSJacob Faibussowitsch       if (byteSwap) PetscCall(PetscByteSwap(&eid, PETSC_ENUM, 1));
6819566063dSJacob Faibussowitsch       PetscCall(GmshEntitiesAdd(mesh->entities, (PetscInt)index, dim, eid, &entity));
6829566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, entity->bbox, 6, NULL, PETSC_DOUBLE));
6839566063dSJacob Faibussowitsch       if (byteSwap) PetscCall(PetscByteSwap(entity->bbox, PETSC_DOUBLE, 6));
6846497c311SBarry Smith       PetscCall(PetscViewerRead(viewer, &lnum, 1, NULL, PETSC_LONG));
6856497c311SBarry Smith       if (byteSwap) PetscCall(PetscByteSwap(&lnum, PETSC_LONG, 1));
6866497c311SBarry Smith       PetscCall(PetscIntCast(lnum, &num));
6879566063dSJacob Faibussowitsch       PetscCall(GmshBufferGet(gmsh, num, sizeof(int), &ibuf));
6889566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, ibuf, num, NULL, PETSC_ENUM));
6899566063dSJacob Faibussowitsch       if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, num));
6907d5b9244SMatthew G. Knepley       entity->numTags = numTags = (int)PetscMin(num, GMSH_MAX_TAGS);
691de78e4feSLisandro Dalcin       for (t = 0; t < numTags; ++t) entity->tags[t] = ibuf[t];
692de78e4feSLisandro Dalcin       if (dim == 0) continue;
6936497c311SBarry Smith       PetscCall(PetscViewerRead(viewer, &lnum, 1, NULL, PETSC_LONG));
6946497c311SBarry Smith       if (byteSwap) PetscCall(PetscByteSwap(&lnum, PETSC_LONG, 1));
6956497c311SBarry Smith       PetscCall(GmshBufferGet(gmsh, lnum, sizeof(int), &ibuf));
6966497c311SBarry Smith       PetscCall(PetscIntCast(lnum, &num));
6979566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, ibuf, num, NULL, PETSC_ENUM));
6989566063dSJacob Faibussowitsch       if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, num));
699de78e4feSLisandro Dalcin     }
700de78e4feSLisandro Dalcin   }
7013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
702de78e4feSLisandro Dalcin }
703de78e4feSLisandro Dalcin 
704de78e4feSLisandro Dalcin /*
705de78e4feSLisandro Dalcin $Nodes
706de78e4feSLisandro Dalcin   numEntityBlocks(unsigned long) numNodes(unsigned long)
707de78e4feSLisandro Dalcin   tagEntity(int) dimEntity(int) typeNode(int) numNodes(unsigned long)
708de78e4feSLisandro Dalcin     tag(int) x(double) y(double) z(double)
709de78e4feSLisandro Dalcin     ...
710de78e4feSLisandro Dalcin   ...
711de78e4feSLisandro Dalcin $EndNodes
712de78e4feSLisandro Dalcin */
713d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadNodes_v40(GmshFile *gmsh, GmshMesh *mesh)
714d71ae5a4SJacob Faibussowitsch {
715698a79b9SLisandro Dalcin   PetscViewer viewer   = gmsh->viewer;
716698a79b9SLisandro Dalcin   PetscBool   byteSwap = gmsh->byteSwap;
7177d5b9244SMatthew G. Knepley   long        block, node, n, t, numEntityBlocks, numTotalNodes, numNodes;
718de78e4feSLisandro Dalcin   int         info[3], nid;
7190598e1a2SLisandro Dalcin   GmshNodes  *nodes;
720de78e4feSLisandro Dalcin 
721de78e4feSLisandro Dalcin   PetscFunctionBegin;
7229566063dSJacob Faibussowitsch   PetscCall(PetscViewerRead(viewer, &numEntityBlocks, 1, NULL, PETSC_LONG));
7239566063dSJacob Faibussowitsch   if (byteSwap) PetscCall(PetscByteSwap(&numEntityBlocks, PETSC_LONG, 1));
7249566063dSJacob Faibussowitsch   PetscCall(PetscViewerRead(viewer, &numTotalNodes, 1, NULL, PETSC_LONG));
7259566063dSJacob Faibussowitsch   if (byteSwap) PetscCall(PetscByteSwap(&numTotalNodes, PETSC_LONG, 1));
7269566063dSJacob Faibussowitsch   PetscCall(GmshNodesCreate(numTotalNodes, &nodes));
7276497c311SBarry Smith   PetscCall(PetscIntCast(numTotalNodes, &mesh->numNodes));
7280598e1a2SLisandro Dalcin   mesh->nodelist = nodes;
7290598e1a2SLisandro Dalcin   for (n = 0, block = 0; block < numEntityBlocks; ++block) {
7309566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, info, 3, NULL, PETSC_ENUM));
7319566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, &numNodes, 1, NULL, PETSC_LONG));
7329566063dSJacob Faibussowitsch     if (byteSwap) PetscCall(PetscByteSwap(&numNodes, PETSC_LONG, 1));
733698a79b9SLisandro Dalcin     if (gmsh->binary) {
734277f51e8SBarry Smith       size_t   nbytes = sizeof(int) + 3 * sizeof(double);
735da81f932SPierre Jolivet       char    *cbuf   = NULL; /* dummy value to prevent warning from compiler about possible uninitialized value */
7366497c311SBarry Smith       PetscInt icnt;
7376497c311SBarry Smith 
7389566063dSJacob Faibussowitsch       PetscCall(GmshBufferGet(gmsh, numNodes, nbytes, &cbuf));
7396497c311SBarry Smith       PetscCall(PetscIntCast(numNodes * nbytes, &icnt));
7406497c311SBarry Smith       PetscCall(PetscViewerRead(viewer, cbuf, icnt, NULL, PETSC_CHAR));
7410598e1a2SLisandro Dalcin       for (node = 0; node < numNodes; ++node, ++n) {
742de78e4feSLisandro Dalcin         char   *cnid = cbuf + node * nbytes, *cxyz = cnid + sizeof(int);
7430598e1a2SLisandro Dalcin         double *xyz = nodes->xyz + n * 3;
7446497c311SBarry Smith 
7459566063dSJacob Faibussowitsch         if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(cnid, PETSC_ENUM, 1));
7469566063dSJacob Faibussowitsch         if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(cxyz, PETSC_DOUBLE, 3));
7479566063dSJacob Faibussowitsch         PetscCall(PetscMemcpy(&nid, cnid, sizeof(int)));
7489566063dSJacob Faibussowitsch         PetscCall(PetscMemcpy(xyz, cxyz, 3 * sizeof(double)));
7499566063dSJacob Faibussowitsch         if (byteSwap) PetscCall(PetscByteSwap(&nid, PETSC_ENUM, 1));
7509566063dSJacob Faibussowitsch         if (byteSwap) PetscCall(PetscByteSwap(xyz, PETSC_DOUBLE, 3));
7510598e1a2SLisandro Dalcin         nodes->id[n] = nid;
7527d5b9244SMatthew G. Knepley         for (t = 0; t < GMSH_MAX_TAGS; ++t) nodes->tag[n * GMSH_MAX_TAGS + t] = -1;
753de78e4feSLisandro Dalcin       }
754de78e4feSLisandro Dalcin     } else {
7550598e1a2SLisandro Dalcin       for (node = 0; node < numNodes; ++node, ++n) {
7560598e1a2SLisandro Dalcin         double *xyz = nodes->xyz + n * 3;
7576497c311SBarry Smith 
7589566063dSJacob Faibussowitsch         PetscCall(PetscViewerRead(viewer, &nid, 1, NULL, PETSC_ENUM));
7599566063dSJacob Faibussowitsch         PetscCall(PetscViewerRead(viewer, xyz, 3, NULL, PETSC_DOUBLE));
7609566063dSJacob Faibussowitsch         if (byteSwap) PetscCall(PetscByteSwap(&nid, PETSC_ENUM, 1));
7619566063dSJacob Faibussowitsch         if (byteSwap) PetscCall(PetscByteSwap(xyz, PETSC_DOUBLE, 3));
7620598e1a2SLisandro Dalcin         nodes->id[n] = nid;
7637d5b9244SMatthew G. Knepley         for (t = 0; t < GMSH_MAX_TAGS; ++t) nodes->tag[n * GMSH_MAX_TAGS + t] = -1;
764de78e4feSLisandro Dalcin       }
765de78e4feSLisandro Dalcin     }
766de78e4feSLisandro Dalcin   }
7673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
768de78e4feSLisandro Dalcin }
769de78e4feSLisandro Dalcin 
770de78e4feSLisandro Dalcin /*
771de78e4feSLisandro Dalcin $Elements
772de78e4feSLisandro Dalcin   numEntityBlocks(unsigned long) numElements(unsigned long)
773de78e4feSLisandro Dalcin   tagEntity(int) dimEntity(int) typeEle(int) numElements(unsigned long)
774de78e4feSLisandro Dalcin     tag(int) numVert[...](int)
775de78e4feSLisandro Dalcin     ...
776de78e4feSLisandro Dalcin   ...
777de78e4feSLisandro Dalcin $EndElements
778de78e4feSLisandro Dalcin */
779d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadElements_v40(GmshFile *gmsh, GmshMesh *mesh)
780d71ae5a4SJacob Faibussowitsch {
781698a79b9SLisandro Dalcin   PetscViewer  viewer   = gmsh->viewer;
782698a79b9SLisandro Dalcin   PetscBool    byteSwap = gmsh->byteSwap;
783de78e4feSLisandro Dalcin   long         c, block, numEntityBlocks, numTotalElements, elem, numElements;
784de78e4feSLisandro Dalcin   int          p, info[3], *ibuf = NULL;
7850598e1a2SLisandro Dalcin   int          eid, dim, cellType, numVerts, numNodes, numTags;
786a5ba3d71SLisandro Dalcin   GmshEntity  *entity = NULL;
787de78e4feSLisandro Dalcin   GmshElement *elements;
7886497c311SBarry Smith   PetscInt    *nodeMap = gmsh->nodeMap, icnt;
789de78e4feSLisandro Dalcin 
790de78e4feSLisandro Dalcin   PetscFunctionBegin;
7919566063dSJacob Faibussowitsch   PetscCall(PetscViewerRead(viewer, &numEntityBlocks, 1, NULL, PETSC_LONG));
7929566063dSJacob Faibussowitsch   if (byteSwap) PetscCall(PetscByteSwap(&numEntityBlocks, PETSC_LONG, 1));
7939566063dSJacob Faibussowitsch   PetscCall(PetscViewerRead(viewer, &numTotalElements, 1, NULL, PETSC_LONG));
7949566063dSJacob Faibussowitsch   if (byteSwap) PetscCall(PetscByteSwap(&numTotalElements, PETSC_LONG, 1));
7959566063dSJacob Faibussowitsch   PetscCall(GmshElementsCreate(numTotalElements, &elements));
7966497c311SBarry Smith   PetscCall(PetscIntCast(numTotalElements, &mesh->numElems));
7970598e1a2SLisandro Dalcin   mesh->elements = elements;
798de78e4feSLisandro Dalcin   for (c = 0, block = 0; block < numEntityBlocks; ++block) {
7999566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, info, 3, NULL, PETSC_ENUM));
8009566063dSJacob Faibussowitsch     if (byteSwap) PetscCall(PetscByteSwap(info, PETSC_ENUM, 3));
8019371c9d4SSatish Balay     eid      = info[0];
8029371c9d4SSatish Balay     dim      = info[1];
8039371c9d4SSatish Balay     cellType = info[2];
8049566063dSJacob Faibussowitsch     PetscCall(GmshEntitiesGet(mesh->entities, dim, eid, &entity));
8059566063dSJacob Faibussowitsch     PetscCall(GmshCellTypeCheck(cellType));
8060598e1a2SLisandro Dalcin     numVerts = GmshCellMap[cellType].numVerts;
8070598e1a2SLisandro Dalcin     numNodes = GmshCellMap[cellType].numNodes;
8086497c311SBarry Smith     numTags  = (int)entity->numTags;
8099566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, &numElements, 1, NULL, PETSC_LONG));
8109566063dSJacob Faibussowitsch     if (byteSwap) PetscCall(PetscByteSwap(&numElements, PETSC_LONG, 1));
8119566063dSJacob Faibussowitsch     PetscCall(GmshBufferGet(gmsh, (1 + numNodes) * numElements, sizeof(int), &ibuf));
8126497c311SBarry Smith     PetscCall(PetscIntCast((1 + numNodes) * numElements, &icnt));
8136497c311SBarry Smith     PetscCall(PetscViewerRead(viewer, ibuf, icnt, NULL, PETSC_ENUM));
8149566063dSJacob Faibussowitsch     if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, (1 + numNodes) * numElements));
815de78e4feSLisandro Dalcin     for (elem = 0; elem < numElements; ++elem, ++c) {
816de78e4feSLisandro Dalcin       GmshElement *element = elements + c;
8170598e1a2SLisandro Dalcin       const int   *id = ibuf + elem * (1 + numNodes), *nodes = id + 1;
8180598e1a2SLisandro Dalcin       element->id       = id[0];
819de78e4feSLisandro Dalcin       element->dim      = dim;
820de78e4feSLisandro Dalcin       element->cellType = cellType;
8210598e1a2SLisandro Dalcin       element->numVerts = numVerts;
822de78e4feSLisandro Dalcin       element->numNodes = numNodes;
823de78e4feSLisandro Dalcin       element->numTags  = numTags;
8249566063dSJacob Faibussowitsch       PetscCall(PetscSegBufferGet(mesh->segbuf, (size_t)element->numNodes, &element->nodes));
8250598e1a2SLisandro Dalcin       for (p = 0; p < element->numNodes; p++) element->nodes[p] = nodeMap[nodes[p]];
8260598e1a2SLisandro Dalcin       for (p = 0; p < element->numTags; p++) element->tags[p] = entity->tags[p];
827de78e4feSLisandro Dalcin     }
828de78e4feSLisandro Dalcin   }
8293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
830698a79b9SLisandro Dalcin }
831698a79b9SLisandro Dalcin 
832d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadPeriodic_v40(GmshFile *gmsh, PetscInt periodicMap[])
833d71ae5a4SJacob Faibussowitsch {
834698a79b9SLisandro Dalcin   PetscViewer viewer     = gmsh->viewer;
835698a79b9SLisandro Dalcin   int         fileFormat = gmsh->fileFormat;
836698a79b9SLisandro Dalcin   PetscBool   binary     = gmsh->binary;
837698a79b9SLisandro Dalcin   PetscBool   byteSwap   = gmsh->byteSwap;
838698a79b9SLisandro Dalcin   int         numPeriodic, snum, i;
839698a79b9SLisandro Dalcin   char        line[PETSC_MAX_PATH_LEN];
8400598e1a2SLisandro Dalcin   PetscInt   *nodeMap = gmsh->nodeMap;
841698a79b9SLisandro Dalcin 
842698a79b9SLisandro Dalcin   PetscFunctionBegin;
843698a79b9SLisandro Dalcin   if (fileFormat == 22 || !binary) {
8449566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING));
845698a79b9SLisandro Dalcin     snum = sscanf(line, "%d", &numPeriodic);
84608401ef6SPierre Jolivet     PetscCheck(snum == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
847698a79b9SLisandro Dalcin   } else {
8489566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, &numPeriodic, 1, NULL, PETSC_ENUM));
8499566063dSJacob Faibussowitsch     if (byteSwap) PetscCall(PetscByteSwap(&numPeriodic, PETSC_ENUM, 1));
850698a79b9SLisandro Dalcin   }
851698a79b9SLisandro Dalcin   for (i = 0; i < numPeriodic; i++) {
8529dddd249SSatish Balay     int    ibuf[3], correspondingDim = -1, correspondingTag = -1, primaryTag = -1, correspondingNode, primaryNode;
853698a79b9SLisandro Dalcin     long   j, nNodes;
854698a79b9SLisandro Dalcin     double affine[16];
855698a79b9SLisandro Dalcin 
856698a79b9SLisandro Dalcin     if (fileFormat == 22 || !binary) {
8579566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, line, 3, NULL, PETSC_STRING));
8589dddd249SSatish Balay       snum = sscanf(line, "%d %d %d", &correspondingDim, &correspondingTag, &primaryTag);
85908401ef6SPierre Jolivet       PetscCheck(snum == 3, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
860698a79b9SLisandro Dalcin     } else {
8619566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, ibuf, 3, NULL, PETSC_ENUM));
8629566063dSJacob Faibussowitsch       if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, 3));
8639371c9d4SSatish Balay       correspondingDim = ibuf[0];
8649371c9d4SSatish Balay       correspondingTag = ibuf[1];
8659371c9d4SSatish Balay       primaryTag       = ibuf[2];
866698a79b9SLisandro Dalcin     }
8679371c9d4SSatish Balay     (void)correspondingDim;
8689371c9d4SSatish Balay     (void)correspondingTag;
8699371c9d4SSatish Balay     (void)primaryTag; /* unused */
870698a79b9SLisandro Dalcin 
871698a79b9SLisandro Dalcin     if (fileFormat == 22 || !binary) {
8729566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING));
873698a79b9SLisandro Dalcin       snum = sscanf(line, "%ld", &nNodes);
8744c500f23SPierre Jolivet       if (snum != 1) { /* discard transformation and try again */
8759566063dSJacob Faibussowitsch         PetscCall(PetscViewerRead(viewer, line, -PETSC_MAX_PATH_LEN, NULL, PETSC_STRING));
8769566063dSJacob Faibussowitsch         PetscCall(PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING));
877698a79b9SLisandro Dalcin         snum = sscanf(line, "%ld", &nNodes);
87808401ef6SPierre Jolivet         PetscCheck(snum == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
879698a79b9SLisandro Dalcin       }
880698a79b9SLisandro Dalcin     } else {
8819566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, &nNodes, 1, NULL, PETSC_LONG));
8829566063dSJacob Faibussowitsch       if (byteSwap) PetscCall(PetscByteSwap(&nNodes, PETSC_LONG, 1));
8834c500f23SPierre Jolivet       if (nNodes == -1) { /* discard transformation and try again */
8849566063dSJacob Faibussowitsch         PetscCall(PetscViewerRead(viewer, affine, 16, NULL, PETSC_DOUBLE));
8859566063dSJacob Faibussowitsch         PetscCall(PetscViewerRead(viewer, &nNodes, 1, NULL, PETSC_LONG));
8869566063dSJacob Faibussowitsch         if (byteSwap) PetscCall(PetscByteSwap(&nNodes, PETSC_LONG, 1));
887698a79b9SLisandro Dalcin       }
888698a79b9SLisandro Dalcin     }
889698a79b9SLisandro Dalcin 
890698a79b9SLisandro Dalcin     for (j = 0; j < nNodes; j++) {
891698a79b9SLisandro Dalcin       if (fileFormat == 22 || !binary) {
8929566063dSJacob Faibussowitsch         PetscCall(PetscViewerRead(viewer, line, 2, NULL, PETSC_STRING));
8939dddd249SSatish Balay         snum = sscanf(line, "%d %d", &correspondingNode, &primaryNode);
89408401ef6SPierre Jolivet         PetscCheck(snum == 2, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
895698a79b9SLisandro Dalcin       } else {
8969566063dSJacob Faibussowitsch         PetscCall(PetscViewerRead(viewer, ibuf, 2, NULL, PETSC_ENUM));
8979566063dSJacob Faibussowitsch         if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, 2));
8989371c9d4SSatish Balay         correspondingNode = ibuf[0];
8999371c9d4SSatish Balay         primaryNode       = ibuf[1];
900698a79b9SLisandro Dalcin       }
9019dddd249SSatish Balay       correspondingNode              = (int)nodeMap[correspondingNode];
9029dddd249SSatish Balay       primaryNode                    = (int)nodeMap[primaryNode];
9039dddd249SSatish Balay       periodicMap[correspondingNode] = primaryNode;
904698a79b9SLisandro Dalcin     }
905698a79b9SLisandro Dalcin   }
9063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
907698a79b9SLisandro Dalcin }
908698a79b9SLisandro Dalcin 
9090598e1a2SLisandro Dalcin /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
910698a79b9SLisandro Dalcin $Entities
911698a79b9SLisandro Dalcin   numPoints(size_t) numCurves(size_t)
912698a79b9SLisandro Dalcin     numSurfaces(size_t) numVolumes(size_t)
913698a79b9SLisandro Dalcin   pointTag(int) X(double) Y(double) Z(double)
914698a79b9SLisandro Dalcin     numPhysicalTags(size_t) physicalTag(int) ...
915698a79b9SLisandro Dalcin   ...
916698a79b9SLisandro Dalcin   curveTag(int) minX(double) minY(double) minZ(double)
917698a79b9SLisandro Dalcin     maxX(double) maxY(double) maxZ(double)
918698a79b9SLisandro Dalcin     numPhysicalTags(size_t) physicalTag(int) ...
919698a79b9SLisandro Dalcin     numBoundingPoints(size_t) pointTag(int) ...
920698a79b9SLisandro Dalcin   ...
921698a79b9SLisandro Dalcin   surfaceTag(int) minX(double) minY(double) minZ(double)
922698a79b9SLisandro Dalcin     maxX(double) maxY(double) maxZ(double)
923698a79b9SLisandro Dalcin     numPhysicalTags(size_t) physicalTag(int) ...
924698a79b9SLisandro Dalcin     numBoundingCurves(size_t) curveTag(int) ...
925698a79b9SLisandro Dalcin   ...
926698a79b9SLisandro Dalcin   volumeTag(int) minX(double) minY(double) minZ(double)
927698a79b9SLisandro Dalcin     maxX(double) maxY(double) maxZ(double)
928698a79b9SLisandro Dalcin     numPhysicalTags(size_t) physicalTag(int) ...
929698a79b9SLisandro Dalcin     numBoundngSurfaces(size_t) surfaceTag(int) ...
930698a79b9SLisandro Dalcin   ...
931698a79b9SLisandro Dalcin $EndEntities
932698a79b9SLisandro Dalcin */
933d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadEntities_v41(GmshFile *gmsh, GmshMesh *mesh)
934d71ae5a4SJacob Faibussowitsch {
9356497c311SBarry Smith   PetscCount  count[4], index, numTags;
936698a79b9SLisandro Dalcin   int         dim, eid, *tags = NULL;
937698a79b9SLisandro Dalcin   GmshEntity *entity = NULL;
938698a79b9SLisandro Dalcin 
939698a79b9SLisandro Dalcin   PetscFunctionBegin;
9406497c311SBarry Smith   PetscCall(GmshReadPetscCount(gmsh, count, 4));
9419566063dSJacob Faibussowitsch   PetscCall(GmshEntitiesCreate(count, &mesh->entities));
942698a79b9SLisandro Dalcin   for (dim = 0; dim < 4; ++dim) {
943698a79b9SLisandro Dalcin     for (index = 0; index < count[dim]; ++index) {
9449566063dSJacob Faibussowitsch       PetscCall(GmshReadInt(gmsh, &eid, 1));
9459566063dSJacob Faibussowitsch       PetscCall(GmshEntitiesAdd(mesh->entities, (PetscInt)index, dim, eid, &entity));
9469566063dSJacob Faibussowitsch       PetscCall(GmshReadDouble(gmsh, entity->bbox, (dim == 0) ? 3 : 6));
9476497c311SBarry Smith       PetscCall(GmshReadPetscCount(gmsh, &numTags, 1));
9489566063dSJacob Faibussowitsch       PetscCall(GmshBufferGet(gmsh, numTags, sizeof(int), &tags));
9499566063dSJacob Faibussowitsch       PetscCall(GmshReadInt(gmsh, tags, numTags));
9506497c311SBarry Smith       PetscCheck(numTags <= GMSH_MAX_TAGS, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "PETSc currently supports up to %" PetscInt_FMT " tags per entity, not %" PetscCount_FMT, (PetscInt)GMSH_MAX_TAGS, numTags);
9516497c311SBarry Smith       PetscCall(PetscIntCast(numTags, &entity->numTags));
9526497c311SBarry Smith       for (PetscInt i = 0; i < entity->numTags; ++i) entity->tags[i] = tags[i];
953698a79b9SLisandro Dalcin       if (dim == 0) continue;
9546497c311SBarry Smith       PetscCall(GmshReadPetscCount(gmsh, &numTags, 1));
9559566063dSJacob Faibussowitsch       PetscCall(GmshBufferGet(gmsh, numTags, sizeof(int), &tags));
9569566063dSJacob Faibussowitsch       PetscCall(GmshReadInt(gmsh, tags, numTags));
95781a1af93SMatthew G. Knepley       /* Currently, we do not save the ids for the bounding entities */
958698a79b9SLisandro Dalcin     }
959698a79b9SLisandro Dalcin   }
9603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
961698a79b9SLisandro Dalcin }
962698a79b9SLisandro Dalcin 
96333a088b6SMatthew G. Knepley /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
964698a79b9SLisandro Dalcin $Nodes
965698a79b9SLisandro Dalcin   numEntityBlocks(size_t) numNodes(size_t)
966698a79b9SLisandro Dalcin     minNodeTag(size_t) maxNodeTag(size_t)
967698a79b9SLisandro Dalcin   entityDim(int) entityTag(int) parametric(int; 0 or 1) numNodesBlock(size_t)
968698a79b9SLisandro Dalcin     nodeTag(size_t)
969698a79b9SLisandro Dalcin     ...
970698a79b9SLisandro Dalcin     x(double) y(double) z(double)
971698a79b9SLisandro Dalcin        < u(double; if parametric and entityDim = 1 or entityDim = 2) >
972698a79b9SLisandro Dalcin        < v(double; if parametric and entityDim = 2) >
973698a79b9SLisandro Dalcin     ...
974698a79b9SLisandro Dalcin   ...
975698a79b9SLisandro Dalcin $EndNodes
976698a79b9SLisandro Dalcin */
977d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadNodes_v41(GmshFile *gmsh, GmshMesh *mesh)
978d71ae5a4SJacob Faibussowitsch {
97981a1af93SMatthew G. Knepley   int         info[3], dim, eid, parametric;
9806497c311SBarry Smith   PetscCount  sizes[4], numEntityBlocks, numNodes, numNodesBlock = 0;
9816497c311SBarry Smith   PetscInt    numTags;
98281a1af93SMatthew G. Knepley   GmshEntity *entity = NULL;
9830598e1a2SLisandro Dalcin   GmshNodes  *nodes;
984698a79b9SLisandro Dalcin 
985698a79b9SLisandro Dalcin   PetscFunctionBegin;
9866497c311SBarry Smith   PetscCall(GmshReadPetscCount(gmsh, sizes, 4));
9879371c9d4SSatish Balay   numEntityBlocks = sizes[0];
9889371c9d4SSatish Balay   numNodes        = sizes[1];
9899566063dSJacob Faibussowitsch   PetscCall(GmshNodesCreate(numNodes, &nodes));
9906497c311SBarry Smith   PetscCall(PetscIntCast(numNodes, &mesh->numNodes));
9910598e1a2SLisandro Dalcin   mesh->nodelist = nodes;
9926497c311SBarry Smith   if (numEntityBlocks && !mesh->entities) PetscCall(PetscInfo(NULL, "File specifies %" PetscCount_FMT " entity blocks, but was missing the $Entities section\n", numEntityBlocks));
9936497c311SBarry Smith   for (PetscCount block = 0, node = 0; block < numEntityBlocks; ++block, node += numNodesBlock) {
9949566063dSJacob Faibussowitsch     PetscCall(GmshReadInt(gmsh, info, 3));
9959371c9d4SSatish Balay     dim        = info[0];
9969371c9d4SSatish Balay     eid        = info[1];
9979371c9d4SSatish Balay     parametric = info[2];
998e43c9757SMatthew G. Knepley     if (mesh->entities) PetscCall(GmshEntitiesGet(mesh->entities, dim, eid, &entity));
999e43c9757SMatthew G. Knepley     numTags = entity ? entity->numTags : 0;
100081a1af93SMatthew G. Knepley     PetscCheck(!parametric, PETSC_COMM_SELF, PETSC_ERR_SUP, "Parametric coordinates not supported");
10016497c311SBarry Smith     PetscCall(GmshReadPetscCount(gmsh, &numNodesBlock, 1));
10026497c311SBarry Smith     PetscCall(GmshReadPetscInt(gmsh, nodes->id + node, numNodesBlock));
10039566063dSJacob Faibussowitsch     PetscCall(GmshReadDouble(gmsh, nodes->xyz + node * 3, numNodesBlock * 3));
10046497c311SBarry Smith     for (PetscCount n = 0; n < numNodesBlock; ++n) {
10057d5b9244SMatthew G. Knepley       PetscInt *tags = &nodes->tag[node * GMSH_MAX_TAGS];
10067d5b9244SMatthew G. Knepley 
10076497c311SBarry Smith       for (PetscInt t = 0; t < numTags; ++t) tags[n * GMSH_MAX_TAGS + t] = entity->tags[t];
10086497c311SBarry Smith       for (PetscInt t = numTags; t < GMSH_MAX_TAGS; ++t) tags[n * GMSH_MAX_TAGS + t] = -1;
10097d5b9244SMatthew G. Knepley     }
1010698a79b9SLisandro Dalcin   }
10116497c311SBarry Smith   PetscCall(PetscIntCast(sizes[2], &gmsh->nodeStart));
10126497c311SBarry Smith   PetscCall(PetscIntCast(sizes[3] + 1, &gmsh->nodeEnd));
10133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1014698a79b9SLisandro Dalcin }
1015698a79b9SLisandro Dalcin 
101633a088b6SMatthew G. Knepley /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
1017698a79b9SLisandro Dalcin $Elements
1018698a79b9SLisandro Dalcin   numEntityBlocks(size_t) numElements(size_t)
1019698a79b9SLisandro Dalcin     minElementTag(size_t) maxElementTag(size_t)
1020698a79b9SLisandro Dalcin   entityDim(int) entityTag(int) elementType(int; see below) numElementsBlock(size_t)
1021698a79b9SLisandro Dalcin     elementTag(size_t) nodeTag(size_t) ...
1022698a79b9SLisandro Dalcin     ...
1023698a79b9SLisandro Dalcin   ...
1024698a79b9SLisandro Dalcin $EndElements
1025698a79b9SLisandro Dalcin */
1026d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadElements_v41(GmshFile *gmsh, GmshMesh *mesh)
1027d71ae5a4SJacob Faibussowitsch {
10280598e1a2SLisandro Dalcin   int          info[3], eid, dim, cellType;
10296497c311SBarry Smith   PetscCount   sizes[4], numEntityBlocks, numElements, numBlockElements, numVerts, numNodes, numTags, block, elem, c, p;
1030698a79b9SLisandro Dalcin   GmshEntity  *entity = NULL;
1031698a79b9SLisandro Dalcin   GmshElement *elements;
10326497c311SBarry Smith   PetscInt    *nodeMap = gmsh->nodeMap, *ibuf = NULL;
1033698a79b9SLisandro Dalcin 
1034698a79b9SLisandro Dalcin   PetscFunctionBegin;
10356497c311SBarry Smith   PetscCall(GmshReadPetscCount(gmsh, sizes, 4));
10369371c9d4SSatish Balay   numEntityBlocks = sizes[0];
10379371c9d4SSatish Balay   numElements     = sizes[1];
10389566063dSJacob Faibussowitsch   PetscCall(GmshElementsCreate(numElements, &elements));
10396497c311SBarry Smith   PetscCall(PetscIntCast(numElements, &mesh->numElems));
10400598e1a2SLisandro Dalcin   mesh->elements = elements;
10416497c311SBarry Smith   if (numEntityBlocks && !mesh->entities) PetscCall(PetscInfo(NULL, "File specifies %" PetscCount_FMT " entity blocks, but was missing the $Entities section\n", numEntityBlocks));
1042698a79b9SLisandro Dalcin   for (c = 0, block = 0; block < numEntityBlocks; ++block) {
10439566063dSJacob Faibussowitsch     PetscCall(GmshReadInt(gmsh, info, 3));
10449371c9d4SSatish Balay     dim      = info[0];
10459371c9d4SSatish Balay     eid      = info[1];
10469371c9d4SSatish Balay     cellType = info[2];
1047e43c9757SMatthew G. Knepley     if (mesh->entities) PetscCall(GmshEntitiesGet(mesh->entities, dim, eid, &entity));
10489566063dSJacob Faibussowitsch     PetscCall(GmshCellTypeCheck(cellType));
10490598e1a2SLisandro Dalcin     numVerts = GmshCellMap[cellType].numVerts;
10500598e1a2SLisandro Dalcin     numNodes = GmshCellMap[cellType].numNodes;
1051e43c9757SMatthew G. Knepley     numTags  = entity ? entity->numTags : 0;
10526497c311SBarry Smith     PetscCall(GmshReadPetscCount(gmsh, &numBlockElements, 1));
10539566063dSJacob Faibussowitsch     PetscCall(GmshBufferGet(gmsh, (1 + numNodes) * numBlockElements, sizeof(PetscInt), &ibuf));
10546497c311SBarry Smith     PetscCall(GmshReadPetscInt(gmsh, ibuf, (1 + numNodes) * numBlockElements));
1055698a79b9SLisandro Dalcin     for (elem = 0; elem < numBlockElements; ++elem, ++c) {
1056698a79b9SLisandro Dalcin       GmshElement    *element = elements + c;
10570598e1a2SLisandro Dalcin       const PetscInt *id = ibuf + elem * (1 + numNodes), *nodes = id + 1;
10586497c311SBarry Smith 
1059698a79b9SLisandro Dalcin       element->id       = id[0];
1060698a79b9SLisandro Dalcin       element->dim      = dim;
1061698a79b9SLisandro Dalcin       element->cellType = cellType;
10626497c311SBarry Smith       PetscCall(PetscIntCast(numVerts, &element->numVerts));
10636497c311SBarry Smith       PetscCall(PetscIntCast(numNodes, &element->numNodes));
10646497c311SBarry Smith       PetscCall(PetscIntCast(numTags, &element->numTags));
10656497c311SBarry Smith       PetscCall(PetscSegBufferGet(mesh->segbuf, element->numNodes, &element->nodes));
10660598e1a2SLisandro Dalcin       for (p = 0; p < element->numNodes; p++) element->nodes[p] = nodeMap[nodes[p]];
10670598e1a2SLisandro Dalcin       for (p = 0; p < element->numTags; p++) element->tags[p] = entity->tags[p];
1068698a79b9SLisandro Dalcin     }
1069698a79b9SLisandro Dalcin   }
10703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1071698a79b9SLisandro Dalcin }
1072698a79b9SLisandro Dalcin 
10730598e1a2SLisandro Dalcin /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
1074698a79b9SLisandro Dalcin $Periodic
1075698a79b9SLisandro Dalcin   numPeriodicLinks(size_t)
10769dddd249SSatish Balay   entityDim(int) entityTag(int) entityTagPrimary(int)
1077698a79b9SLisandro Dalcin   numAffine(size_t) value(double) ...
1078698a79b9SLisandro Dalcin   numCorrespondingNodes(size_t)
10799dddd249SSatish Balay     nodeTag(size_t) nodeTagPrimary(size_t)
1080698a79b9SLisandro Dalcin     ...
1081698a79b9SLisandro Dalcin   ...
1082698a79b9SLisandro Dalcin $EndPeriodic
1083698a79b9SLisandro Dalcin */
1084d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadPeriodic_v41(GmshFile *gmsh, PetscInt periodicMap[])
1085d71ae5a4SJacob Faibussowitsch {
1086698a79b9SLisandro Dalcin   int        info[3];
1087698a79b9SLisandro Dalcin   double     dbuf[16];
10886497c311SBarry Smith   PetscCount numPeriodicLinks, numAffine, numCorrespondingNodes;
10896497c311SBarry Smith   PetscInt  *nodeMap = gmsh->nodeMap, *nodeTags = NULL;
1090698a79b9SLisandro Dalcin 
1091698a79b9SLisandro Dalcin   PetscFunctionBegin;
10926497c311SBarry Smith   PetscCall(GmshReadPetscCount(gmsh, &numPeriodicLinks, 1));
10936497c311SBarry Smith   for (PetscCount link = 0; link < numPeriodicLinks; ++link) {
10949566063dSJacob Faibussowitsch     PetscCall(GmshReadInt(gmsh, info, 3));
10956497c311SBarry Smith     PetscCall(GmshReadPetscCount(gmsh, &numAffine, 1));
10969566063dSJacob Faibussowitsch     PetscCall(GmshReadDouble(gmsh, dbuf, numAffine));
10976497c311SBarry Smith     PetscCall(GmshReadPetscCount(gmsh, &numCorrespondingNodes, 1));
10989566063dSJacob Faibussowitsch     PetscCall(GmshBufferGet(gmsh, numCorrespondingNodes, sizeof(PetscInt), &nodeTags));
10996497c311SBarry Smith     PetscCall(GmshReadPetscInt(gmsh, nodeTags, numCorrespondingNodes * 2));
11006497c311SBarry Smith     for (PetscCount node = 0; node < numCorrespondingNodes; ++node) {
11019dddd249SSatish Balay       PetscInt correspondingNode = nodeMap[nodeTags[node * 2 + 0]];
11029dddd249SSatish Balay       PetscInt primaryNode       = nodeMap[nodeTags[node * 2 + 1]];
11036497c311SBarry Smith 
11049dddd249SSatish Balay       periodicMap[correspondingNode] = primaryNode;
1105698a79b9SLisandro Dalcin     }
1106698a79b9SLisandro Dalcin   }
11073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1108698a79b9SLisandro Dalcin }
1109698a79b9SLisandro Dalcin 
11100598e1a2SLisandro Dalcin /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
1111d6689ca9SLisandro Dalcin $MeshFormat // same as MSH version 2
1112d6689ca9SLisandro Dalcin   version(ASCII double; currently 4.1)
1113d6689ca9SLisandro Dalcin   file-type(ASCII int; 0 for ASCII mode, 1 for binary mode)
1114d6689ca9SLisandro Dalcin   data-size(ASCII int; sizeof(size_t))
1115d6689ca9SLisandro Dalcin   < int with value one; only in binary mode, to detect endianness >
1116d6689ca9SLisandro Dalcin $EndMeshFormat
1117d6689ca9SLisandro Dalcin */
1118d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadMeshFormat(GmshFile *gmsh)
1119d71ae5a4SJacob Faibussowitsch {
1120698a79b9SLisandro Dalcin   char  line[PETSC_MAX_PATH_LEN];
1121698a79b9SLisandro Dalcin   int   snum, fileType, fileFormat, dataSize, checkEndian;
1122698a79b9SLisandro Dalcin   float version;
1123698a79b9SLisandro Dalcin 
1124698a79b9SLisandro Dalcin   PetscFunctionBegin;
11259566063dSJacob Faibussowitsch   PetscCall(GmshReadString(gmsh, line, 3));
1126698a79b9SLisandro Dalcin   snum       = sscanf(line, "%f %d %d", &version, &fileType, &dataSize);
1127a8d4e440SJunchao Zhang   fileFormat = (int)roundf(version * 10);
112808401ef6SPierre Jolivet   PetscCheck(snum == 3, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to parse Gmsh file header: %s", line);
1129a8d4e440SJunchao Zhang   PetscCheck(fileFormat >= 22, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at least 2.2", (double)version);
11301dca8a05SBarry Smith   PetscCheck((int)version != 3, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f not supported", (double)version);
1131a8d4e440SJunchao Zhang   PetscCheck(fileFormat <= 41, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at most 4.1", (double)version);
113208401ef6SPierre Jolivet   PetscCheck(!gmsh->binary || fileType, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Viewer is binary but Gmsh file is ASCII");
113308401ef6SPierre Jolivet   PetscCheck(gmsh->binary || !fileType, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Viewer is ASCII but Gmsh file is binary");
11341dca8a05SBarry 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);
11351dca8a05SBarry 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);
1136698a79b9SLisandro Dalcin   gmsh->fileFormat = fileFormat;
1137698a79b9SLisandro Dalcin   gmsh->dataSize   = dataSize;
1138698a79b9SLisandro Dalcin   gmsh->byteSwap   = PETSC_FALSE;
1139698a79b9SLisandro Dalcin   if (gmsh->binary) {
11409566063dSJacob Faibussowitsch     PetscCall(GmshReadInt(gmsh, &checkEndian, 1));
1141698a79b9SLisandro Dalcin     if (checkEndian != 1) {
11429566063dSJacob Faibussowitsch       PetscCall(PetscByteSwap(&checkEndian, PETSC_ENUM, 1));
114308401ef6SPierre Jolivet       PetscCheck(checkEndian == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to detect endianness in Gmsh file header: %s", line);
1144698a79b9SLisandro Dalcin       gmsh->byteSwap = PETSC_TRUE;
1145698a79b9SLisandro Dalcin     }
1146698a79b9SLisandro Dalcin   }
11473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1148698a79b9SLisandro Dalcin }
1149698a79b9SLisandro Dalcin 
11508749820aSMatthew G. Knepley /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
11518749820aSMatthew G. Knepley Neper: https://neper.info/ adds this section
11528749820aSMatthew G. Knepley 
11538749820aSMatthew G. Knepley $MeshVersion
11548749820aSMatthew G. Knepley   <major>.<minor>,<patch>
11558749820aSMatthew G. Knepley $EndMeshVersion
11568749820aSMatthew G. Knepley */
11578749820aSMatthew G. Knepley static PetscErrorCode GmshReadMeshVersion(GmshFile *gmsh)
11588749820aSMatthew G. Knepley {
11598749820aSMatthew G. Knepley   char line[PETSC_MAX_PATH_LEN];
11608749820aSMatthew G. Knepley   int  snum, major, minor, patch;
11618749820aSMatthew G. Knepley 
11628749820aSMatthew G. Knepley   PetscFunctionBegin;
11638749820aSMatthew G. Knepley   PetscCall(GmshReadString(gmsh, line, 1));
11648749820aSMatthew G. Knepley   snum = sscanf(line, "%d.%d.%d", &major, &minor, &patch);
11658749820aSMatthew G. Knepley   PetscCheck(snum == 3, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to parse Gmsh file header: %s", line);
11668749820aSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
11678749820aSMatthew G. Knepley }
11688749820aSMatthew G. Knepley 
11698749820aSMatthew G. Knepley /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
11708749820aSMatthew G. Knepley Neper: https://neper.info/ adds this section
11718749820aSMatthew G. Knepley 
11728749820aSMatthew G. Knepley $Domain
11738749820aSMatthew G. Knepley   <shape>
11748749820aSMatthew G. Knepley $EndDomain
11758749820aSMatthew G. Knepley */
11768749820aSMatthew G. Knepley static PetscErrorCode GmshReadMeshDomain(GmshFile *gmsh)
11778749820aSMatthew G. Knepley {
11788749820aSMatthew G. Knepley   char line[PETSC_MAX_PATH_LEN];
11798749820aSMatthew G. Knepley 
11808749820aSMatthew G. Knepley   PetscFunctionBegin;
11818749820aSMatthew G. Knepley   PetscCall(GmshReadString(gmsh, line, 1));
11828749820aSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
11838749820aSMatthew G. Knepley }
11848749820aSMatthew G. Knepley 
11851f643af3SLisandro Dalcin /*
11861f643af3SLisandro Dalcin PhysicalNames
11871f643af3SLisandro Dalcin   numPhysicalNames(ASCII int)
11881f643af3SLisandro Dalcin   dimension(ASCII int) physicalTag(ASCII int) "name"(127 characters max)
11891f643af3SLisandro Dalcin   ...
11901f643af3SLisandro Dalcin $EndPhysicalNames
11911f643af3SLisandro Dalcin */
1192d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadPhysicalNames(GmshFile *gmsh, GmshMesh *mesh)
1193d71ae5a4SJacob Faibussowitsch {
1194bbcf679cSJacob Faibussowitsch   char line[PETSC_MAX_PATH_LEN], name[128 + 2], *p = NULL, *q = NULL, *r = NULL;
1195a45dabc8SMatthew G. Knepley   int  snum, region, dim, tag;
1196698a79b9SLisandro Dalcin 
1197698a79b9SLisandro Dalcin   PetscFunctionBegin;
11989566063dSJacob Faibussowitsch   PetscCall(GmshReadString(gmsh, line, 1));
1199a45dabc8SMatthew G. Knepley   snum             = sscanf(line, "%d", &region);
1200a45dabc8SMatthew G. Knepley   mesh->numRegions = region;
120108401ef6SPierre Jolivet   PetscCheck(snum == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
120290d778b8SLisandro Dalcin   PetscCall(PetscMalloc3(mesh->numRegions, &mesh->regionDims, mesh->numRegions, &mesh->regionTags, mesh->numRegions, &mesh->regionNames));
1203a45dabc8SMatthew G. Knepley   for (region = 0; region < mesh->numRegions; ++region) {
12049566063dSJacob Faibussowitsch     PetscCall(GmshReadString(gmsh, line, 2));
12051f643af3SLisandro Dalcin     snum = sscanf(line, "%d %d", &dim, &tag);
120608401ef6SPierre Jolivet     PetscCheck(snum == 2, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
12079566063dSJacob Faibussowitsch     PetscCall(GmshReadString(gmsh, line, -(PetscInt)sizeof(line)));
12089566063dSJacob Faibussowitsch     PetscCall(PetscStrchr(line, '"', &p));
120928b400f6SJacob Faibussowitsch     PetscCheck(p, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
12109566063dSJacob Faibussowitsch     PetscCall(PetscStrrchr(line, '"', &q));
121108401ef6SPierre Jolivet     PetscCheck(q != p, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
12125f5cd6d5SMatthew G. Knepley     PetscCall(PetscStrrchr(line, ':', &r));
12135f5cd6d5SMatthew G. Knepley     if (p != r) q = r;
12149566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(name, p + 1, (size_t)(q - p - 1)));
121590d778b8SLisandro Dalcin     mesh->regionDims[region] = dim;
1216a45dabc8SMatthew G. Knepley     mesh->regionTags[region] = tag;
12179566063dSJacob Faibussowitsch     PetscCall(PetscStrallocpy(name, &mesh->regionNames[region]));
1218698a79b9SLisandro Dalcin   }
12193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1220de78e4feSLisandro Dalcin }
1221de78e4feSLisandro Dalcin 
1222d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadEntities(GmshFile *gmsh, GmshMesh *mesh)
1223d71ae5a4SJacob Faibussowitsch {
12240598e1a2SLisandro Dalcin   PetscFunctionBegin;
12250598e1a2SLisandro Dalcin   switch (gmsh->fileFormat) {
1226d71ae5a4SJacob Faibussowitsch   case 41:
1227d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadEntities_v41(gmsh, mesh));
1228d71ae5a4SJacob Faibussowitsch     break;
1229d71ae5a4SJacob Faibussowitsch   default:
1230d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadEntities_v40(gmsh, mesh));
1231d71ae5a4SJacob Faibussowitsch     break;
123296ca5757SLisandro Dalcin   }
12333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12340598e1a2SLisandro Dalcin }
12350598e1a2SLisandro Dalcin 
1236d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadNodes(GmshFile *gmsh, GmshMesh *mesh)
1237d71ae5a4SJacob Faibussowitsch {
12380598e1a2SLisandro Dalcin   PetscFunctionBegin;
12390598e1a2SLisandro Dalcin   switch (gmsh->fileFormat) {
1240d71ae5a4SJacob Faibussowitsch   case 41:
1241d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadNodes_v41(gmsh, mesh));
1242d71ae5a4SJacob Faibussowitsch     break;
1243d71ae5a4SJacob Faibussowitsch   case 40:
1244d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadNodes_v40(gmsh, mesh));
1245d71ae5a4SJacob Faibussowitsch     break;
1246d71ae5a4SJacob Faibussowitsch   default:
1247d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadNodes_v22(gmsh, mesh));
1248d71ae5a4SJacob Faibussowitsch     break;
12490598e1a2SLisandro Dalcin   }
12500598e1a2SLisandro Dalcin 
12510598e1a2SLisandro Dalcin   { /* Gmsh v2.2/v4.0 does not provide min/max node tags */
12520598e1a2SLisandro Dalcin     if (mesh->numNodes > 0 && gmsh->nodeEnd >= gmsh->nodeStart) {
1253*1690c2aeSBarry Smith       PetscInt   tagMin = PETSC_INT_MAX, tagMax = PETSC_INT_MIN, n;
12540598e1a2SLisandro Dalcin       GmshNodes *nodes = mesh->nodelist;
12550598e1a2SLisandro Dalcin       for (n = 0; n < mesh->numNodes; ++n) {
12560598e1a2SLisandro Dalcin         const PetscInt tag = nodes->id[n];
12570598e1a2SLisandro Dalcin         tagMin             = PetscMin(tag, tagMin);
12580598e1a2SLisandro Dalcin         tagMax             = PetscMax(tag, tagMax);
12590598e1a2SLisandro Dalcin       }
12600598e1a2SLisandro Dalcin       gmsh->nodeStart = tagMin;
12610598e1a2SLisandro Dalcin       gmsh->nodeEnd   = tagMax + 1;
12620598e1a2SLisandro Dalcin     }
12630598e1a2SLisandro Dalcin   }
12640598e1a2SLisandro Dalcin 
12650598e1a2SLisandro Dalcin   { /* Support for sparse node tags */
12660598e1a2SLisandro Dalcin     PetscInt   n, t;
12670598e1a2SLisandro Dalcin     GmshNodes *nodes = mesh->nodelist;
12689566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(gmsh->nodeEnd - gmsh->nodeStart, &gmsh->nbuf));
1269*1690c2aeSBarry Smith     for (t = 0; t < gmsh->nodeEnd - gmsh->nodeStart; ++t) gmsh->nbuf[t] = PETSC_INT_MIN;
12700598e1a2SLisandro Dalcin     gmsh->nodeMap = gmsh->nbuf - gmsh->nodeStart;
12710598e1a2SLisandro Dalcin     for (n = 0; n < mesh->numNodes; ++n) {
12720598e1a2SLisandro Dalcin       const PetscInt tag = nodes->id[n];
127363a3b9bcSJacob Faibussowitsch       PetscCheck(gmsh->nodeMap[tag] < 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Repeated node tag %" PetscInt_FMT, tag);
12740598e1a2SLisandro Dalcin       gmsh->nodeMap[tag] = n;
12750598e1a2SLisandro Dalcin     }
12760598e1a2SLisandro Dalcin   }
12773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12780598e1a2SLisandro Dalcin }
12790598e1a2SLisandro Dalcin 
1280d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadElements(GmshFile *gmsh, GmshMesh *mesh)
1281d71ae5a4SJacob Faibussowitsch {
12820598e1a2SLisandro Dalcin   PetscFunctionBegin;
12830598e1a2SLisandro Dalcin   switch (gmsh->fileFormat) {
1284d71ae5a4SJacob Faibussowitsch   case 41:
1285d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadElements_v41(gmsh, mesh));
1286d71ae5a4SJacob Faibussowitsch     break;
1287d71ae5a4SJacob Faibussowitsch   case 40:
1288d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadElements_v40(gmsh, mesh));
1289d71ae5a4SJacob Faibussowitsch     break;
1290d71ae5a4SJacob Faibussowitsch   default:
1291d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadElements_v22(gmsh, mesh));
1292d71ae5a4SJacob Faibussowitsch     break;
12930598e1a2SLisandro Dalcin   }
12940598e1a2SLisandro Dalcin 
12950598e1a2SLisandro Dalcin   { /* Reorder elements by codimension and polytope type */
12960598e1a2SLisandro Dalcin     PetscInt     ne       = mesh->numElems;
12970598e1a2SLisandro Dalcin     GmshElement *elements = mesh->elements;
1298066ea43fSLisandro Dalcin     PetscInt     keymap[GMSH_NUM_POLYTOPES], nk = 0;
1299066ea43fSLisandro Dalcin     PetscInt     offset[GMSH_NUM_POLYTOPES + 1], e, k;
13000598e1a2SLisandro Dalcin 
1301*1690c2aeSBarry Smith     for (k = 0; k < GMSH_NUM_POLYTOPES; ++k) keymap[k] = PETSC_INT_MIN;
13029566063dSJacob Faibussowitsch     PetscCall(PetscMemzero(offset, sizeof(offset)));
13030598e1a2SLisandro Dalcin 
1304066ea43fSLisandro Dalcin     keymap[GMSH_TET] = nk++;
1305066ea43fSLisandro Dalcin     keymap[GMSH_HEX] = nk++;
1306066ea43fSLisandro Dalcin     keymap[GMSH_PRI] = nk++;
1307066ea43fSLisandro Dalcin     keymap[GMSH_PYR] = nk++;
1308066ea43fSLisandro Dalcin     keymap[GMSH_TRI] = nk++;
1309066ea43fSLisandro Dalcin     keymap[GMSH_QUA] = nk++;
1310066ea43fSLisandro Dalcin     keymap[GMSH_SEG] = nk++;
1311066ea43fSLisandro Dalcin     keymap[GMSH_VTX] = nk++;
13120598e1a2SLisandro Dalcin 
13139566063dSJacob Faibussowitsch     PetscCall(GmshElementsCreate(mesh->numElems, &mesh->elements));
13144ad8454bSPierre Jolivet #define key(eid) keymap[GmshCellMap[elements[eid].cellType].polytope]
13150598e1a2SLisandro Dalcin     for (e = 0; e < ne; ++e) offset[1 + key(e)]++;
13160598e1a2SLisandro Dalcin     for (k = 1; k < nk; ++k) offset[k] += offset[k - 1];
13170598e1a2SLisandro Dalcin     for (e = 0; e < ne; ++e) mesh->elements[offset[key(e)]++] = elements[e];
13180598e1a2SLisandro Dalcin #undef key
13199566063dSJacob Faibussowitsch     PetscCall(GmshElementsDestroy(&elements));
1320066ea43fSLisandro Dalcin   }
13210598e1a2SLisandro Dalcin 
1322066ea43fSLisandro Dalcin   { /* Mesh dimension and order */
1323066ea43fSLisandro Dalcin     GmshElement *elem = mesh->numElems ? mesh->elements : NULL;
1324066ea43fSLisandro Dalcin     mesh->dim         = elem ? GmshCellMap[elem->cellType].dim : 0;
1325066ea43fSLisandro Dalcin     mesh->order       = elem ? GmshCellMap[elem->cellType].order : 0;
13260598e1a2SLisandro Dalcin   }
13270598e1a2SLisandro Dalcin 
13280598e1a2SLisandro Dalcin   {
13290598e1a2SLisandro Dalcin     PetscBT  vtx;
13300598e1a2SLisandro Dalcin     PetscInt dim = mesh->dim, e, n, v;
13310598e1a2SLisandro Dalcin 
13329566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(mesh->numNodes, &vtx));
13330598e1a2SLisandro Dalcin 
13340598e1a2SLisandro Dalcin     /* Compute number of cells and set of vertices */
13350598e1a2SLisandro Dalcin     mesh->numCells = 0;
13360598e1a2SLisandro Dalcin     for (e = 0; e < mesh->numElems; ++e) {
13370598e1a2SLisandro Dalcin       GmshElement *elem = mesh->elements + e;
13380598e1a2SLisandro Dalcin       if (elem->dim == dim && dim > 0) mesh->numCells++;
133948a46eb9SPierre Jolivet       for (v = 0; v < elem->numVerts; v++) PetscCall(PetscBTSet(vtx, elem->nodes[v]));
13400598e1a2SLisandro Dalcin     }
13410598e1a2SLisandro Dalcin 
13420598e1a2SLisandro Dalcin     /* Compute numbering for vertices */
13430598e1a2SLisandro Dalcin     mesh->numVerts = 0;
13449566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(mesh->numNodes, &mesh->vertexMap));
1345*1690c2aeSBarry Smith     for (n = 0; n < mesh->numNodes; ++n) mesh->vertexMap[n] = PetscBTLookup(vtx, n) ? mesh->numVerts++ : PETSC_INT_MIN;
13460598e1a2SLisandro Dalcin 
13479566063dSJacob Faibussowitsch     PetscCall(PetscBTDestroy(&vtx));
13480598e1a2SLisandro Dalcin   }
13493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13500598e1a2SLisandro Dalcin }
13510598e1a2SLisandro Dalcin 
1352d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadPeriodic(GmshFile *gmsh, GmshMesh *mesh)
1353d71ae5a4SJacob Faibussowitsch {
13540598e1a2SLisandro Dalcin   PetscInt n;
13550598e1a2SLisandro Dalcin 
13560598e1a2SLisandro Dalcin   PetscFunctionBegin;
13579566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(mesh->numNodes, &mesh->periodMap));
13580598e1a2SLisandro Dalcin   for (n = 0; n < mesh->numNodes; ++n) mesh->periodMap[n] = n;
13590598e1a2SLisandro Dalcin   switch (gmsh->fileFormat) {
1360d71ae5a4SJacob Faibussowitsch   case 41:
1361d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadPeriodic_v41(gmsh, mesh->periodMap));
1362d71ae5a4SJacob Faibussowitsch     break;
1363d71ae5a4SJacob Faibussowitsch   default:
1364d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadPeriodic_v40(gmsh, mesh->periodMap));
1365d71ae5a4SJacob Faibussowitsch     break;
13660598e1a2SLisandro Dalcin   }
13670598e1a2SLisandro Dalcin 
13689dddd249SSatish Balay   /* Find canonical primary nodes */
13690598e1a2SLisandro Dalcin   for (n = 0; n < mesh->numNodes; ++n)
13709371c9d4SSatish Balay     while (mesh->periodMap[n] != mesh->periodMap[mesh->periodMap[n]]) mesh->periodMap[n] = mesh->periodMap[mesh->periodMap[n]];
13710598e1a2SLisandro Dalcin 
13729dddd249SSatish Balay   /* Renumber vertices (filter out correspondings) */
13730598e1a2SLisandro Dalcin   mesh->numVerts = 0;
13740598e1a2SLisandro Dalcin   for (n = 0; n < mesh->numNodes; ++n)
13750598e1a2SLisandro Dalcin     if (mesh->vertexMap[n] >= 0)   /* is vertex */
13769dddd249SSatish Balay       if (mesh->periodMap[n] == n) /* is primary */
13770598e1a2SLisandro Dalcin         mesh->vertexMap[n] = mesh->numVerts++;
13780598e1a2SLisandro Dalcin   for (n = 0; n < mesh->numNodes; ++n)
13790598e1a2SLisandro Dalcin     if (mesh->vertexMap[n] >= 0)   /* is vertex */
13809dddd249SSatish Balay       if (mesh->periodMap[n] != n) /* is corresponding  */
13810598e1a2SLisandro Dalcin         mesh->vertexMap[n] = mesh->vertexMap[mesh->periodMap[n]];
13823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13830598e1a2SLisandro Dalcin }
13840598e1a2SLisandro Dalcin 
1385066ea43fSLisandro Dalcin #define DM_POLYTOPE_VERTEX DM_POLYTOPE_POINT
1386066ea43fSLisandro Dalcin static const DMPolytopeType DMPolytopeMap[] = {
1387066ea43fSLisandro Dalcin   /* GMSH_VTX */ DM_POLYTOPE_VERTEX,
1388066ea43fSLisandro Dalcin   /* GMSH_SEG */ DM_POLYTOPE_SEGMENT,
1389066ea43fSLisandro Dalcin   /* GMSH_TRI */ DM_POLYTOPE_TRIANGLE,
1390066ea43fSLisandro Dalcin   /* GMSH_QUA */ DM_POLYTOPE_QUADRILATERAL,
1391066ea43fSLisandro Dalcin   /* GMSH_TET */ DM_POLYTOPE_TETRAHEDRON,
1392066ea43fSLisandro Dalcin   /* GMSH_HEX */ DM_POLYTOPE_HEXAHEDRON,
1393066ea43fSLisandro Dalcin   /* GMSH_PRI */ DM_POLYTOPE_TRI_PRISM,
13949371c9d4SSatish Balay   /* GMSH_PYR */ DM_POLYTOPE_PYRAMID,       DM_POLYTOPE_UNKNOWN};
13950598e1a2SLisandro Dalcin 
1396d71ae5a4SJacob Faibussowitsch static inline DMPolytopeType DMPolytopeTypeFromGmsh(PetscInt cellType)
1397d71ae5a4SJacob Faibussowitsch {
1398066ea43fSLisandro Dalcin   return DMPolytopeMap[GmshCellMap[cellType].polytope];
1399066ea43fSLisandro Dalcin }
1400066ea43fSLisandro Dalcin 
1401d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshCreateFE(MPI_Comm comm, const char prefix[], PetscBool isSimplex, PetscBool continuity, PetscDTNodeType nodeType, PetscInt dim, PetscInt Nc, PetscInt k, PetscFE *fem)
1402d71ae5a4SJacob Faibussowitsch {
1403066ea43fSLisandro Dalcin   DM              K;
1404066ea43fSLisandro Dalcin   PetscSpace      P;
1405066ea43fSLisandro Dalcin   PetscDualSpace  Q;
1406066ea43fSLisandro Dalcin   PetscQuadrature q, fq;
1407066ea43fSLisandro Dalcin   PetscBool       isTensor = isSimplex ? PETSC_FALSE : PETSC_TRUE;
1408066ea43fSLisandro Dalcin   PetscBool       endpoint = PETSC_TRUE;
1409066ea43fSLisandro Dalcin   char            name[32];
1410066ea43fSLisandro Dalcin 
1411066ea43fSLisandro Dalcin   PetscFunctionBegin;
1412066ea43fSLisandro Dalcin   /* Create space */
14139566063dSJacob Faibussowitsch   PetscCall(PetscSpaceCreate(comm, &P));
14149566063dSJacob Faibussowitsch   PetscCall(PetscSpaceSetType(P, PETSCSPACEPOLYNOMIAL));
14159566063dSJacob Faibussowitsch   PetscCall(PetscSpacePolynomialSetTensor(P, isTensor));
14169566063dSJacob Faibussowitsch   PetscCall(PetscSpaceSetNumComponents(P, Nc));
14179566063dSJacob Faibussowitsch   PetscCall(PetscSpaceSetNumVariables(P, dim));
14189566063dSJacob Faibussowitsch   PetscCall(PetscSpaceSetDegree(P, k, PETSC_DETERMINE));
1419066ea43fSLisandro Dalcin   if (prefix) {
14209566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)P, prefix));
14219566063dSJacob Faibussowitsch     PetscCall(PetscSpaceSetFromOptions(P));
14229566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)P, NULL));
14239566063dSJacob Faibussowitsch     PetscCall(PetscSpaceGetDegree(P, &k, NULL));
1424066ea43fSLisandro Dalcin   }
14259566063dSJacob Faibussowitsch   PetscCall(PetscSpaceSetUp(P));
1426066ea43fSLisandro Dalcin   /* Create dual space */
14279566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceCreate(comm, &Q));
14289566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetType(Q, PETSCDUALSPACELAGRANGE));
14299566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceLagrangeSetTensor(Q, isTensor));
14309566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceLagrangeSetContinuity(Q, continuity));
14319566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceLagrangeSetNodeType(Q, nodeType, endpoint, 0));
14329566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetNumComponents(Q, Nc));
14339566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetOrder(Q, k));
14349566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceCell(PETSC_COMM_SELF, DMPolytopeTypeSimpleShape(dim, isSimplex), &K));
14359566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetDM(Q, K));
14369566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&K));
1437066ea43fSLisandro Dalcin   if (prefix) {
14389566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)Q, prefix));
14399566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceSetFromOptions(Q));
14409566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)Q, NULL));
1441066ea43fSLisandro Dalcin   }
14429566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetUp(Q));
1443066ea43fSLisandro Dalcin   /* Create quadrature */
1444066ea43fSLisandro Dalcin   if (isSimplex) {
14459566063dSJacob Faibussowitsch     PetscCall(PetscDTStroudConicalQuadrature(dim, 1, k + 1, -1, +1, &q));
14469566063dSJacob Faibussowitsch     PetscCall(PetscDTStroudConicalQuadrature(dim - 1, 1, k + 1, -1, +1, &fq));
1447066ea43fSLisandro Dalcin   } else {
14489566063dSJacob Faibussowitsch     PetscCall(PetscDTGaussTensorQuadrature(dim, 1, k + 1, -1, +1, &q));
14499566063dSJacob Faibussowitsch     PetscCall(PetscDTGaussTensorQuadrature(dim - 1, 1, k + 1, -1, +1, &fq));
1450066ea43fSLisandro Dalcin   }
1451066ea43fSLisandro Dalcin   /* Create finite element */
14529566063dSJacob Faibussowitsch   PetscCall(PetscFECreate(comm, fem));
14539566063dSJacob Faibussowitsch   PetscCall(PetscFESetType(*fem, PETSCFEBASIC));
14549566063dSJacob Faibussowitsch   PetscCall(PetscFESetNumComponents(*fem, Nc));
14559566063dSJacob Faibussowitsch   PetscCall(PetscFESetBasisSpace(*fem, P));
14569566063dSJacob Faibussowitsch   PetscCall(PetscFESetDualSpace(*fem, Q));
14579566063dSJacob Faibussowitsch   PetscCall(PetscFESetQuadrature(*fem, q));
14589566063dSJacob Faibussowitsch   PetscCall(PetscFESetFaceQuadrature(*fem, fq));
1459066ea43fSLisandro Dalcin   if (prefix) {
14609566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*fem, prefix));
14619566063dSJacob Faibussowitsch     PetscCall(PetscFESetFromOptions(*fem));
14629566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*fem, NULL));
1463066ea43fSLisandro Dalcin   }
14649566063dSJacob Faibussowitsch   PetscCall(PetscFESetUp(*fem));
1465066ea43fSLisandro Dalcin   /* Cleanup */
14669566063dSJacob Faibussowitsch   PetscCall(PetscSpaceDestroy(&P));
14679566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceDestroy(&Q));
14689566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureDestroy(&q));
14699566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureDestroy(&fq));
1470066ea43fSLisandro Dalcin   /* Set finite element name */
147163a3b9bcSJacob Faibussowitsch   PetscCall(PetscSNPrintf(name, sizeof(name), "%s%" PetscInt_FMT, isSimplex ? "P" : "Q", k));
14729566063dSJacob Faibussowitsch   PetscCall(PetscFESetName(*fem, name));
14733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
147496ca5757SLisandro Dalcin }
147596ca5757SLisandro Dalcin 
1476cc4c1da9SBarry Smith /*@
1477a1cb98faSBarry Smith   DMPlexCreateGmshFromFile - Create a `DMPLEX` mesh from a Gmsh file
1478d6689ca9SLisandro Dalcin 
1479a4e35b19SJacob Faibussowitsch   Input Parameters:
1480d6689ca9SLisandro Dalcin + comm        - The MPI communicator
1481d6689ca9SLisandro Dalcin . filename    - Name of the Gmsh file
1482d6689ca9SLisandro Dalcin - interpolate - Create faces and edges in the mesh
1483d6689ca9SLisandro Dalcin 
1484d6689ca9SLisandro Dalcin   Output Parameter:
1485a1cb98faSBarry Smith . dm - The `DM` object representing the mesh
1486d6689ca9SLisandro Dalcin 
1487d6689ca9SLisandro Dalcin   Level: beginner
1488d6689ca9SLisandro Dalcin 
14891cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromFile()`, `DMPlexCreateGmsh()`, `DMPlexCreate()`
1490d6689ca9SLisandro Dalcin @*/
1491d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateGmshFromFile(MPI_Comm comm, const char filename[], PetscBool interpolate, DM *dm)
1492d71ae5a4SJacob Faibussowitsch {
1493d6689ca9SLisandro Dalcin   PetscViewer     viewer;
1494d6689ca9SLisandro Dalcin   PetscMPIInt     rank;
1495d6689ca9SLisandro Dalcin   int             fileType;
1496d6689ca9SLisandro Dalcin   PetscViewerType vtype;
1497d6689ca9SLisandro Dalcin 
1498d6689ca9SLisandro Dalcin   PetscFunctionBegin;
14999566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1500d6689ca9SLisandro Dalcin 
1501d6689ca9SLisandro Dalcin   /* Determine Gmsh file type (ASCII or binary) from file header */
1502dd400576SPatrick Sanan   if (rank == 0) {
15030598e1a2SLisandro Dalcin     GmshFile gmsh[1];
1504d6689ca9SLisandro Dalcin     char     line[PETSC_MAX_PATH_LEN];
1505d6689ca9SLisandro Dalcin     int      snum;
1506d6689ca9SLisandro Dalcin     float    version;
1507a8d4e440SJunchao Zhang     int      fileFormat;
1508d6689ca9SLisandro Dalcin 
15099566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(gmsh, 1));
15109566063dSJacob Faibussowitsch     PetscCall(PetscViewerCreate(PETSC_COMM_SELF, &gmsh->viewer));
15119566063dSJacob Faibussowitsch     PetscCall(PetscViewerSetType(gmsh->viewer, PETSCVIEWERASCII));
15129566063dSJacob Faibussowitsch     PetscCall(PetscViewerFileSetMode(gmsh->viewer, FILE_MODE_READ));
15139566063dSJacob Faibussowitsch     PetscCall(PetscViewerFileSetName(gmsh->viewer, filename));
1514d6689ca9SLisandro Dalcin     /* Read only the first two lines of the Gmsh file */
15159566063dSJacob Faibussowitsch     PetscCall(GmshReadSection(gmsh, line));
15169566063dSJacob Faibussowitsch     PetscCall(GmshExpect(gmsh, "$MeshFormat", line));
15179566063dSJacob Faibussowitsch     PetscCall(GmshReadString(gmsh, line, 2));
1518d6689ca9SLisandro Dalcin     snum       = sscanf(line, "%f %d", &version, &fileType);
1519a8d4e440SJunchao Zhang     fileFormat = (int)roundf(version * 10);
152008401ef6SPierre Jolivet     PetscCheck(snum == 2, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to parse Gmsh file header: %s", line);
1521a8d4e440SJunchao Zhang     PetscCheck(fileFormat >= 22, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at least 2.2", (double)version);
15221dca8a05SBarry Smith     PetscCheck((int)version != 3, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f not supported", (double)version);
1523a8d4e440SJunchao Zhang     PetscCheck(fileFormat <= 41, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at most 4.1", (double)version);
15249566063dSJacob Faibussowitsch     PetscCall(PetscViewerDestroy(&gmsh->viewer));
1525d6689ca9SLisandro Dalcin   }
15269566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Bcast(&fileType, 1, MPI_INT, 0, comm));
1527d6689ca9SLisandro Dalcin   vtype = (fileType == 0) ? PETSCVIEWERASCII : PETSCVIEWERBINARY;
1528d6689ca9SLisandro Dalcin 
1529d6689ca9SLisandro Dalcin   /* Create appropriate viewer and build plex */
15309566063dSJacob Faibussowitsch   PetscCall(PetscViewerCreate(comm, &viewer));
15319566063dSJacob Faibussowitsch   PetscCall(PetscViewerSetType(viewer, vtype));
15329566063dSJacob Faibussowitsch   PetscCall(PetscViewerFileSetMode(viewer, FILE_MODE_READ));
15339566063dSJacob Faibussowitsch   PetscCall(PetscViewerFileSetName(viewer, filename));
15349566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateGmsh(comm, viewer, interpolate, dm));
15359566063dSJacob Faibussowitsch   PetscCall(PetscViewerDestroy(&viewer));
15363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1537d6689ca9SLisandro Dalcin }
1538d6689ca9SLisandro Dalcin 
1539331830f3SMatthew G. Knepley /*@
1540a1cb98faSBarry Smith   DMPlexCreateGmsh - Create a `DMPLEX` mesh from a Gmsh file viewer
1541331830f3SMatthew G. Knepley 
1542d083f849SBarry Smith   Collective
1543331830f3SMatthew G. Knepley 
1544331830f3SMatthew G. Knepley   Input Parameters:
1545331830f3SMatthew G. Knepley + comm        - The MPI communicator
1546a1cb98faSBarry Smith . viewer      - The `PetscViewer` associated with a Gmsh file
1547331830f3SMatthew G. Knepley - interpolate - Create faces and edges in the mesh
1548331830f3SMatthew G. Knepley 
1549331830f3SMatthew G. Knepley   Output Parameter:
1550a1cb98faSBarry Smith . dm - The `DM` object representing the mesh
1551331830f3SMatthew G. Knepley 
1552a1cb98faSBarry Smith   Options Database Keys:
1553df93260fSMatthew G. Knepley + -dm_plex_gmsh_hybrid        - Force triangular prisms to use tensor order
1554df93260fSMatthew G. Knepley . -dm_plex_gmsh_periodic      - Read Gmsh periodic section and construct a periodic Plex
1555df93260fSMatthew G. Knepley . -dm_plex_gmsh_highorder     - Generate high-order coordinates
1556df93260fSMatthew 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
15572b205333SMatthew G. Knepley . -dm_plex_gmsh_use_generic   - Generate generic labels, i.e. Cell Sets, Face Sets, etc.
1558df93260fSMatthew G. Knepley . -dm_plex_gmsh_use_regions   - Generate labels with region names
1559df93260fSMatthew G. Knepley . -dm_plex_gmsh_mark_vertices - Add vertices to generated labels
1560df93260fSMatthew G. Knepley . -dm_plex_gmsh_multiple_tags - Allow multiple tags for default labels
1561df93260fSMatthew G. Knepley - -dm_plex_gmsh_spacedim <d>  - Embedding space dimension, if different from topological dimension
1562df93260fSMatthew G. Knepley 
15631d27aa22SBarry Smith   Level: beginner
15641d27aa22SBarry Smith 
15651d27aa22SBarry Smith   Notes:
15661d27aa22SBarry Smith   The Gmsh file format is described in <http://gmsh.info/doc/texinfo/gmsh.html#MSH-file-format>
1567df93260fSMatthew G. Knepley 
15686497c311SBarry Smith   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`.
1569331830f3SMatthew G. Knepley 
15701cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`
1571331830f3SMatthew G. Knepley @*/
1572d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateGmsh(MPI_Comm comm, PetscViewer viewer, PetscBool interpolate, DM *dm)
1573d71ae5a4SJacob Faibussowitsch {
15740598e1a2SLisandro Dalcin   GmshMesh    *mesh          = NULL;
157511c56cb0SLisandro Dalcin   PetscViewer  parentviewer  = NULL;
15760598e1a2SLisandro Dalcin   PetscBT      periodicVerts = NULL;
1577eae3dc7dSJacob Faibussowitsch   PetscBT     *periodicCells = NULL;
15786858538eSMatthew G. Knepley   DM           cdm, cdmCell = NULL;
15796858538eSMatthew G. Knepley   PetscSection cs, csCell   = NULL;
15806858538eSMatthew G. Knepley   Vec          coordinates, coordinatesCell;
15810444adf6SMatthew G. Knepley   DMLabel      cellSets = NULL, faceSets = NULL, edgeSets = NULL, vertSets = NULL, marker = NULL, *regionSets;
15829db5b827SMatthew G. Knepley   PetscInt     dim = 0, coordDim = -1, order = 0, maxHeight = 0;
15839db5b827SMatthew G. Knepley   PetscInt     numNodes = 0, numElems = 0, numVerts = 0, numCells = 0, vStart, vEnd;
1584066ea43fSLisandro Dalcin   PetscInt     cell, cone[8], e, n, v, d;
15852b205333SMatthew G. Knepley   PetscBool    usegeneric = PETSC_TRUE, useregions = PETSC_FALSE, markvertices = PETSC_FALSE, multipleTags = PETSC_FALSE;
15862b205333SMatthew G. Knepley   PetscBool    flg, binary, hybrid = interpolate, periodic = PETSC_TRUE;
1587066ea43fSLisandro Dalcin   PetscBool    highOrder = PETSC_TRUE, highOrderSet, project = PETSC_FALSE;
1588066ea43fSLisandro Dalcin   PetscBool    isSimplex = PETSC_FALSE, isHybrid = PETSC_FALSE, hasTetra = PETSC_FALSE;
15890598e1a2SLisandro Dalcin   PetscMPIInt  rank;
1590331830f3SMatthew G. Knepley 
1591331830f3SMatthew G. Knepley   PetscFunctionBegin;
15929566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1593d0609cedSBarry Smith   PetscObjectOptionsBegin((PetscObject)viewer);
1594d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "DMPlex Gmsh options");
1595df93260fSMatthew G. Knepley   PetscCall(PetscOptionsBool("-dm_plex_gmsh_hybrid", "Force triangular prisms to use tensor order", "DMPlexCreateGmsh", hybrid, &hybrid, NULL));
15969566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_plex_gmsh_periodic", "Read Gmsh periodic section", "DMPlexCreateGmsh", periodic, &periodic, NULL));
15979566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_plex_gmsh_highorder", "Generate high-order coordinates", "DMPlexCreateGmsh", highOrder, &highOrder, &highOrderSet));
15989566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_plex_gmsh_project", "Project high-order coordinates to a different space", "DMPlexCreateGmsh", project, &project, NULL));
15999566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_plex_gmsh_use_regions", "Generate labels with region names", "DMPlexCreateGmsh", useregions, &useregions, NULL));
16002b205333SMatthew G. Knepley   PetscCall(PetscOptionsBool("-dm_plex_gmsh_use_generic", "Generate generic labels, i.e. Cell Sets, Face Sets, etc", "DMPlexCreateGmsh", usegeneric, &usegeneric, &flg));
16012b205333SMatthew G. Knepley   if (!flg && useregions) usegeneric = PETSC_FALSE;
16029566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_plex_gmsh_mark_vertices", "Add vertices to generated labels", "DMPlexCreateGmsh", markvertices, &markvertices, NULL));
1603df93260fSMatthew G. Knepley   PetscCall(PetscOptionsBool("-dm_plex_gmsh_multiple_tags", "Allow multiple tags for default labels", "DMPlexCreateGmsh", multipleTags, &multipleTags, NULL));
16049566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBoundedInt("-dm_plex_gmsh_spacedim", "Embedding space dimension", "DMPlexCreateGmsh", coordDim, &coordDim, NULL, PETSC_DECIDE));
16059db5b827SMatthew G. Knepley   PetscCall(PetscOptionsBoundedInt("-dm_localize_height", "Localize edges and faces in addition to cells", "", maxHeight, &maxHeight, NULL, 0));
1606d0609cedSBarry Smith   PetscOptionsHeadEnd();
1607d0609cedSBarry Smith   PetscOptionsEnd();
16080598e1a2SLisandro Dalcin 
16099566063dSJacob Faibussowitsch   PetscCall(GmshCellInfoSetUp());
161011c56cb0SLisandro Dalcin 
16119566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm, dm));
16129566063dSJacob Faibussowitsch   PetscCall(DMSetType(*dm, DMPLEX));
16139566063dSJacob Faibussowitsch   PetscCall(PetscLogEventBegin(DMPLEX_CreateGmsh, *dm, NULL, NULL, NULL));
161411c56cb0SLisandro Dalcin 
16159566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &binary));
161611c56cb0SLisandro Dalcin 
161711c56cb0SLisandro Dalcin   /* Binary viewers read on all ranks, get subviewer to read only in rank 0 */
16183b46f529SLisandro Dalcin   if (binary) {
161911c56cb0SLisandro Dalcin     parentviewer = viewer;
16209566063dSJacob Faibussowitsch     PetscCall(PetscViewerGetSubViewer(parentviewer, PETSC_COMM_SELF, &viewer));
162111c56cb0SLisandro Dalcin   }
162211c56cb0SLisandro Dalcin 
1623dd400576SPatrick Sanan   if (rank == 0) {
16240598e1a2SLisandro Dalcin     GmshFile  gmsh[1];
1625698a79b9SLisandro Dalcin     char      line[PETSC_MAX_PATH_LEN];
1626698a79b9SLisandro Dalcin     PetscBool match;
1627331830f3SMatthew G. Knepley 
16289566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(gmsh, 1));
1629698a79b9SLisandro Dalcin     gmsh->viewer = viewer;
1630698a79b9SLisandro Dalcin     gmsh->binary = binary;
1631698a79b9SLisandro Dalcin 
16329566063dSJacob Faibussowitsch     PetscCall(GmshMeshCreate(&mesh));
16330598e1a2SLisandro Dalcin 
1634698a79b9SLisandro Dalcin     /* Read mesh format */
16359566063dSJacob Faibussowitsch     PetscCall(GmshReadSection(gmsh, line));
16369566063dSJacob Faibussowitsch     PetscCall(GmshExpect(gmsh, "$MeshFormat", line));
16379566063dSJacob Faibussowitsch     PetscCall(GmshReadMeshFormat(gmsh));
16389566063dSJacob Faibussowitsch     PetscCall(GmshReadEndSection(gmsh, "$EndMeshFormat", line));
163911c56cb0SLisandro Dalcin 
16408749820aSMatthew G. Knepley     /* OPTIONAL Read mesh version (Neper only) */
16419566063dSJacob Faibussowitsch     PetscCall(GmshReadSection(gmsh, line));
16428749820aSMatthew G. Knepley     PetscCall(GmshMatch(gmsh, "$MeshVersion", line, &match));
16438749820aSMatthew G. Knepley     if (match) {
16448749820aSMatthew G. Knepley       PetscCall(GmshExpect(gmsh, "$MeshVersion", line));
16458749820aSMatthew G. Knepley       PetscCall(GmshReadMeshVersion(gmsh));
16468749820aSMatthew G. Knepley       PetscCall(GmshReadEndSection(gmsh, "$EndMeshVersion", line));
16478749820aSMatthew G. Knepley       /* Initial read for entity section */
16488749820aSMatthew G. Knepley       PetscCall(GmshReadSection(gmsh, line));
16498749820aSMatthew G. Knepley     }
16508749820aSMatthew G. Knepley 
16518749820aSMatthew G. Knepley     /* OPTIONAL Read mesh domain (Neper only) */
16528749820aSMatthew G. Knepley     PetscCall(GmshMatch(gmsh, "$Domain", line, &match));
16538749820aSMatthew G. Knepley     if (match) {
16548749820aSMatthew G. Knepley       PetscCall(GmshExpect(gmsh, "$Domain", line));
16558749820aSMatthew G. Knepley       PetscCall(GmshReadMeshDomain(gmsh));
16568749820aSMatthew G. Knepley       PetscCall(GmshReadEndSection(gmsh, "$EndDomain", line));
16578749820aSMatthew G. Knepley       /* Initial read for entity section */
16588749820aSMatthew G. Knepley       PetscCall(GmshReadSection(gmsh, line));
16598749820aSMatthew G. Knepley     }
16608749820aSMatthew G. Knepley 
16618749820aSMatthew G. Knepley     /* OPTIONAL Read physical names */
16629566063dSJacob Faibussowitsch     PetscCall(GmshMatch(gmsh, "$PhysicalNames", line, &match));
1663dc0ede3bSMatthew G. Knepley     if (match) {
16649566063dSJacob Faibussowitsch       PetscCall(GmshExpect(gmsh, "$PhysicalNames", line));
16659566063dSJacob Faibussowitsch       PetscCall(GmshReadPhysicalNames(gmsh, mesh));
16669566063dSJacob Faibussowitsch       PetscCall(GmshReadEndSection(gmsh, "$EndPhysicalNames", line));
1667698a79b9SLisandro Dalcin       /* Initial read for entity section */
16689566063dSJacob Faibussowitsch       PetscCall(GmshReadSection(gmsh, line));
1669dc0ede3bSMatthew G. Knepley     }
167011c56cb0SLisandro Dalcin 
1671e43c9757SMatthew G. Knepley     /* OPTIONAL Read entities */
1672698a79b9SLisandro Dalcin     if (gmsh->fileFormat >= 40) {
1673e43c9757SMatthew G. Knepley       PetscCall(GmshMatch(gmsh, "$Entities", line, &match));
1674e43c9757SMatthew G. Knepley       if (match) {
16759566063dSJacob Faibussowitsch         PetscCall(GmshExpect(gmsh, "$Entities", line));
16769566063dSJacob Faibussowitsch         PetscCall(GmshReadEntities(gmsh, mesh));
16779566063dSJacob Faibussowitsch         PetscCall(GmshReadEndSection(gmsh, "$EndEntities", line));
1678698a79b9SLisandro Dalcin         /* Initial read for nodes section */
16799566063dSJacob Faibussowitsch         PetscCall(GmshReadSection(gmsh, line));
1680de78e4feSLisandro Dalcin       }
1681e43c9757SMatthew G. Knepley     }
1682de78e4feSLisandro Dalcin 
1683698a79b9SLisandro Dalcin     /* Read nodes */
16849566063dSJacob Faibussowitsch     PetscCall(GmshExpect(gmsh, "$Nodes", line));
16859566063dSJacob Faibussowitsch     PetscCall(GmshReadNodes(gmsh, mesh));
16869566063dSJacob Faibussowitsch     PetscCall(GmshReadEndSection(gmsh, "$EndNodes", line));
168711c56cb0SLisandro Dalcin 
1688698a79b9SLisandro Dalcin     /* Read elements */
16899566063dSJacob Faibussowitsch     PetscCall(GmshReadSection(gmsh, line));
16909566063dSJacob Faibussowitsch     PetscCall(GmshExpect(gmsh, "$Elements", line));
16919566063dSJacob Faibussowitsch     PetscCall(GmshReadElements(gmsh, mesh));
16929566063dSJacob Faibussowitsch     PetscCall(GmshReadEndSection(gmsh, "$EndElements", line));
1693de78e4feSLisandro Dalcin 
16940598e1a2SLisandro Dalcin     /* Read periodic section (OPTIONAL) */
1695698a79b9SLisandro Dalcin     if (periodic) {
16969566063dSJacob Faibussowitsch       PetscCall(GmshReadSection(gmsh, line));
16979566063dSJacob Faibussowitsch       PetscCall(GmshMatch(gmsh, "$Periodic", line, &periodic));
1698ef12879bSLisandro Dalcin     }
1699ef12879bSLisandro Dalcin     if (periodic) {
17009566063dSJacob Faibussowitsch       PetscCall(GmshExpect(gmsh, "$Periodic", line));
17019566063dSJacob Faibussowitsch       PetscCall(GmshReadPeriodic(gmsh, mesh));
17029566063dSJacob Faibussowitsch       PetscCall(GmshReadEndSection(gmsh, "$EndPeriodic", line));
1703698a79b9SLisandro Dalcin     }
1704698a79b9SLisandro Dalcin 
17059566063dSJacob Faibussowitsch     PetscCall(PetscFree(gmsh->wbuf));
17069566063dSJacob Faibussowitsch     PetscCall(PetscFree(gmsh->sbuf));
17079566063dSJacob Faibussowitsch     PetscCall(PetscFree(gmsh->nbuf));
17080598e1a2SLisandro Dalcin 
17090598e1a2SLisandro Dalcin     dim      = mesh->dim;
1710066ea43fSLisandro Dalcin     order    = mesh->order;
17110598e1a2SLisandro Dalcin     numNodes = mesh->numNodes;
17120598e1a2SLisandro Dalcin     numElems = mesh->numElems;
17130598e1a2SLisandro Dalcin     numVerts = mesh->numVerts;
17140598e1a2SLisandro Dalcin     numCells = mesh->numCells;
1715066ea43fSLisandro Dalcin 
1716066ea43fSLisandro Dalcin     {
1717066ea43fSLisandro Dalcin       GmshElement *elemA = mesh->numCells > 0 ? mesh->elements : NULL;
17188e3a54c0SPierre Jolivet       GmshElement *elemB = PetscSafePointerPlusOffset(elemA, mesh->numCells - 1);
1719066ea43fSLisandro Dalcin       int          ptA   = elemA ? GmshCellMap[elemA->cellType].polytope : -1;
1720066ea43fSLisandro Dalcin       int          ptB   = elemB ? GmshCellMap[elemB->cellType].polytope : -1;
1721066ea43fSLisandro Dalcin       isSimplex          = (ptA == GMSH_QUA || ptA == GMSH_HEX) ? PETSC_FALSE : PETSC_TRUE;
1722066ea43fSLisandro Dalcin       isHybrid           = (ptA == ptB) ? PETSC_FALSE : PETSC_TRUE;
1723066ea43fSLisandro Dalcin       hasTetra           = (ptA == GMSH_TET) ? PETSC_TRUE : PETSC_FALSE;
1724066ea43fSLisandro Dalcin     }
1725698a79b9SLisandro Dalcin   }
1726698a79b9SLisandro Dalcin 
172748a46eb9SPierre Jolivet   if (parentviewer) PetscCall(PetscViewerRestoreSubViewer(parentviewer, PETSC_COMM_SELF, &viewer));
1728698a79b9SLisandro Dalcin 
1729066ea43fSLisandro Dalcin   {
1730066ea43fSLisandro Dalcin     int buf[6];
1731698a79b9SLisandro Dalcin 
1732066ea43fSLisandro Dalcin     buf[0] = (int)dim;
1733066ea43fSLisandro Dalcin     buf[1] = (int)order;
1734066ea43fSLisandro Dalcin     buf[2] = periodic;
1735066ea43fSLisandro Dalcin     buf[3] = isSimplex;
1736066ea43fSLisandro Dalcin     buf[4] = isHybrid;
1737066ea43fSLisandro Dalcin     buf[5] = hasTetra;
1738066ea43fSLisandro Dalcin 
17399566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Bcast(buf, 6, MPI_INT, 0, comm));
1740066ea43fSLisandro Dalcin 
1741066ea43fSLisandro Dalcin     dim       = buf[0];
1742066ea43fSLisandro Dalcin     order     = buf[1];
1743066ea43fSLisandro Dalcin     periodic  = buf[2] ? PETSC_TRUE : PETSC_FALSE;
1744066ea43fSLisandro Dalcin     isSimplex = buf[3] ? PETSC_TRUE : PETSC_FALSE;
1745066ea43fSLisandro Dalcin     isHybrid  = buf[4] ? PETSC_TRUE : PETSC_FALSE;
1746066ea43fSLisandro Dalcin     hasTetra  = buf[5] ? PETSC_TRUE : PETSC_FALSE;
1747dea2a3c7SStefano Zampini   }
1748dea2a3c7SStefano Zampini 
1749066ea43fSLisandro Dalcin   if (!highOrderSet) highOrder = (order > 1) ? PETSC_TRUE : PETSC_FALSE;
175008401ef6SPierre Jolivet   PetscCheck(!highOrder || !isHybrid, comm, PETSC_ERR_SUP, "No support for discretization on hybrid meshes yet");
1751066ea43fSLisandro Dalcin 
17520598e1a2SLisandro Dalcin   /* We do not want this label automatically computed, instead we fill it here */
17539566063dSJacob Faibussowitsch   PetscCall(DMCreateLabel(*dm, "celltype"));
175411c56cb0SLisandro Dalcin 
1755a4bb7517SMichael Lange   /* Allocate the cell-vertex mesh */
17569566063dSJacob Faibussowitsch   PetscCall(DMPlexSetChart(*dm, 0, numCells + numVerts));
17570598e1a2SLisandro Dalcin   for (cell = 0; cell < numCells; ++cell) {
17580598e1a2SLisandro Dalcin     GmshElement   *elem  = mesh->elements + cell;
17590598e1a2SLisandro Dalcin     DMPolytopeType ctype = DMPolytopeTypeFromGmsh(elem->cellType);
17600598e1a2SLisandro Dalcin     if (hybrid && hasTetra && ctype == DM_POLYTOPE_TRI_PRISM) ctype = DM_POLYTOPE_TRI_PRISM_TENSOR;
17619566063dSJacob Faibussowitsch     PetscCall(DMPlexSetConeSize(*dm, cell, elem->numVerts));
17629566063dSJacob Faibussowitsch     PetscCall(DMPlexSetCellType(*dm, cell, ctype));
1763db397164SMichael Lange   }
176448a46eb9SPierre Jolivet   for (v = numCells; v < numCells + numVerts; ++v) PetscCall(DMPlexSetCellType(*dm, v, DM_POLYTOPE_POINT));
17659566063dSJacob Faibussowitsch   PetscCall(DMSetUp(*dm));
176696ca5757SLisandro Dalcin 
1767a4bb7517SMichael Lange   /* Add cell-vertex connections */
17680598e1a2SLisandro Dalcin   for (cell = 0; cell < numCells; ++cell) {
17690598e1a2SLisandro Dalcin     GmshElement *elem = mesh->elements + cell;
17700598e1a2SLisandro Dalcin     for (v = 0; v < elem->numVerts; ++v) {
17710598e1a2SLisandro Dalcin       const PetscInt nn = elem->nodes[v];
17720598e1a2SLisandro Dalcin       const PetscInt vv = mesh->vertexMap[nn];
17730598e1a2SLisandro Dalcin       cone[v]           = numCells + vv;
1774db397164SMichael Lange     }
17759566063dSJacob Faibussowitsch     PetscCall(DMPlexReorderCell(*dm, cell, cone));
17769566063dSJacob Faibussowitsch     PetscCall(DMPlexSetCone(*dm, cell, cone));
1777a4bb7517SMichael Lange   }
177896ca5757SLisandro Dalcin 
17799566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(*dm, dim));
17809566063dSJacob Faibussowitsch   PetscCall(DMPlexSymmetrize(*dm));
17819566063dSJacob Faibussowitsch   PetscCall(DMPlexStratify(*dm));
1782331830f3SMatthew G. Knepley   if (interpolate) {
17835fd9971aSMatthew G. Knepley     DM idm;
1784331830f3SMatthew G. Knepley 
17859566063dSJacob Faibussowitsch     PetscCall(DMPlexInterpolate(*dm, &idm));
17869566063dSJacob Faibussowitsch     PetscCall(DMDestroy(dm));
1787331830f3SMatthew G. Knepley     *dm = idm;
1788331830f3SMatthew G. Knepley   }
17899db5b827SMatthew G. Knepley   PetscCall(DMPlexGetDepthStratum(*dm, 0, &vStart, &vEnd));
1790917266a4SLisandro Dalcin 
1791dd400576SPatrick Sanan   if (rank == 0) {
1792a45dabc8SMatthew G. Knepley     const PetscInt Nr = useregions ? mesh->numRegions : 0;
1793d1a54cefSMatthew G. Knepley 
17949566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(Nr, &regionSets));
17950598e1a2SLisandro Dalcin     for (cell = 0, e = 0; e < numElems; ++e) {
17960598e1a2SLisandro Dalcin       GmshElement *elem = mesh->elements + e;
17976e1dd89aSLawrence Mitchell 
17986e1dd89aSLawrence Mitchell       /* Create cell sets */
17990598e1a2SLisandro Dalcin       if (elem->dim == dim && dim > 0) {
18000598e1a2SLisandro Dalcin         if (elem->numTags > 0) {
1801df93260fSMatthew G. Knepley           PetscInt Nt = elem->numTags, t, r;
1802a45dabc8SMatthew G. Knepley 
1803df93260fSMatthew G. Knepley           for (t = 0; t < Nt; ++t) {
1804df93260fSMatthew G. Knepley             const PetscInt  tag     = elem->tags[t];
18052b205333SMatthew G. Knepley             const PetscBool generic = usegeneric && (!t || multipleTags) ? PETSC_TRUE : PETSC_FALSE;
1806df93260fSMatthew G. Knepley 
1807df93260fSMatthew G. Knepley             if (generic) PetscCall(DMSetLabelValue_Fast(*dm, &cellSets, "Cell Sets", cell, tag));
1808a45dabc8SMatthew G. Knepley             for (r = 0; r < Nr; ++r) {
1809df93260fSMatthew G. Knepley               if (mesh->regionDims[r] != dim) continue;
18109566063dSJacob Faibussowitsch               if (mesh->regionTags[r] == tag) PetscCall(DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], cell, tag));
1811a45dabc8SMatthew G. Knepley             }
18126e1dd89aSLawrence Mitchell           }
1813df93260fSMatthew G. Knepley         }
1814917266a4SLisandro Dalcin         cell++;
18156e1dd89aSLawrence Mitchell       }
18160c070f12SSander Arens 
18170598e1a2SLisandro Dalcin       /* Create face sets */
1818aec57b10SMatthew G. Knepley       if (elem->numTags && interpolate && elem->dim == dim - 1) {
18190598e1a2SLisandro Dalcin         PetscInt        joinSize;
18200598e1a2SLisandro Dalcin         const PetscInt *join = NULL;
18210444adf6SMatthew G. Knepley         PetscInt        Nt   = elem->numTags, pdepth;
1822a45dabc8SMatthew G. Knepley 
18230598e1a2SLisandro Dalcin         /* Find the relevant facet with vertex joins */
18240598e1a2SLisandro Dalcin         for (v = 0; v < elem->numVerts; ++v) {
18250598e1a2SLisandro Dalcin           const PetscInt nn = elem->nodes[v];
18260598e1a2SLisandro Dalcin           const PetscInt vv = mesh->vertexMap[nn];
18270598e1a2SLisandro Dalcin           cone[v]           = vStart + vv;
18280598e1a2SLisandro Dalcin         }
18299566063dSJacob Faibussowitsch         PetscCall(DMPlexGetFullJoin(*dm, elem->numVerts, cone, &joinSize, &join));
183063a3b9bcSJacob 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);
18310444adf6SMatthew G. Knepley         PetscCall(DMPlexGetPointDepth(*dm, join[0], &pdepth));
18320444adf6SMatthew 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);
18330444adf6SMatthew G. Knepley         for (PetscInt t = 0; t < Nt; ++t) {
18345ad74b4fSMatthew G. Knepley           const PetscInt  tag     = elem->tags[t];
18352b205333SMatthew G. Knepley           const PetscBool generic = usegeneric && (!t || multipleTags) ? PETSC_TRUE : PETSC_FALSE;
18365ad74b4fSMatthew G. Knepley 
1837df93260fSMatthew G. Knepley           if (generic) PetscCall(DMSetLabelValue_Fast(*dm, &faceSets, "Face Sets", join[0], tag));
18380444adf6SMatthew G. Knepley           for (PetscInt r = 0; r < Nr; ++r) {
1839df93260fSMatthew G. Knepley             if (mesh->regionDims[r] != dim - 1) continue;
18409566063dSJacob Faibussowitsch             if (mesh->regionTags[r] == tag) PetscCall(DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], join[0], tag));
1841a45dabc8SMatthew G. Knepley           }
18425ad74b4fSMatthew G. Knepley         }
18439566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreJoin(*dm, elem->numVerts, cone, &joinSize, &join));
18440598e1a2SLisandro Dalcin       }
18450598e1a2SLisandro Dalcin 
1846aec57b10SMatthew G. Knepley       /* Create edge sets */
1847aec57b10SMatthew G. Knepley       if (elem->numTags && interpolate && dim > 2 && elem->dim == 1) {
1848aec57b10SMatthew G. Knepley         PetscInt        joinSize;
1849aec57b10SMatthew G. Knepley         const PetscInt *join = NULL;
1850aec57b10SMatthew G. Knepley         PetscInt        Nt   = elem->numTags, t, r;
1851aec57b10SMatthew G. Knepley 
1852aec57b10SMatthew G. Knepley         /* Find the relevant edge with vertex joins */
1853aec57b10SMatthew G. Knepley         for (v = 0; v < elem->numVerts; ++v) {
1854aec57b10SMatthew G. Knepley           const PetscInt nn = elem->nodes[v];
1855aec57b10SMatthew G. Knepley           const PetscInt vv = mesh->vertexMap[nn];
1856aec57b10SMatthew G. Knepley           cone[v]           = vStart + vv;
1857aec57b10SMatthew G. Knepley         }
1858aec57b10SMatthew G. Knepley         PetscCall(DMPlexGetJoin(*dm, elem->numVerts, cone, &joinSize, &join));
1859aec57b10SMatthew 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);
1860aec57b10SMatthew G. Knepley         for (t = 0; t < Nt; ++t) {
1861aec57b10SMatthew G. Knepley           const PetscInt  tag     = elem->tags[t];
18622b205333SMatthew G. Knepley           const PetscBool generic = usegeneric && (!t || multipleTags) ? PETSC_TRUE : PETSC_FALSE;
1863aec57b10SMatthew G. Knepley 
18640444adf6SMatthew G. Knepley           if (generic) PetscCall(DMSetLabelValue_Fast(*dm, &edgeSets, "Edge Sets", join[0], tag));
1865aec57b10SMatthew G. Knepley           for (r = 0; r < Nr; ++r) {
1866aec57b10SMatthew G. Knepley             if (mesh->regionDims[r] != 1) continue;
1867aec57b10SMatthew G. Knepley             if (mesh->regionTags[r] == tag) PetscCall(DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], join[0], tag));
1868aec57b10SMatthew G. Knepley           }
1869aec57b10SMatthew G. Knepley         }
1870aec57b10SMatthew G. Knepley         PetscCall(DMPlexRestoreJoin(*dm, elem->numVerts, cone, &joinSize, &join));
1871aec57b10SMatthew G. Knepley       }
1872aec57b10SMatthew G. Knepley 
18730c070f12SSander Arens       /* Create vertex sets */
1874aec57b10SMatthew G. Knepley       if (elem->numTags && elem->dim == 0 && markvertices) {
18750598e1a2SLisandro Dalcin         const PetscInt nn  = elem->nodes[0];
18760598e1a2SLisandro Dalcin         const PetscInt vv  = mesh->vertexMap[nn];
1877a45dabc8SMatthew G. Knepley         const PetscInt tag = elem->tags[0];
1878a45dabc8SMatthew G. Knepley         PetscInt       r;
1879a45dabc8SMatthew G. Knepley 
18808a3d9825SMatthew G. Knepley         if (vv < 0) continue;
18812b205333SMatthew G. Knepley         if (usegeneric) PetscCall(DMSetLabelValue_Fast(*dm, &vertSets, "Vertex Sets", vStart + vv, tag));
188281a1af93SMatthew G. Knepley         for (r = 0; r < Nr; ++r) {
1883df93260fSMatthew G. Knepley           if (mesh->regionDims[r] != 0) continue;
18849566063dSJacob Faibussowitsch           if (mesh->regionTags[r] == tag) PetscCall(DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], vStart + vv, tag));
188581a1af93SMatthew G. Knepley         }
188681a1af93SMatthew G. Knepley       }
188781a1af93SMatthew G. Knepley     }
188881a1af93SMatthew G. Knepley     if (markvertices) {
188981a1af93SMatthew G. Knepley       for (v = 0; v < numNodes; ++v) {
189081a1af93SMatthew G. Knepley         const PetscInt  vv   = mesh->vertexMap[v];
18917d5b9244SMatthew G. Knepley         const PetscInt *tags = &mesh->nodelist->tag[v * GMSH_MAX_TAGS];
18927d5b9244SMatthew G. Knepley         PetscInt        r, t;
189381a1af93SMatthew G. Knepley 
18948a3d9825SMatthew G. Knepley         if (vv < 0) continue;
18957d5b9244SMatthew G. Knepley         for (t = 0; t < GMSH_MAX_TAGS; ++t) {
18967d5b9244SMatthew G. Knepley           const PetscInt  tag     = tags[t];
18972b205333SMatthew G. Knepley           const PetscBool generic = usegeneric && (!t || multipleTags) ? PETSC_TRUE : PETSC_FALSE;
18987d5b9244SMatthew G. Knepley 
18997d5b9244SMatthew G. Knepley           if (tag == -1) continue;
1900df93260fSMatthew G. Knepley           if (generic) PetscCall(DMSetLabelValue_Fast(*dm, &vertSets, "Vertex Sets", vStart + vv, tag));
1901a45dabc8SMatthew G. Knepley           for (r = 0; r < Nr; ++r) {
19029566063dSJacob Faibussowitsch             if (mesh->regionTags[r] == tag) PetscCall(DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], vStart + vv, tag));
19030598e1a2SLisandro Dalcin           }
19040598e1a2SLisandro Dalcin         }
19050598e1a2SLisandro Dalcin       }
19060598e1a2SLisandro Dalcin     }
19079566063dSJacob Faibussowitsch     PetscCall(PetscFree(regionSets));
1908a45dabc8SMatthew G. Knepley   }
19090598e1a2SLisandro Dalcin 
19100444adf6SMatthew G. Knepley   { /* Create Cell/Face/Edge/Vertex Sets labels at all processes */
19119371c9d4SSatish Balay     enum {
19120444adf6SMatthew G. Knepley       n = 5
19139371c9d4SSatish Balay     };
19147dd454faSLisandro Dalcin     PetscBool flag[n];
19157dd454faSLisandro Dalcin 
19167dd454faSLisandro Dalcin     flag[0] = cellSets ? PETSC_TRUE : PETSC_FALSE;
19177dd454faSLisandro Dalcin     flag[1] = faceSets ? PETSC_TRUE : PETSC_FALSE;
19180444adf6SMatthew G. Knepley     flag[2] = edgeSets ? PETSC_TRUE : PETSC_FALSE;
19190444adf6SMatthew G. Knepley     flag[3] = vertSets ? PETSC_TRUE : PETSC_FALSE;
19200444adf6SMatthew G. Knepley     flag[4] = marker ? PETSC_TRUE : PETSC_FALSE;
19219566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Bcast(flag, n, MPIU_BOOL, 0, comm));
19229566063dSJacob Faibussowitsch     if (flag[0]) PetscCall(DMCreateLabel(*dm, "Cell Sets"));
19239566063dSJacob Faibussowitsch     if (flag[1]) PetscCall(DMCreateLabel(*dm, "Face Sets"));
19240444adf6SMatthew G. Knepley     if (flag[2]) PetscCall(DMCreateLabel(*dm, "Edge Sets"));
19250444adf6SMatthew G. Knepley     if (flag[3]) PetscCall(DMCreateLabel(*dm, "Vertex Sets"));
19260444adf6SMatthew G. Knepley     if (flag[4]) PetscCall(DMCreateLabel(*dm, "marker"));
19277dd454faSLisandro Dalcin   }
19287dd454faSLisandro Dalcin 
19290598e1a2SLisandro Dalcin   if (periodic) {
19309566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(numVerts, &periodicVerts));
19310598e1a2SLisandro Dalcin     for (n = 0; n < numNodes; ++n) {
19320598e1a2SLisandro Dalcin       if (mesh->vertexMap[n] >= 0) {
19330598e1a2SLisandro Dalcin         if (PetscUnlikely(mesh->periodMap[n] != n)) {
19340598e1a2SLisandro Dalcin           PetscInt m = mesh->periodMap[n];
19359566063dSJacob Faibussowitsch           PetscCall(PetscBTSet(periodicVerts, mesh->vertexMap[n]));
19369566063dSJacob Faibussowitsch           PetscCall(PetscBTSet(periodicVerts, mesh->vertexMap[m]));
19370598e1a2SLisandro Dalcin         }
19380598e1a2SLisandro Dalcin       }
19390598e1a2SLisandro Dalcin     }
19409db5b827SMatthew G. Knepley     PetscCall(DMGetCoordinateDM(*dm, &cdm));
1941eae3dc7dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxHeight + 1, &periodicCells));
19429db5b827SMatthew G. Knepley     for (PetscInt h = 0; h <= maxHeight; ++h) {
19439db5b827SMatthew G. Knepley       PetscInt pStart, pEnd;
19449db5b827SMatthew G. Knepley 
19459db5b827SMatthew G. Knepley       PetscCall(DMPlexGetHeightStratum(*dm, h, &pStart, &pEnd));
19469db5b827SMatthew G. Knepley       PetscCall(PetscBTCreate(pEnd - pStart, &periodicCells[h]));
19479db5b827SMatthew G. Knepley       for (PetscInt p = pStart; p < pEnd; ++p) {
19489db5b827SMatthew G. Knepley         PetscInt *closure = NULL;
19499db5b827SMatthew G. Knepley         PetscInt  Ncl;
19509db5b827SMatthew G. Knepley 
19519db5b827SMatthew G. Knepley         PetscCall(DMPlexGetTransitiveClosure(*dm, p, PETSC_TRUE, &Ncl, &closure));
19529db5b827SMatthew G. Knepley         for (PetscInt cl = 0; cl < Ncl * 2; cl += 2) {
19539db5b827SMatthew G. Knepley           if (closure[cl] >= vStart && closure[cl] < vEnd) {
19549db5b827SMatthew G. Knepley             if (PetscUnlikely(PetscBTLookup(periodicVerts, closure[cl] - vStart))) {
19559db5b827SMatthew G. Knepley               PetscCall(PetscBTSet(periodicCells[h], p - pStart));
19569371c9d4SSatish Balay               break;
19570c070f12SSander Arens             }
19580c070f12SSander Arens           }
19590c070f12SSander Arens         }
19609db5b827SMatthew G. Knepley         PetscCall(DMPlexRestoreTransitiveClosure(*dm, p, PETSC_TRUE, &Ncl, &closure));
19619db5b827SMatthew G. Knepley       }
19629db5b827SMatthew G. Knepley     }
196316ad7e67SMichael Lange   }
196416ad7e67SMichael Lange 
1965066ea43fSLisandro Dalcin   /* Setup coordinate DM */
19660598e1a2SLisandro Dalcin   if (coordDim < 0) coordDim = dim;
19679566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinateDim(*dm, coordDim));
19689566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(*dm, &cdm));
1969066ea43fSLisandro Dalcin   if (highOrder) {
1970066ea43fSLisandro Dalcin     PetscFE         fe;
1971066ea43fSLisandro Dalcin     PetscBool       continuity = periodic ? PETSC_FALSE : PETSC_TRUE;
1972066ea43fSLisandro Dalcin     PetscDTNodeType nodeType   = PETSCDTNODES_EQUISPACED;
1973066ea43fSLisandro Dalcin 
1974066ea43fSLisandro Dalcin     if (isSimplex) continuity = PETSC_FALSE; /* XXX FIXME Requires DMPlexSetClosurePermutationLexicographic() */
1975066ea43fSLisandro Dalcin 
19769566063dSJacob Faibussowitsch     PetscCall(GmshCreateFE(comm, NULL, isSimplex, continuity, nodeType, dim, coordDim, order, &fe));
19779566063dSJacob Faibussowitsch     PetscCall(PetscFEViewFromOptions(fe, NULL, "-dm_plex_gmsh_fe_view"));
19789566063dSJacob Faibussowitsch     PetscCall(DMSetField(cdm, 0, NULL, (PetscObject)fe));
19799566063dSJacob Faibussowitsch     PetscCall(PetscFEDestroy(&fe));
19809566063dSJacob Faibussowitsch     PetscCall(DMCreateDS(cdm));
1981066ea43fSLisandro Dalcin   }
19826858538eSMatthew G. Knepley   if (periodic) {
19836858538eSMatthew G. Knepley     PetscCall(DMClone(cdm, &cdmCell));
19846858538eSMatthew G. Knepley     PetscCall(DMSetCellCoordinateDM(*dm, cdmCell));
19856858538eSMatthew G. Knepley   }
1986066ea43fSLisandro Dalcin 
1987066ea43fSLisandro Dalcin   /* Create coordinates */
1988066ea43fSLisandro Dalcin   if (highOrder) {
1989066ea43fSLisandro Dalcin     PetscInt     maxDof = GmshNumNodes_HEX(order) * coordDim;
1990066ea43fSLisandro Dalcin     double      *coords = mesh ? mesh->nodelist->xyz : NULL;
1991066ea43fSLisandro Dalcin     PetscSection section;
1992066ea43fSLisandro Dalcin     PetscScalar *cellCoords;
1993066ea43fSLisandro Dalcin 
19949566063dSJacob Faibussowitsch     PetscCall(DMSetLocalSection(cdm, NULL));
19956858538eSMatthew G. Knepley     PetscCall(DMGetLocalSection(cdm, &cs));
19966858538eSMatthew G. Knepley     PetscCall(PetscSectionClone(cs, &section));
19979566063dSJacob Faibussowitsch     PetscCall(DMPlexSetClosurePermutationTensor(cdm, 0, section)); /* XXX Implement DMPlexSetClosurePermutationLexicographic() */
1998066ea43fSLisandro Dalcin 
19999566063dSJacob Faibussowitsch     PetscCall(DMCreateLocalVector(cdm, &coordinates));
20009566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxDof, &cellCoords));
2001066ea43fSLisandro Dalcin     for (cell = 0; cell < numCells; ++cell) {
2002066ea43fSLisandro Dalcin       GmshElement *elem     = mesh->elements + cell;
2003066ea43fSLisandro Dalcin       const int   *lexorder = GmshCellMap[elem->cellType].lexorder();
2004b9bf55e5SMatthew G. Knepley       int          s        = 0;
2005066ea43fSLisandro Dalcin       for (n = 0; n < elem->numNodes; ++n) {
2006b9bf55e5SMatthew G. Knepley         while (lexorder[n + s] < 0) ++s;
2007b9bf55e5SMatthew G. Knepley         const PetscInt node = elem->nodes[lexorder[n + s]];
2008b9bf55e5SMatthew G. Knepley         for (d = 0; d < coordDim; ++d) cellCoords[(n + s) * coordDim + d] = (PetscReal)coords[node * 3 + d];
2009b9bf55e5SMatthew G. Knepley       }
2010b9bf55e5SMatthew G. Knepley       if (s) {
2011b9bf55e5SMatthew G. Knepley         /* For the coordinate mapping we weight vertices by -1/4 and edges by 1/2, which we get from Q_2 interpolation */
2012b9bf55e5SMatthew G. Knepley         PetscReal quaCenterWeights[9] = {-0.25, 0.5, -0.25, 0.5, 0.0, 0.5, -0.25, 0.5, -0.25};
2013b9bf55e5SMatthew G. Knepley         /* For the coordinate mapping we weight vertices by -1/4 and edges by 1/2, which we get from Q_2 interpolation */
20149371c9d4SSatish 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};
20159371c9d4SSatish 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};
20169371c9d4SSatish 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};
20179371c9d4SSatish 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};
20189371c9d4SSatish 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};
20199371c9d4SSatish 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};
20209371c9d4SSatish 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};
2021b9bf55e5SMatthew G. Knepley         PetscReal  *sdWeights2[9]        = {NULL, NULL, NULL, NULL, quaCenterWeights, NULL, NULL, NULL, NULL};
20229371c9d4SSatish Balay         PetscReal  *sdWeights3[27]       = {NULL, NULL, NULL, NULL, hexBottomWeights, NULL, NULL, NULL, NULL, NULL, hexFrontWeights, NULL, hexLeftWeights, hexCenterWeights, hexRightWeights, NULL, hexBackWeights, NULL,
2023b9bf55e5SMatthew G. Knepley                                             NULL, NULL, NULL, NULL, hexTopWeights,    NULL, NULL, NULL, NULL};
2024b9bf55e5SMatthew G. Knepley         PetscReal **sdWeights[4]         = {NULL, NULL, sdWeights2, sdWeights3};
2025b9bf55e5SMatthew G. Knepley 
2026b9bf55e5SMatthew G. Knepley         /* Missing entries in serendipity cell, only works for 8-node quad and 20-node hex */
2027b9bf55e5SMatthew G. Knepley         for (n = 0; n < elem->numNodes + s; ++n) {
2028b9bf55e5SMatthew G. Knepley           if (lexorder[n] >= 0) continue;
2029b9bf55e5SMatthew G. Knepley           for (d = 0; d < coordDim; ++d) cellCoords[n * coordDim + d] = 0.0;
2030b9bf55e5SMatthew G. Knepley           for (int bn = 0; bn < elem->numNodes + s; ++bn) {
2031b9bf55e5SMatthew G. Knepley             if (lexorder[bn] < 0) continue;
2032b9bf55e5SMatthew G. Knepley             const PetscReal *weights = sdWeights[coordDim][n];
2033b9bf55e5SMatthew G. Knepley             const PetscInt   bnode   = elem->nodes[lexorder[bn]];
2034b9bf55e5SMatthew G. Knepley             for (d = 0; d < coordDim; ++d) cellCoords[n * coordDim + d] += weights[bn] * (PetscReal)coords[bnode * 3 + d];
2035b9bf55e5SMatthew G. Knepley           }
2036b9bf55e5SMatthew G. Knepley         }
2037066ea43fSLisandro Dalcin       }
20389566063dSJacob Faibussowitsch       PetscCall(DMPlexVecSetClosure(cdm, section, coordinates, cell, cellCoords, INSERT_VALUES));
2039066ea43fSLisandro Dalcin     }
20409566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&section));
20419566063dSJacob Faibussowitsch     PetscCall(PetscFree(cellCoords));
2042066ea43fSLisandro Dalcin   } else {
2043066ea43fSLisandro Dalcin     PetscInt    *nodeMap;
2044066ea43fSLisandro Dalcin     double      *coords = mesh ? mesh->nodelist->xyz : NULL;
2045066ea43fSLisandro Dalcin     PetscScalar *pointCoords;
2046066ea43fSLisandro Dalcin 
20476858538eSMatthew G. Knepley     PetscCall(DMGetCoordinateSection(*dm, &cs));
20486858538eSMatthew G. Knepley     PetscCall(PetscSectionSetNumFields(cs, 1));
20496858538eSMatthew G. Knepley     PetscCall(PetscSectionSetFieldComponents(cs, 0, coordDim));
20506858538eSMatthew G. Knepley     PetscCall(PetscSectionSetChart(cs, numCells, numCells + numVerts));
20516858538eSMatthew G. Knepley     for (v = numCells; v < numCells + numVerts; ++v) {
20526858538eSMatthew G. Knepley       PetscCall(PetscSectionSetDof(cs, v, coordDim));
20536858538eSMatthew G. Knepley       PetscCall(PetscSectionSetFieldDof(cs, v, 0, coordDim));
2054f45c9589SStefano Zampini     }
20556858538eSMatthew G. Knepley     PetscCall(PetscSectionSetUp(cs));
20566858538eSMatthew G. Knepley 
20576858538eSMatthew G. Knepley     /* We need to localize coordinates on cells */
20580598e1a2SLisandro Dalcin     if (periodic) {
2059*1690c2aeSBarry Smith       PetscInt newStart = PETSC_INT_MAX, newEnd = -1, pStart, pEnd;
20609db5b827SMatthew G. Knepley 
20616858538eSMatthew G. Knepley       PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)cdmCell), &csCell));
20626858538eSMatthew G. Knepley       PetscCall(PetscSectionSetNumFields(csCell, 1));
20636858538eSMatthew G. Knepley       PetscCall(PetscSectionSetFieldComponents(csCell, 0, coordDim));
20649db5b827SMatthew G. Knepley       for (PetscInt h = 0; h <= maxHeight; h++) {
20659db5b827SMatthew G. Knepley         PetscCall(DMPlexGetHeightStratum(cdmCell, h, &pStart, &pEnd));
20669db5b827SMatthew G. Knepley         newStart = PetscMin(newStart, pStart);
20679db5b827SMatthew G. Knepley         newEnd   = PetscMax(newEnd, pEnd);
20689db5b827SMatthew G. Knepley       }
20699db5b827SMatthew G. Knepley       PetscCall(PetscSectionSetChart(csCell, newStart, newEnd));
20709db5b827SMatthew G. Knepley       for (PetscInt h = 0; h <= maxHeight; h++) {
20719db5b827SMatthew G. Knepley         PetscCall(DMPlexGetHeightStratum(cdmCell, h, &pStart, &pEnd));
20729db5b827SMatthew G. Knepley         for (PetscInt p = pStart; p < pEnd; ++p) {
20739db5b827SMatthew G. Knepley           PetscInt *closure = NULL;
20749db5b827SMatthew G. Knepley           PetscInt  Ncl, Nv = 0;
20756858538eSMatthew G. Knepley 
20769db5b827SMatthew G. Knepley           if (PetscUnlikely(PetscBTLookup(periodicCells[h], p - pStart))) {
20779db5b827SMatthew G. Knepley             PetscCall(DMPlexGetTransitiveClosure(*dm, p, PETSC_TRUE, &Ncl, &closure));
20789db5b827SMatthew G. Knepley             for (PetscInt cl = 0; cl < Ncl * 2; cl += 2) {
20799db5b827SMatthew G. Knepley               if (closure[cl] >= vStart && closure[cl] < vEnd) ++Nv;
20809db5b827SMatthew G. Knepley             }
20819db5b827SMatthew G. Knepley             PetscCall(DMPlexRestoreTransitiveClosure(*dm, p, PETSC_TRUE, &Ncl, &closure));
20829db5b827SMatthew G. Knepley             PetscCall(PetscSectionSetDof(csCell, p, Nv * coordDim));
20839db5b827SMatthew G. Knepley             PetscCall(PetscSectionSetFieldDof(csCell, p, 0, Nv * coordDim));
20849db5b827SMatthew G. Knepley           }
2085f45c9589SStefano Zampini         }
2086f45c9589SStefano Zampini       }
20876858538eSMatthew G. Knepley       PetscCall(PetscSectionSetUp(csCell));
20886858538eSMatthew G. Knepley       PetscCall(DMSetCellCoordinateSection(*dm, PETSC_DETERMINE, csCell));
2089f45c9589SStefano Zampini     }
2090066ea43fSLisandro Dalcin 
20919566063dSJacob Faibussowitsch     PetscCall(DMCreateLocalVector(cdm, &coordinates));
20929566063dSJacob Faibussowitsch     PetscCall(VecGetArray(coordinates, &pointCoords));
20936858538eSMatthew G. Knepley     PetscCall(PetscMalloc1(numVerts, &nodeMap));
20946858538eSMatthew G. Knepley     for (n = 0; n < numNodes; n++)
20956858538eSMatthew G. Knepley       if (mesh->vertexMap[n] >= 0) nodeMap[mesh->vertexMap[n]] = n;
20966858538eSMatthew G. Knepley     for (v = 0; v < numVerts; ++v) {
20976858538eSMatthew G. Knepley       PetscInt off, node = nodeMap[v];
20986858538eSMatthew G. Knepley 
20996858538eSMatthew G. Knepley       PetscCall(PetscSectionGetOffset(cs, numCells + v, &off));
21006858538eSMatthew G. Knepley       for (d = 0; d < coordDim; ++d) pointCoords[off + d] = (PetscReal)coords[node * 3 + d];
21016858538eSMatthew G. Knepley     }
21026858538eSMatthew G. Knepley     PetscCall(VecRestoreArray(coordinates, &pointCoords));
21036858538eSMatthew G. Knepley 
21040598e1a2SLisandro Dalcin     if (periodic) {
21059db5b827SMatthew G. Knepley       PetscInt cStart, cEnd;
21069db5b827SMatthew G. Knepley 
21079db5b827SMatthew G. Knepley       PetscCall(DMPlexGetHeightStratum(cdmCell, 0, &cStart, &cEnd));
21086858538eSMatthew G. Knepley       PetscCall(DMCreateLocalVector(cdmCell, &coordinatesCell));
21096858538eSMatthew G. Knepley       PetscCall(VecGetArray(coordinatesCell, &pointCoords));
21109db5b827SMatthew G. Knepley       for (PetscInt c = cStart; c < cEnd; ++c) {
21119db5b827SMatthew G. Knepley         GmshElement *elem    = mesh->elements + c - cStart;
21129db5b827SMatthew G. Knepley         PetscInt    *closure = NULL;
21139db5b827SMatthew G. Knepley         PetscInt     verts[8];
21149db5b827SMatthew G. Knepley         PetscInt     Ncl, Nv = 0;
21159db5b827SMatthew G. Knepley 
21169db5b827SMatthew G. Knepley         for (PetscInt v = 0; v < elem->numVerts; ++v) cone[v] = elem->nodes[v];
21179db5b827SMatthew G. Knepley         PetscCall(DMPlexReorderCell(cdmCell, c, cone));
21189db5b827SMatthew G. Knepley         PetscCall(DMPlexGetTransitiveClosure(cdmCell, c, PETSC_TRUE, &Ncl, &closure));
21199db5b827SMatthew G. Knepley         for (PetscInt cl = 0; cl < Ncl * 2; cl += 2) {
21209db5b827SMatthew G. Knepley           if (closure[cl] >= vStart && closure[cl] < vEnd) verts[Nv++] = closure[cl];
2121331830f3SMatthew G. Knepley         }
21229db5b827SMatthew 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);
21239db5b827SMatthew G. Knepley         for (PetscInt cl = 0; cl < Ncl * 2; cl += 2) {
21249db5b827SMatthew G. Knepley           const PetscInt point = closure[cl];
21259db5b827SMatthew G. Knepley           PetscInt       hStart, h;
21269db5b827SMatthew G. Knepley 
21279db5b827SMatthew G. Knepley           PetscCall(DMPlexGetPointHeight(cdmCell, point, &h));
21289db5b827SMatthew G. Knepley           if (h > maxHeight) continue;
21299db5b827SMatthew G. Knepley           PetscCall(DMPlexGetHeightStratum(cdmCell, h, &hStart, NULL));
21309db5b827SMatthew G. Knepley           if (PetscUnlikely(PetscBTLookup(periodicCells[h], point - hStart))) {
21319db5b827SMatthew G. Knepley             PetscInt *pclosure = NULL;
21329db5b827SMatthew G. Knepley             PetscInt  Npcl, off, v;
21339db5b827SMatthew G. Knepley 
21349db5b827SMatthew G. Knepley             PetscCall(PetscSectionGetOffset(csCell, point, &off));
21359db5b827SMatthew G. Knepley             PetscCall(DMPlexGetTransitiveClosure(cdmCell, point, PETSC_TRUE, &Npcl, &pclosure));
21369db5b827SMatthew G. Knepley             for (PetscInt pcl = 0; pcl < Npcl * 2; pcl += 2) {
21379db5b827SMatthew G. Knepley               if (pclosure[pcl] >= vStart && pclosure[pcl] < vEnd) {
21389db5b827SMatthew G. Knepley                 for (v = 0; v < Nv; ++v)
21399db5b827SMatthew G. Knepley                   if (verts[v] == pclosure[pcl]) break;
21409db5b827SMatthew 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);
21419db5b827SMatthew G. Knepley                 for (PetscInt d = 0; d < coordDim; ++d) pointCoords[off++] = (PetscReal)coords[cone[v] * 3 + d];
21429db5b827SMatthew G. Knepley                 ++v;
21439db5b827SMatthew G. Knepley               }
21449db5b827SMatthew G. Knepley             }
21459db5b827SMatthew G. Knepley             PetscCall(DMPlexRestoreTransitiveClosure(cdmCell, point, PETSC_TRUE, &Npcl, &pclosure));
21469db5b827SMatthew G. Knepley           }
21479db5b827SMatthew G. Knepley         }
21489db5b827SMatthew G. Knepley         PetscCall(DMPlexRestoreTransitiveClosure(cdmCell, c, PETSC_TRUE, &Ncl, &closure));
2149331830f3SMatthew G. Knepley       }
21506858538eSMatthew G. Knepley       PetscCall(VecSetBlockSize(coordinatesCell, coordDim));
21516858538eSMatthew G. Knepley       PetscCall(VecRestoreArray(coordinatesCell, &pointCoords));
21526858538eSMatthew G. Knepley       PetscCall(DMSetCellCoordinatesLocal(*dm, coordinatesCell));
21536858538eSMatthew G. Knepley       PetscCall(VecDestroy(&coordinatesCell));
2154331830f3SMatthew G. Knepley     }
21559db5b827SMatthew G. Knepley     PetscCall(PetscFree(nodeMap));
21566858538eSMatthew G. Knepley     PetscCall(PetscSectionDestroy(&csCell));
21576858538eSMatthew G. Knepley     PetscCall(DMDestroy(&cdmCell));
2158066ea43fSLisandro Dalcin   }
2159066ea43fSLisandro Dalcin 
21609566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
21619566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(coordinates, coordDim));
21629566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinatesLocal(*dm, coordinates));
21639566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&coordinates));
216411c56cb0SLisandro Dalcin 
21659566063dSJacob Faibussowitsch   PetscCall(GmshMeshDestroy(&mesh));
21669566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&periodicVerts));
2167eae3dc7dSJacob Faibussowitsch   if (periodic) {
2168eae3dc7dSJacob Faibussowitsch     for (PetscInt h = 0; h <= maxHeight; ++h) PetscCall(PetscBTDestroy(periodicCells + h));
2169eae3dc7dSJacob Faibussowitsch     PetscCall(PetscFree(periodicCells));
2170eae3dc7dSJacob Faibussowitsch   }
217111c56cb0SLisandro Dalcin 
2172066ea43fSLisandro Dalcin   if (highOrder && project) {
2173066ea43fSLisandro Dalcin     PetscFE         fe;
2174066ea43fSLisandro Dalcin     const char      prefix[]   = "dm_plex_gmsh_project_";
2175066ea43fSLisandro Dalcin     PetscBool       continuity = periodic ? PETSC_FALSE : PETSC_TRUE;
2176066ea43fSLisandro Dalcin     PetscDTNodeType nodeType   = PETSCDTNODES_GAUSSJACOBI;
2177066ea43fSLisandro Dalcin 
2178066ea43fSLisandro Dalcin     if (isSimplex) continuity = PETSC_FALSE; /* XXX FIXME Requires DMPlexSetClosurePermutationLexicographic() */
21799566063dSJacob Faibussowitsch     PetscCall(GmshCreateFE(comm, prefix, isSimplex, continuity, nodeType, dim, coordDim, order, &fe));
21809566063dSJacob Faibussowitsch     PetscCall(PetscFEViewFromOptions(fe, NULL, "-dm_plex_gmsh_project_fe_view"));
2181e44f6aebSMatthew G. Knepley     PetscCall(DMSetCoordinateDisc(*dm, fe, PETSC_TRUE));
21829566063dSJacob Faibussowitsch     PetscCall(PetscFEDestroy(&fe));
2183066ea43fSLisandro Dalcin   }
2184066ea43fSLisandro Dalcin 
21859566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_CreateGmsh, *dm, NULL, NULL, NULL));
21863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2187331830f3SMatthew G. Knepley }
2188