xref: /petsc/src/dm/impls/plex/plexgmsh.c (revision bb3f79421f07d75a645a9cd229e7a2e9f281316b)
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 #define GmshCellEntry(cellType, polytope, dim, order) {cellType, GMSH_##polytope, dim, order, GmshNumNodes_##polytope(1), GmshNumNodes_##polytope(order), GmshLexOrder_##polytope##_##order}
1210598e1a2SLisandro Dalcin 
1220598e1a2SLisandro Dalcin static const GmshCellInfo GmshCellTable[] = {
123066ea43fSLisandro Dalcin   GmshCellEntry(15, VTX, 0, 0),
1240598e1a2SLisandro Dalcin 
1259371c9d4SSatish Balay   GmshCellEntry(1, SEG, 1, 1),   GmshCellEntry(8, SEG, 1, 2),   GmshCellEntry(26, SEG, 1, 3),
1269371c9d4SSatish Balay   GmshCellEntry(27, SEG, 1, 4),  GmshCellEntry(28, SEG, 1, 5),  GmshCellEntry(62, SEG, 1, 6),
1279371c9d4SSatish Balay   GmshCellEntry(63, SEG, 1, 7),  GmshCellEntry(64, SEG, 1, 8),  GmshCellEntry(65, SEG, 1, 9),
128066ea43fSLisandro Dalcin   GmshCellEntry(66, SEG, 1, 10),
1290598e1a2SLisandro Dalcin 
1309371c9d4SSatish Balay   GmshCellEntry(2, TRI, 2, 1),   GmshCellEntry(9, TRI, 2, 2),   GmshCellEntry(21, TRI, 2, 3),
1319371c9d4SSatish Balay   GmshCellEntry(23, TRI, 2, 4),  GmshCellEntry(25, TRI, 2, 5),  GmshCellEntry(42, TRI, 2, 6),
1329371c9d4SSatish Balay   GmshCellEntry(43, TRI, 2, 7),  GmshCellEntry(44, TRI, 2, 8),  GmshCellEntry(45, TRI, 2, 9),
133066ea43fSLisandro Dalcin   GmshCellEntry(46, TRI, 2, 10),
1340598e1a2SLisandro Dalcin 
1359371c9d4SSatish Balay   GmshCellEntry(3, QUA, 2, 1),   GmshCellEntry(10, QUA, 2, 2),  {16, GMSH_QUA, 2, 2, 4, 8,  GmshLexOrder_QUA_2_Serendipity},
1369371c9d4SSatish Balay   GmshCellEntry(36, QUA, 2, 3),  GmshCellEntry(37, QUA, 2, 4),  GmshCellEntry(38, QUA, 2, 5),
1379371c9d4SSatish Balay   GmshCellEntry(47, QUA, 2, 6),  GmshCellEntry(48, QUA, 2, 7),  GmshCellEntry(49, QUA, 2, 8),
1389371c9d4SSatish Balay   GmshCellEntry(50, QUA, 2, 9),  GmshCellEntry(51, QUA, 2, 10),
1390598e1a2SLisandro Dalcin 
1409371c9d4SSatish Balay   GmshCellEntry(4, TET, 3, 1),   GmshCellEntry(11, TET, 3, 2),  GmshCellEntry(29, TET, 3, 3),
1419371c9d4SSatish Balay   GmshCellEntry(30, TET, 3, 4),  GmshCellEntry(31, TET, 3, 5),  GmshCellEntry(71, TET, 3, 6),
1429371c9d4SSatish Balay   GmshCellEntry(72, TET, 3, 7),  GmshCellEntry(73, TET, 3, 8),  GmshCellEntry(74, TET, 3, 9),
143066ea43fSLisandro Dalcin   GmshCellEntry(75, TET, 3, 10),
1440598e1a2SLisandro Dalcin 
1459371c9d4SSatish Balay   GmshCellEntry(5, HEX, 3, 1),   GmshCellEntry(12, HEX, 3, 2),  {17, GMSH_HEX, 3, 2, 8, 20, GmshLexOrder_HEX_2_Serendipity},
1469371c9d4SSatish Balay   GmshCellEntry(92, HEX, 3, 3),  GmshCellEntry(93, HEX, 3, 4),  GmshCellEntry(94, HEX, 3, 5),
1479371c9d4SSatish Balay   GmshCellEntry(95, HEX, 3, 6),  GmshCellEntry(96, HEX, 3, 7),  GmshCellEntry(97, HEX, 3, 8),
1489371c9d4SSatish Balay   GmshCellEntry(98, HEX, 3, 9),  GmshCellEntry(-1, HEX, 3, 10),
1490598e1a2SLisandro Dalcin 
1509371c9d4SSatish Balay   GmshCellEntry(6, PRI, 3, 1),   GmshCellEntry(13, PRI, 3, 2),  GmshCellEntry(90, PRI, 3, 3),
1519371c9d4SSatish Balay   GmshCellEntry(91, PRI, 3, 4),  GmshCellEntry(106, PRI, 3, 5), GmshCellEntry(107, PRI, 3, 6),
1529371c9d4SSatish Balay   GmshCellEntry(108, PRI, 3, 7), GmshCellEntry(109, PRI, 3, 8), GmshCellEntry(110, PRI, 3, 9),
153066ea43fSLisandro Dalcin   GmshCellEntry(-1, PRI, 3, 10),
1540598e1a2SLisandro Dalcin 
1559371c9d4SSatish Balay   GmshCellEntry(7, PYR, 3, 1),   GmshCellEntry(14, PYR, 3, 2),  GmshCellEntry(118, PYR, 3, 3),
1569371c9d4SSatish Balay   GmshCellEntry(119, PYR, 3, 4), GmshCellEntry(120, PYR, 3, 5), GmshCellEntry(121, PYR, 3, 6),
1579371c9d4SSatish Balay   GmshCellEntry(122, PYR, 3, 7), GmshCellEntry(123, PYR, 3, 8), GmshCellEntry(124, PYR, 3, 9),
158066ea43fSLisandro Dalcin   GmshCellEntry(-1, PYR, 3, 10)
1590598e1a2SLisandro Dalcin 
1600598e1a2SLisandro Dalcin #if 0
161066ea43fSLisandro Dalcin   {20, GMSH_TRI, 2, 3, 3,  9, NULL},
162066ea43fSLisandro Dalcin   {18, GMSH_PRI, 3, 2, 6, 15, NULL},
163066ea43fSLisandro Dalcin   {19, GMSH_PYR, 3, 2, 5, 13, NULL},
1640598e1a2SLisandro Dalcin #endif
1650598e1a2SLisandro Dalcin };
1660598e1a2SLisandro Dalcin 
1670598e1a2SLisandro Dalcin static GmshCellInfo GmshCellMap[150];
1680598e1a2SLisandro Dalcin 
169d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshCellInfoSetUp(void)
170d71ae5a4SJacob Faibussowitsch {
1710598e1a2SLisandro Dalcin   size_t           i, n;
1720598e1a2SLisandro Dalcin   static PetscBool called = PETSC_FALSE;
1730598e1a2SLisandro Dalcin 
1740598e1a2SLisandro Dalcin   PetscFunctionBegin;
1754d86920dSPierre Jolivet   if (called) PetscFunctionReturn(PETSC_SUCCESS);
1760598e1a2SLisandro Dalcin   called = PETSC_TRUE;
177dd39110bSPierre Jolivet   n      = PETSC_STATIC_ARRAY_LENGTH(GmshCellMap);
1780598e1a2SLisandro Dalcin   for (i = 0; i < n; ++i) {
1790598e1a2SLisandro Dalcin     GmshCellMap[i].cellType = -1;
180066ea43fSLisandro Dalcin     GmshCellMap[i].polytope = -1;
1810598e1a2SLisandro Dalcin   }
182dd39110bSPierre Jolivet   n = PETSC_STATIC_ARRAY_LENGTH(GmshCellTable);
183066ea43fSLisandro Dalcin   for (i = 0; i < n; ++i) {
184066ea43fSLisandro Dalcin     if (GmshCellTable[i].cellType <= 0) continue;
185066ea43fSLisandro Dalcin     GmshCellMap[GmshCellTable[i].cellType] = GmshCellTable[i];
186066ea43fSLisandro Dalcin   }
1873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1880598e1a2SLisandro Dalcin }
1890598e1a2SLisandro Dalcin 
1909371c9d4SSatish Balay #define GmshCellTypeCheck(ct) \
1919371c9d4SSatish 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_); \
1929371c9d4SSatish Balay                            PetscCheck(GmshCellMap[_ct_].polytope != -1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported Gmsh element type %d", _ct_);)
1930598e1a2SLisandro Dalcin 
1940598e1a2SLisandro Dalcin typedef struct {
195698a79b9SLisandro Dalcin   PetscViewer viewer;
196698a79b9SLisandro Dalcin   int         fileFormat;
197698a79b9SLisandro Dalcin   int         dataSize;
198698a79b9SLisandro Dalcin   PetscBool   binary;
199698a79b9SLisandro Dalcin   PetscBool   byteSwap;
200698a79b9SLisandro Dalcin   size_t      wlen;
201698a79b9SLisandro Dalcin   void       *wbuf;
202698a79b9SLisandro Dalcin   size_t      slen;
203698a79b9SLisandro Dalcin   void       *sbuf;
2040598e1a2SLisandro Dalcin   PetscInt   *nbuf;
2050598e1a2SLisandro Dalcin   PetscInt    nodeStart;
2060598e1a2SLisandro Dalcin   PetscInt    nodeEnd;
20733a088b6SMatthew G. Knepley   PetscInt   *nodeMap;
208698a79b9SLisandro Dalcin } GmshFile;
209de78e4feSLisandro Dalcin 
2106497c311SBarry Smith /*
2116497c311SBarry Smith    Returns an array of count items each with a sizeof(eltsize)
2126497c311SBarry Smith */
2136497c311SBarry Smith static PetscErrorCode GmshBufferGet(GmshFile *gmsh, PetscCount count, size_t eltsize, void *buf)
214d71ae5a4SJacob Faibussowitsch {
215de78e4feSLisandro Dalcin   size_t size = count * eltsize;
21611c56cb0SLisandro Dalcin 
21711c56cb0SLisandro Dalcin   PetscFunctionBegin;
218698a79b9SLisandro Dalcin   if (gmsh->wlen < size) {
2199566063dSJacob Faibussowitsch     PetscCall(PetscFree(gmsh->wbuf));
2209566063dSJacob Faibussowitsch     PetscCall(PetscMalloc(size, &gmsh->wbuf));
221698a79b9SLisandro Dalcin     gmsh->wlen = size;
222de78e4feSLisandro Dalcin   }
223698a79b9SLisandro Dalcin   *(void **)buf = size ? gmsh->wbuf : NULL;
2243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
225de78e4feSLisandro Dalcin }
226de78e4feSLisandro Dalcin 
2276497c311SBarry Smith /*
2286497c311SBarry Smith     Returns an array of count items each with the size determined by the GmshFile
2296497c311SBarry Smith */
2306497c311SBarry Smith static PetscErrorCode GmshBufferSizeGet(GmshFile *gmsh, PetscCount count, void *buf)
231d71ae5a4SJacob Faibussowitsch {
232698a79b9SLisandro Dalcin   size_t dataSize = (size_t)gmsh->dataSize;
233698a79b9SLisandro Dalcin   size_t size     = count * dataSize;
234698a79b9SLisandro Dalcin 
235698a79b9SLisandro Dalcin   PetscFunctionBegin;
236698a79b9SLisandro Dalcin   if (gmsh->slen < size) {
2379566063dSJacob Faibussowitsch     PetscCall(PetscFree(gmsh->sbuf));
2389566063dSJacob Faibussowitsch     PetscCall(PetscMalloc(size, &gmsh->sbuf));
239698a79b9SLisandro Dalcin     gmsh->slen = size;
240698a79b9SLisandro Dalcin   }
241698a79b9SLisandro Dalcin   *(void **)buf = size ? gmsh->sbuf : NULL;
2423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
243698a79b9SLisandro Dalcin }
244698a79b9SLisandro Dalcin 
2456497c311SBarry Smith /*
2466497c311SBarry Smith     Reads an array of count items each with the size determined by the PetscDataType
2476497c311SBarry Smith */
2486497c311SBarry Smith static PetscErrorCode GmshRead(GmshFile *gmsh, void *buf, PetscCount count, PetscDataType dtype)
249d71ae5a4SJacob Faibussowitsch {
2506497c311SBarry Smith   PetscInt icount;
2516497c311SBarry Smith 
252de78e4feSLisandro Dalcin   PetscFunctionBegin;
2536497c311SBarry Smith   PetscCall(PetscIntCast(count, &icount));
2546497c311SBarry Smith   PetscCall(PetscViewerRead(gmsh->viewer, buf, icount, NULL, dtype));
2556497c311SBarry Smith   if (gmsh->byteSwap) PetscCall(PetscByteSwap(buf, dtype, icount));
2563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
257698a79b9SLisandro Dalcin }
258698a79b9SLisandro Dalcin 
2596497c311SBarry Smith static PetscErrorCode GmshReadString(GmshFile *gmsh, char *buf, PetscCount count)
260d71ae5a4SJacob Faibussowitsch {
2616497c311SBarry Smith   PetscInt icount;
2626497c311SBarry Smith 
263698a79b9SLisandro Dalcin   PetscFunctionBegin;
2646497c311SBarry Smith   PetscCall(PetscIntCast(count, &icount));
2656497c311SBarry Smith   PetscCall(PetscViewerRead(gmsh->viewer, buf, icount, NULL, PETSC_STRING));
2663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
267698a79b9SLisandro Dalcin }
268698a79b9SLisandro Dalcin 
269d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshMatch(PETSC_UNUSED GmshFile *gmsh, const char Section[], char line[PETSC_MAX_PATH_LEN], PetscBool *match)
270d71ae5a4SJacob Faibussowitsch {
271d6689ca9SLisandro Dalcin   PetscFunctionBegin;
2729566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(line, Section, match));
2733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
274d6689ca9SLisandro Dalcin }
275d6689ca9SLisandro Dalcin 
276d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshExpect(GmshFile *gmsh, const char Section[], char line[PETSC_MAX_PATH_LEN])
277d71ae5a4SJacob Faibussowitsch {
278d6689ca9SLisandro Dalcin   PetscBool match;
279d6689ca9SLisandro Dalcin 
280d6689ca9SLisandro Dalcin   PetscFunctionBegin;
2819566063dSJacob Faibussowitsch   PetscCall(GmshMatch(gmsh, Section, line, &match));
28200045ab3SPierre Jolivet   PetscCheck(match, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file, expecting %s, not %s", Section, line);
2833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
284d6689ca9SLisandro Dalcin }
285d6689ca9SLisandro Dalcin 
286d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadSection(GmshFile *gmsh, char line[PETSC_MAX_PATH_LEN])
287d71ae5a4SJacob Faibussowitsch {
288d6689ca9SLisandro Dalcin   PetscBool match;
289d6689ca9SLisandro Dalcin 
290d6689ca9SLisandro Dalcin   PetscFunctionBegin;
291d6689ca9SLisandro Dalcin   while (PETSC_TRUE) {
2929566063dSJacob Faibussowitsch     PetscCall(GmshReadString(gmsh, line, 1));
2939566063dSJacob Faibussowitsch     PetscCall(GmshMatch(gmsh, "$Comments", line, &match));
294d6689ca9SLisandro Dalcin     if (!match) break;
295d6689ca9SLisandro Dalcin     while (PETSC_TRUE) {
2969566063dSJacob Faibussowitsch       PetscCall(GmshReadString(gmsh, line, 1));
2979566063dSJacob Faibussowitsch       PetscCall(GmshMatch(gmsh, "$EndComments", line, &match));
298d6689ca9SLisandro Dalcin       if (match) break;
299d6689ca9SLisandro Dalcin     }
300d6689ca9SLisandro Dalcin   }
3013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
302d6689ca9SLisandro Dalcin }
303d6689ca9SLisandro Dalcin 
304d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadEndSection(GmshFile *gmsh, const char EndSection[], char line[PETSC_MAX_PATH_LEN])
305d71ae5a4SJacob Faibussowitsch {
306d6689ca9SLisandro Dalcin   PetscFunctionBegin;
3079566063dSJacob Faibussowitsch   PetscCall(GmshReadString(gmsh, line, 1));
3089566063dSJacob Faibussowitsch   PetscCall(GmshExpect(gmsh, EndSection, line));
3093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
310d6689ca9SLisandro Dalcin }
311d6689ca9SLisandro Dalcin 
3126497c311SBarry Smith /*
3136497c311SBarry Smith      Read into buf[] count number of PetscInt integers (the file storage size may be different than PetscInt)
3146497c311SBarry Smith */
3156497c311SBarry Smith static PetscErrorCode GmshReadPetscInt(GmshFile *gmsh, PetscInt *buf, PetscCount count)
316d71ae5a4SJacob Faibussowitsch {
3176497c311SBarry Smith   PetscCount i;
318698a79b9SLisandro Dalcin   size_t     dataSize = (size_t)gmsh->dataSize;
319698a79b9SLisandro Dalcin 
320698a79b9SLisandro Dalcin   PetscFunctionBegin;
321698a79b9SLisandro Dalcin   if (dataSize == sizeof(PetscInt)) {
3229566063dSJacob Faibussowitsch     PetscCall(GmshRead(gmsh, buf, count, PETSC_INT));
323698a79b9SLisandro Dalcin   } else if (dataSize == sizeof(int)) {
324698a79b9SLisandro Dalcin     int *ibuf = NULL;
3259566063dSJacob Faibussowitsch     PetscCall(GmshBufferSizeGet(gmsh, count, &ibuf));
3269566063dSJacob Faibussowitsch     PetscCall(GmshRead(gmsh, ibuf, count, PETSC_ENUM));
327698a79b9SLisandro Dalcin     for (i = 0; i < count; ++i) buf[i] = (PetscInt)ibuf[i];
328698a79b9SLisandro Dalcin   } else if (dataSize == sizeof(long)) {
329698a79b9SLisandro Dalcin     long *ibuf = NULL;
3309566063dSJacob Faibussowitsch     PetscCall(GmshBufferSizeGet(gmsh, count, &ibuf));
3319566063dSJacob Faibussowitsch     PetscCall(GmshRead(gmsh, ibuf, count, PETSC_LONG));
332698a79b9SLisandro Dalcin     for (i = 0; i < count; ++i) buf[i] = (PetscInt)ibuf[i];
333698a79b9SLisandro Dalcin   } else if (dataSize == sizeof(PetscInt64)) {
334698a79b9SLisandro Dalcin     PetscInt64 *ibuf = NULL;
3359566063dSJacob Faibussowitsch     PetscCall(GmshBufferSizeGet(gmsh, count, &ibuf));
3369566063dSJacob Faibussowitsch     PetscCall(GmshRead(gmsh, ibuf, count, PETSC_INT64));
337698a79b9SLisandro Dalcin     for (i = 0; i < count; ++i) buf[i] = (PetscInt)ibuf[i];
338698a79b9SLisandro Dalcin   }
3393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
340698a79b9SLisandro Dalcin }
341698a79b9SLisandro Dalcin 
3426497c311SBarry Smith /*
3436497c311SBarry Smith      Read into buf[] count number of PetscCount integers  (the file storage size may be different than PetscCount)
3446497c311SBarry Smith */
3456497c311SBarry Smith static PetscErrorCode GmshReadPetscCount(GmshFile *gmsh, PetscCount *buf, PetscCount count)
3466497c311SBarry Smith {
3476497c311SBarry Smith   PetscCount i;
3486497c311SBarry Smith   size_t     dataSize = (size_t)gmsh->dataSize;
3496497c311SBarry Smith 
3506497c311SBarry Smith   PetscFunctionBegin;
3516497c311SBarry Smith   if (dataSize == sizeof(PetscCount)) {
3526497c311SBarry Smith     PetscCall(GmshRead(gmsh, buf, count, PETSC_COUNT));
3536497c311SBarry Smith   } else if (dataSize == sizeof(int)) {
3546497c311SBarry Smith     int *ibuf = NULL;
3556497c311SBarry Smith     PetscCall(GmshBufferSizeGet(gmsh, count, &ibuf));
3566497c311SBarry Smith     PetscCall(GmshRead(gmsh, ibuf, count, PETSC_ENUM));
3576497c311SBarry Smith     for (i = 0; i < count; ++i) buf[i] = (PetscCount)ibuf[i];
3586497c311SBarry Smith   } else if (dataSize == sizeof(long)) {
3596497c311SBarry Smith     long *ibuf = NULL;
3606497c311SBarry Smith     PetscCall(GmshBufferSizeGet(gmsh, count, &ibuf));
3616497c311SBarry Smith     PetscCall(GmshRead(gmsh, ibuf, count, PETSC_LONG));
3626497c311SBarry Smith     for (i = 0; i < count; ++i) buf[i] = (PetscCount)ibuf[i];
3636497c311SBarry Smith   } else if (dataSize == sizeof(PetscInt64)) {
3646497c311SBarry Smith     PetscInt64 *ibuf = NULL;
3656497c311SBarry Smith     PetscCall(GmshBufferSizeGet(gmsh, count, &ibuf));
3666497c311SBarry Smith     PetscCall(GmshRead(gmsh, ibuf, count, PETSC_INT64));
3676497c311SBarry Smith     for (i = 0; i < count; ++i) buf[i] = (PetscCount)ibuf[i];
3686497c311SBarry Smith   }
3696497c311SBarry Smith   PetscFunctionReturn(PETSC_SUCCESS);
3706497c311SBarry Smith }
3716497c311SBarry Smith 
3726497c311SBarry Smith /*
3736497c311SBarry Smith      Read into buf[] count number of PetscEnum integers
3746497c311SBarry Smith */
3756497c311SBarry Smith static PetscErrorCode GmshReadInt(GmshFile *gmsh, int *buf, PetscCount count)
376d71ae5a4SJacob Faibussowitsch {
377698a79b9SLisandro Dalcin   PetscFunctionBegin;
3789566063dSJacob Faibussowitsch   PetscCall(GmshRead(gmsh, buf, count, PETSC_ENUM));
3793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
380698a79b9SLisandro Dalcin }
381698a79b9SLisandro Dalcin 
3826497c311SBarry Smith /*
3836497c311SBarry Smith      Read into buf[] count number of double
3846497c311SBarry Smith */
3856497c311SBarry Smith static PetscErrorCode GmshReadDouble(GmshFile *gmsh, double *buf, PetscCount count)
386d71ae5a4SJacob Faibussowitsch {
387698a79b9SLisandro Dalcin   PetscFunctionBegin;
3889566063dSJacob Faibussowitsch   PetscCall(GmshRead(gmsh, buf, count, PETSC_DOUBLE));
3893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
390de78e4feSLisandro Dalcin }
391de78e4feSLisandro Dalcin 
3929c0edc59SMatthew G. Knepley #define GMSH_MAX_TAGS 16
3937d5b9244SMatthew G. Knepley 
394de78e4feSLisandro Dalcin typedef struct {
3950598e1a2SLisandro Dalcin   PetscInt id;                  /* Entity ID */
3960598e1a2SLisandro Dalcin   PetscInt dim;                 /* Dimension */
397de78e4feSLisandro Dalcin   double   bbox[6];             /* Bounding box */
398de78e4feSLisandro Dalcin   PetscInt numTags;             /* Size of tag array */
3997d5b9244SMatthew G. Knepley   int      tags[GMSH_MAX_TAGS]; /* Tag array */
400de78e4feSLisandro Dalcin } GmshEntity;
401de78e4feSLisandro Dalcin 
402de78e4feSLisandro Dalcin typedef struct {
403730356f6SLisandro Dalcin   GmshEntity *entity[4];
404730356f6SLisandro Dalcin   PetscHMapI  entityMap[4];
405730356f6SLisandro Dalcin } GmshEntities;
406730356f6SLisandro Dalcin 
4076497c311SBarry Smith static PetscErrorCode GmshEntitiesCreate(PetscCount count[4], GmshEntities **entities)
408d71ae5a4SJacob Faibussowitsch {
409730356f6SLisandro Dalcin   PetscFunctionBegin;
4109566063dSJacob Faibussowitsch   PetscCall(PetscNew(entities));
4116497c311SBarry Smith   for (PetscInt dim = 0; dim < 4; ++dim) {
4129566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(count[dim], &(*entities)->entity[dim]));
4139566063dSJacob Faibussowitsch     PetscCall(PetscHMapICreate(&(*entities)->entityMap[dim]));
414730356f6SLisandro Dalcin   }
4153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
416730356f6SLisandro Dalcin }
417730356f6SLisandro Dalcin 
418d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshEntitiesDestroy(GmshEntities **entities)
419d71ae5a4SJacob Faibussowitsch {
4200598e1a2SLisandro Dalcin   PetscInt dim;
4210598e1a2SLisandro Dalcin 
4220598e1a2SLisandro Dalcin   PetscFunctionBegin;
4233ba16761SJacob Faibussowitsch   if (!*entities) PetscFunctionReturn(PETSC_SUCCESS);
4240598e1a2SLisandro Dalcin   for (dim = 0; dim < 4; ++dim) {
4259566063dSJacob Faibussowitsch     PetscCall(PetscFree((*entities)->entity[dim]));
4269566063dSJacob Faibussowitsch     PetscCall(PetscHMapIDestroy(&(*entities)->entityMap[dim]));
4270598e1a2SLisandro Dalcin   }
428f4f49eeaSPierre Jolivet   PetscCall(PetscFree(*entities));
4293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4300598e1a2SLisandro Dalcin }
4310598e1a2SLisandro Dalcin 
432d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshEntitiesAdd(GmshEntities *entities, PetscInt index, PetscInt dim, PetscInt eid, GmshEntity **entity)
433d71ae5a4SJacob Faibussowitsch {
434730356f6SLisandro Dalcin   PetscFunctionBegin;
4359566063dSJacob Faibussowitsch   PetscCall(PetscHMapISet(entities->entityMap[dim], eid, index));
436730356f6SLisandro Dalcin   entities->entity[dim][index].dim = dim;
437730356f6SLisandro Dalcin   entities->entity[dim][index].id  = eid;
438730356f6SLisandro Dalcin   if (entity) *entity = &entities->entity[dim][index];
4393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
440730356f6SLisandro Dalcin }
441730356f6SLisandro Dalcin 
442d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshEntitiesGet(GmshEntities *entities, PetscInt dim, PetscInt eid, GmshEntity **entity)
443d71ae5a4SJacob Faibussowitsch {
444730356f6SLisandro Dalcin   PetscInt index;
445730356f6SLisandro Dalcin 
446730356f6SLisandro Dalcin   PetscFunctionBegin;
4479566063dSJacob Faibussowitsch   PetscCall(PetscHMapIGet(entities->entityMap[dim], eid, &index));
448730356f6SLisandro Dalcin   *entity = &entities->entity[dim][index];
4493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
450730356f6SLisandro Dalcin }
451730356f6SLisandro Dalcin 
4520598e1a2SLisandro Dalcin typedef struct {
4530598e1a2SLisandro Dalcin   PetscInt *id;  /* Node IDs */
4540598e1a2SLisandro Dalcin   double   *xyz; /* Coordinates */
45581a1af93SMatthew G. Knepley   PetscInt *tag; /* Physical tag */
4560598e1a2SLisandro Dalcin } GmshNodes;
4570598e1a2SLisandro Dalcin 
4586497c311SBarry Smith static PetscErrorCode GmshNodesCreate(PetscCount count, GmshNodes **nodes)
459d71ae5a4SJacob Faibussowitsch {
460730356f6SLisandro Dalcin   PetscFunctionBegin;
4619566063dSJacob Faibussowitsch   PetscCall(PetscNew(nodes));
4629566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(count * 1, &(*nodes)->id));
4639566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(count * 3, &(*nodes)->xyz));
4647d5b9244SMatthew G. Knepley   PetscCall(PetscMalloc1(count * GMSH_MAX_TAGS, &(*nodes)->tag));
4653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
466730356f6SLisandro Dalcin }
4670598e1a2SLisandro Dalcin 
468d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshNodesDestroy(GmshNodes **nodes)
469d71ae5a4SJacob Faibussowitsch {
4700598e1a2SLisandro Dalcin   PetscFunctionBegin;
4713ba16761SJacob Faibussowitsch   if (!*nodes) PetscFunctionReturn(PETSC_SUCCESS);
4729566063dSJacob Faibussowitsch   PetscCall(PetscFree((*nodes)->id));
4739566063dSJacob Faibussowitsch   PetscCall(PetscFree((*nodes)->xyz));
4749566063dSJacob Faibussowitsch   PetscCall(PetscFree((*nodes)->tag));
475f4f49eeaSPierre Jolivet   PetscCall(PetscFree(*nodes));
4763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
477730356f6SLisandro Dalcin }
478730356f6SLisandro Dalcin 
479730356f6SLisandro Dalcin typedef struct {
4800598e1a2SLisandro Dalcin   PetscInt  id;                  /* Element ID */
4810598e1a2SLisandro Dalcin   PetscInt  dim;                 /* Dimension */
482de78e4feSLisandro Dalcin   PetscInt  cellType;            /* Cell type */
4830598e1a2SLisandro Dalcin   PetscInt  numVerts;            /* Size of vertex array */
484de78e4feSLisandro Dalcin   PetscInt  numNodes;            /* Size of node array */
4850598e1a2SLisandro Dalcin   PetscInt *nodes;               /* Vertex/Node array */
48681a1af93SMatthew G. Knepley   PetscInt  numTags;             /* Size of physical tag array */
4877d5b9244SMatthew G. Knepley   int       tags[GMSH_MAX_TAGS]; /* Physical tag array */
488de78e4feSLisandro Dalcin } GmshElement;
489de78e4feSLisandro Dalcin 
4906497c311SBarry Smith static PetscErrorCode GmshElementsCreate(PetscCount count, GmshElement **elements)
491d71ae5a4SJacob Faibussowitsch {
4920598e1a2SLisandro Dalcin   PetscFunctionBegin;
4939566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(count, elements));
4943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4950598e1a2SLisandro Dalcin }
4960598e1a2SLisandro Dalcin 
497d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshElementsDestroy(GmshElement **elements)
498d71ae5a4SJacob Faibussowitsch {
4990598e1a2SLisandro Dalcin   PetscFunctionBegin;
5003ba16761SJacob Faibussowitsch   if (!*elements) PetscFunctionReturn(PETSC_SUCCESS);
5019566063dSJacob Faibussowitsch   PetscCall(PetscFree(*elements));
5023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5030598e1a2SLisandro Dalcin }
5040598e1a2SLisandro Dalcin 
5050598e1a2SLisandro Dalcin typedef struct {
5060598e1a2SLisandro Dalcin   PetscInt       dim;
507066ea43fSLisandro Dalcin   PetscInt       order;
5080598e1a2SLisandro Dalcin   GmshEntities  *entities;
5090598e1a2SLisandro Dalcin   PetscInt       numNodes;
5100598e1a2SLisandro Dalcin   GmshNodes     *nodelist;
5110598e1a2SLisandro Dalcin   PetscInt       numElems;
5120598e1a2SLisandro Dalcin   GmshElement   *elements;
5130598e1a2SLisandro Dalcin   PetscInt       numVerts;
5140598e1a2SLisandro Dalcin   PetscInt       numCells;
5150598e1a2SLisandro Dalcin   PetscInt      *periodMap;
5160598e1a2SLisandro Dalcin   PetscInt      *vertexMap;
5170598e1a2SLisandro Dalcin   PetscSegBuffer segbuf;
518a45dabc8SMatthew G. Knepley   PetscInt       numRegions;
51990d778b8SLisandro Dalcin   PetscInt      *regionDims;
520a45dabc8SMatthew G. Knepley   PetscInt      *regionTags;
521a45dabc8SMatthew G. Knepley   char         **regionNames;
5220598e1a2SLisandro Dalcin } GmshMesh;
5230598e1a2SLisandro Dalcin 
524d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshMeshCreate(GmshMesh **mesh)
525d71ae5a4SJacob Faibussowitsch {
5260598e1a2SLisandro Dalcin   PetscFunctionBegin;
5279566063dSJacob Faibussowitsch   PetscCall(PetscNew(mesh));
5289566063dSJacob Faibussowitsch   PetscCall(PetscSegBufferCreate(sizeof(PetscInt), 0, &(*mesh)->segbuf));
5293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5300598e1a2SLisandro Dalcin }
5310598e1a2SLisandro Dalcin 
532d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshMeshDestroy(GmshMesh **mesh)
533d71ae5a4SJacob Faibussowitsch {
534a45dabc8SMatthew G. Knepley   PetscInt r;
5350598e1a2SLisandro Dalcin 
5360598e1a2SLisandro Dalcin   PetscFunctionBegin;
5373ba16761SJacob Faibussowitsch   if (!*mesh) PetscFunctionReturn(PETSC_SUCCESS);
5389566063dSJacob Faibussowitsch   PetscCall(GmshEntitiesDestroy(&(*mesh)->entities));
5399566063dSJacob Faibussowitsch   PetscCall(GmshNodesDestroy(&(*mesh)->nodelist));
5409566063dSJacob Faibussowitsch   PetscCall(GmshElementsDestroy(&(*mesh)->elements));
5419566063dSJacob Faibussowitsch   PetscCall(PetscFree((*mesh)->periodMap));
5429566063dSJacob Faibussowitsch   PetscCall(PetscFree((*mesh)->vertexMap));
5439566063dSJacob Faibussowitsch   PetscCall(PetscSegBufferDestroy(&(*mesh)->segbuf));
5449566063dSJacob Faibussowitsch   for (r = 0; r < (*mesh)->numRegions; ++r) PetscCall(PetscFree((*mesh)->regionNames[r]));
54590d778b8SLisandro Dalcin   PetscCall(PetscFree3((*mesh)->regionDims, (*mesh)->regionTags, (*mesh)->regionNames));
546f4f49eeaSPierre Jolivet   PetscCall(PetscFree(*mesh));
5473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5480598e1a2SLisandro Dalcin }
5490598e1a2SLisandro Dalcin 
550d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadNodes_v22(GmshFile *gmsh, GmshMesh *mesh)
551d71ae5a4SJacob Faibussowitsch {
552698a79b9SLisandro Dalcin   PetscViewer viewer   = gmsh->viewer;
553698a79b9SLisandro Dalcin   PetscBool   byteSwap = gmsh->byteSwap;
554de78e4feSLisandro Dalcin   char        line[PETSC_MAX_PATH_LEN];
5557d5b9244SMatthew G. Knepley   int         n, t, num, nid, snum;
5560598e1a2SLisandro Dalcin   GmshNodes  *nodes;
557de78e4feSLisandro Dalcin 
558de78e4feSLisandro Dalcin   PetscFunctionBegin;
5599566063dSJacob Faibussowitsch   PetscCall(PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING));
560698a79b9SLisandro Dalcin   snum = sscanf(line, "%d", &num);
56108401ef6SPierre Jolivet   PetscCheck(snum == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
5629566063dSJacob Faibussowitsch   PetscCall(GmshNodesCreate(num, &nodes));
5630598e1a2SLisandro Dalcin   mesh->numNodes = num;
5640598e1a2SLisandro Dalcin   mesh->nodelist = nodes;
5650598e1a2SLisandro Dalcin   for (n = 0; n < num; ++n) {
5660598e1a2SLisandro Dalcin     double *xyz = nodes->xyz + n * 3;
5679566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, &nid, 1, NULL, PETSC_ENUM));
5689566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, xyz, 3, NULL, PETSC_DOUBLE));
5699566063dSJacob Faibussowitsch     if (byteSwap) PetscCall(PetscByteSwap(&nid, PETSC_ENUM, 1));
5709566063dSJacob Faibussowitsch     if (byteSwap) PetscCall(PetscByteSwap(xyz, PETSC_DOUBLE, 3));
5710598e1a2SLisandro Dalcin     nodes->id[n] = nid;
5727d5b9244SMatthew G. Knepley     for (t = 0; t < GMSH_MAX_TAGS; ++t) nodes->tag[n * GMSH_MAX_TAGS + t] = -1;
57311c56cb0SLisandro Dalcin   }
5743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
57511c56cb0SLisandro Dalcin }
57611c56cb0SLisandro Dalcin 
577de78e4feSLisandro Dalcin /* Gmsh elements can be of any dimension/co-dimension, so we need to traverse the
578de78e4feSLisandro Dalcin    file contents multiple times to figure out the true number of cells and facets
579de78e4feSLisandro Dalcin    in the given mesh. To make this more efficient we read the file contents only
580de78e4feSLisandro Dalcin    once and store them in memory, while determining the true number of cells. */
581d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadElements_v22(GmshFile *gmsh, GmshMesh *mesh)
582d71ae5a4SJacob Faibussowitsch {
583698a79b9SLisandro Dalcin   PetscViewer  viewer   = gmsh->viewer;
584698a79b9SLisandro Dalcin   PetscBool    binary   = gmsh->binary;
585698a79b9SLisandro Dalcin   PetscBool    byteSwap = gmsh->byteSwap;
586de78e4feSLisandro Dalcin   char         line[PETSC_MAX_PATH_LEN];
5870598e1a2SLisandro Dalcin   int          i, c, p, num, ibuf[1 + 4 + 1000], snum;
5880598e1a2SLisandro Dalcin   int          cellType, numElem, numVerts, numNodes, numTags;
589df032b82SMatthew G. Knepley   GmshElement *elements;
5900598e1a2SLisandro Dalcin   PetscInt    *nodeMap = gmsh->nodeMap;
591df032b82SMatthew G. Knepley 
592df032b82SMatthew G. Knepley   PetscFunctionBegin;
5939566063dSJacob Faibussowitsch   PetscCall(PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING));
594698a79b9SLisandro Dalcin   snum = sscanf(line, "%d", &num);
59508401ef6SPierre Jolivet   PetscCheck(snum == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
5969566063dSJacob Faibussowitsch   PetscCall(GmshElementsCreate(num, &elements));
5970598e1a2SLisandro Dalcin   mesh->numElems = num;
5980598e1a2SLisandro Dalcin   mesh->elements = elements;
599698a79b9SLisandro Dalcin   for (c = 0; c < num;) {
6009566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, ibuf, 3, NULL, PETSC_ENUM));
6019566063dSJacob Faibussowitsch     if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, 3));
6020598e1a2SLisandro Dalcin 
6030598e1a2SLisandro Dalcin     cellType = binary ? ibuf[0] : ibuf[1];
6040598e1a2SLisandro Dalcin     numElem  = binary ? ibuf[1] : 1;
605df032b82SMatthew G. Knepley     numTags  = ibuf[2];
6060598e1a2SLisandro Dalcin 
6079566063dSJacob Faibussowitsch     PetscCall(GmshCellTypeCheck(cellType));
6080598e1a2SLisandro Dalcin     numVerts = GmshCellMap[cellType].numVerts;
6090598e1a2SLisandro Dalcin     numNodes = GmshCellMap[cellType].numNodes;
6100598e1a2SLisandro Dalcin 
611df032b82SMatthew G. Knepley     for (i = 0; i < numElem; ++i, ++c) {
6120598e1a2SLisandro Dalcin       GmshElement *element = elements + c;
6130598e1a2SLisandro Dalcin       const int    off = binary ? 0 : 1, nint = 1 + numTags + numNodes - off;
6140598e1a2SLisandro Dalcin       const int   *id = ibuf, *nodes = ibuf + 1 + numTags, *tags = ibuf + 1;
6159566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, ibuf + off, nint, NULL, PETSC_ENUM));
6169566063dSJacob Faibussowitsch       if (byteSwap) PetscCall(PetscByteSwap(ibuf + off, PETSC_ENUM, nint));
6170598e1a2SLisandro Dalcin       element->id       = id[0];
6180598e1a2SLisandro Dalcin       element->dim      = GmshCellMap[cellType].dim;
6190598e1a2SLisandro Dalcin       element->cellType = cellType;
6200598e1a2SLisandro Dalcin       element->numVerts = numVerts;
6210598e1a2SLisandro Dalcin       element->numNodes = numNodes;
6227d5b9244SMatthew G. Knepley       element->numTags  = PetscMin(numTags, GMSH_MAX_TAGS);
6239566063dSJacob Faibussowitsch       PetscCall(PetscSegBufferGet(mesh->segbuf, (size_t)element->numNodes, &element->nodes));
6240598e1a2SLisandro Dalcin       for (p = 0; p < element->numNodes; p++) element->nodes[p] = nodeMap[nodes[p]];
6250598e1a2SLisandro Dalcin       for (p = 0; p < element->numTags; p++) element->tags[p] = tags[p];
626df032b82SMatthew G. Knepley     }
627df032b82SMatthew G. Knepley   }
6283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
629df032b82SMatthew G. Knepley }
6307d282ae0SMichael Lange 
631de78e4feSLisandro Dalcin /*
632de78e4feSLisandro Dalcin $Entities
633de78e4feSLisandro Dalcin   numPoints(unsigned long) numCurves(unsigned long)
634de78e4feSLisandro Dalcin     numSurfaces(unsigned long) numVolumes(unsigned long)
635de78e4feSLisandro Dalcin   // points
636de78e4feSLisandro Dalcin   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
637de78e4feSLisandro Dalcin     boxMaxX(double) boxMaxY(double) boxMaxZ(double)
638de78e4feSLisandro Dalcin     numPhysicals(unsigned long) phyisicalTag[...](int)
639de78e4feSLisandro Dalcin   ...
640de78e4feSLisandro Dalcin   // curves
641de78e4feSLisandro Dalcin   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
642de78e4feSLisandro Dalcin      boxMaxX(double) boxMaxY(double) boxMaxZ(double)
643de78e4feSLisandro Dalcin      numPhysicals(unsigned long) physicalTag[...](int)
644de78e4feSLisandro Dalcin      numBREPVert(unsigned long) tagBREPVert[...](int)
645de78e4feSLisandro Dalcin   ...
646de78e4feSLisandro Dalcin   // surfaces
647de78e4feSLisandro Dalcin   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
648de78e4feSLisandro Dalcin     boxMaxX(double) boxMaxY(double) boxMaxZ(double)
649de78e4feSLisandro Dalcin     numPhysicals(unsigned long) physicalTag[...](int)
650de78e4feSLisandro Dalcin     numBREPCurve(unsigned long) tagBREPCurve[...](int)
651de78e4feSLisandro Dalcin   ...
652de78e4feSLisandro Dalcin   // volumes
653de78e4feSLisandro Dalcin   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
654de78e4feSLisandro Dalcin     boxMaxX(double) boxMaxY(double) boxMaxZ(double)
655de78e4feSLisandro Dalcin     numPhysicals(unsigned long) physicalTag[...](int)
656de78e4feSLisandro Dalcin     numBREPSurfaces(unsigned long) tagBREPSurfaces[...](int)
657de78e4feSLisandro Dalcin   ...
658de78e4feSLisandro Dalcin $EndEntities
659de78e4feSLisandro Dalcin */
660d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadEntities_v40(GmshFile *gmsh, GmshMesh *mesh)
661d71ae5a4SJacob Faibussowitsch {
662698a79b9SLisandro Dalcin   PetscViewer viewer   = gmsh->viewer;
663698a79b9SLisandro Dalcin   PetscBool   byteSwap = gmsh->byteSwap;
6646497c311SBarry Smith   long        lnum, lbuf[4];
665730356f6SLisandro Dalcin   int         dim, eid, numTags, *ibuf, t;
6666497c311SBarry Smith   PetscCount  index, count[4];
6676497c311SBarry Smith   PetscInt    i, num;
668a5ba3d71SLisandro Dalcin   GmshEntity *entity = NULL;
669de78e4feSLisandro Dalcin 
670de78e4feSLisandro Dalcin   PetscFunctionBegin;
6719566063dSJacob Faibussowitsch   PetscCall(PetscViewerRead(viewer, lbuf, 4, NULL, PETSC_LONG));
6729566063dSJacob Faibussowitsch   if (byteSwap) PetscCall(PetscByteSwap(lbuf, PETSC_LONG, 4));
6736497c311SBarry Smith   for (i = 0; i < 4; ++i) count[i] = (PetscCount)lbuf[i];
6749566063dSJacob Faibussowitsch   PetscCall(GmshEntitiesCreate(count, &mesh->entities));
675de78e4feSLisandro Dalcin   for (dim = 0; dim < 4; ++dim) {
676730356f6SLisandro Dalcin     for (index = 0; index < count[dim]; ++index) {
6779566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, &eid, 1, NULL, PETSC_ENUM));
6789566063dSJacob Faibussowitsch       if (byteSwap) PetscCall(PetscByteSwap(&eid, PETSC_ENUM, 1));
6799566063dSJacob Faibussowitsch       PetscCall(GmshEntitiesAdd(mesh->entities, (PetscInt)index, dim, eid, &entity));
6809566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, entity->bbox, 6, NULL, PETSC_DOUBLE));
6819566063dSJacob Faibussowitsch       if (byteSwap) PetscCall(PetscByteSwap(entity->bbox, PETSC_DOUBLE, 6));
6826497c311SBarry Smith       PetscCall(PetscViewerRead(viewer, &lnum, 1, NULL, PETSC_LONG));
6836497c311SBarry Smith       if (byteSwap) PetscCall(PetscByteSwap(&lnum, PETSC_LONG, 1));
6846497c311SBarry Smith       PetscCall(PetscIntCast(lnum, &num));
6859566063dSJacob Faibussowitsch       PetscCall(GmshBufferGet(gmsh, num, sizeof(int), &ibuf));
6869566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, ibuf, num, NULL, PETSC_ENUM));
6879566063dSJacob Faibussowitsch       if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, num));
6887d5b9244SMatthew G. Knepley       entity->numTags = numTags = (int)PetscMin(num, GMSH_MAX_TAGS);
689de78e4feSLisandro Dalcin       for (t = 0; t < numTags; ++t) entity->tags[t] = ibuf[t];
690de78e4feSLisandro Dalcin       if (dim == 0) continue;
6916497c311SBarry Smith       PetscCall(PetscViewerRead(viewer, &lnum, 1, NULL, PETSC_LONG));
6926497c311SBarry Smith       if (byteSwap) PetscCall(PetscByteSwap(&lnum, PETSC_LONG, 1));
6936497c311SBarry Smith       PetscCall(GmshBufferGet(gmsh, lnum, sizeof(int), &ibuf));
6946497c311SBarry Smith       PetscCall(PetscIntCast(lnum, &num));
6959566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, ibuf, num, NULL, PETSC_ENUM));
6969566063dSJacob Faibussowitsch       if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, num));
697de78e4feSLisandro Dalcin     }
698de78e4feSLisandro Dalcin   }
6993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
700de78e4feSLisandro Dalcin }
701de78e4feSLisandro Dalcin 
702de78e4feSLisandro Dalcin /*
703de78e4feSLisandro Dalcin $Nodes
704de78e4feSLisandro Dalcin   numEntityBlocks(unsigned long) numNodes(unsigned long)
705de78e4feSLisandro Dalcin   tagEntity(int) dimEntity(int) typeNode(int) numNodes(unsigned long)
706de78e4feSLisandro Dalcin     tag(int) x(double) y(double) z(double)
707de78e4feSLisandro Dalcin     ...
708de78e4feSLisandro Dalcin   ...
709de78e4feSLisandro Dalcin $EndNodes
710de78e4feSLisandro Dalcin */
711d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadNodes_v40(GmshFile *gmsh, GmshMesh *mesh)
712d71ae5a4SJacob Faibussowitsch {
713698a79b9SLisandro Dalcin   PetscViewer viewer   = gmsh->viewer;
714698a79b9SLisandro Dalcin   PetscBool   byteSwap = gmsh->byteSwap;
7157d5b9244SMatthew G. Knepley   long        block, node, n, t, numEntityBlocks, numTotalNodes, numNodes;
716de78e4feSLisandro Dalcin   int         info[3], nid;
7170598e1a2SLisandro Dalcin   GmshNodes  *nodes;
718de78e4feSLisandro Dalcin 
719de78e4feSLisandro Dalcin   PetscFunctionBegin;
7209566063dSJacob Faibussowitsch   PetscCall(PetscViewerRead(viewer, &numEntityBlocks, 1, NULL, PETSC_LONG));
7219566063dSJacob Faibussowitsch   if (byteSwap) PetscCall(PetscByteSwap(&numEntityBlocks, PETSC_LONG, 1));
7229566063dSJacob Faibussowitsch   PetscCall(PetscViewerRead(viewer, &numTotalNodes, 1, NULL, PETSC_LONG));
7239566063dSJacob Faibussowitsch   if (byteSwap) PetscCall(PetscByteSwap(&numTotalNodes, PETSC_LONG, 1));
7249566063dSJacob Faibussowitsch   PetscCall(GmshNodesCreate(numTotalNodes, &nodes));
7256497c311SBarry Smith   PetscCall(PetscIntCast(numTotalNodes, &mesh->numNodes));
7260598e1a2SLisandro Dalcin   mesh->nodelist = nodes;
7270598e1a2SLisandro Dalcin   for (n = 0, block = 0; block < numEntityBlocks; ++block) {
7289566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, info, 3, NULL, PETSC_ENUM));
7299566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, &numNodes, 1, NULL, PETSC_LONG));
7309566063dSJacob Faibussowitsch     if (byteSwap) PetscCall(PetscByteSwap(&numNodes, PETSC_LONG, 1));
731698a79b9SLisandro Dalcin     if (gmsh->binary) {
732277f51e8SBarry Smith       size_t   nbytes = sizeof(int) + 3 * sizeof(double);
733da81f932SPierre Jolivet       char    *cbuf   = NULL; /* dummy value to prevent warning from compiler about possible uninitialized value */
7346497c311SBarry Smith       PetscInt icnt;
7356497c311SBarry Smith 
7369566063dSJacob Faibussowitsch       PetscCall(GmshBufferGet(gmsh, numNodes, nbytes, &cbuf));
7376497c311SBarry Smith       PetscCall(PetscIntCast(numNodes * nbytes, &icnt));
7386497c311SBarry Smith       PetscCall(PetscViewerRead(viewer, cbuf, icnt, NULL, PETSC_CHAR));
7390598e1a2SLisandro Dalcin       for (node = 0; node < numNodes; ++node, ++n) {
740de78e4feSLisandro Dalcin         char   *cnid = cbuf + node * nbytes, *cxyz = cnid + sizeof(int);
7410598e1a2SLisandro Dalcin         double *xyz = nodes->xyz + n * 3;
7426497c311SBarry Smith 
7439566063dSJacob Faibussowitsch         if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(cnid, PETSC_ENUM, 1));
7449566063dSJacob Faibussowitsch         if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(cxyz, PETSC_DOUBLE, 3));
7459566063dSJacob Faibussowitsch         PetscCall(PetscMemcpy(&nid, cnid, sizeof(int)));
7469566063dSJacob Faibussowitsch         PetscCall(PetscMemcpy(xyz, cxyz, 3 * sizeof(double)));
7479566063dSJacob Faibussowitsch         if (byteSwap) PetscCall(PetscByteSwap(&nid, PETSC_ENUM, 1));
7489566063dSJacob Faibussowitsch         if (byteSwap) PetscCall(PetscByteSwap(xyz, PETSC_DOUBLE, 3));
7490598e1a2SLisandro Dalcin         nodes->id[n] = nid;
7507d5b9244SMatthew G. Knepley         for (t = 0; t < GMSH_MAX_TAGS; ++t) nodes->tag[n * GMSH_MAX_TAGS + t] = -1;
751de78e4feSLisandro Dalcin       }
752de78e4feSLisandro Dalcin     } else {
7530598e1a2SLisandro Dalcin       for (node = 0; node < numNodes; ++node, ++n) {
7540598e1a2SLisandro Dalcin         double *xyz = nodes->xyz + n * 3;
7556497c311SBarry Smith 
7569566063dSJacob Faibussowitsch         PetscCall(PetscViewerRead(viewer, &nid, 1, NULL, PETSC_ENUM));
7579566063dSJacob Faibussowitsch         PetscCall(PetscViewerRead(viewer, xyz, 3, NULL, PETSC_DOUBLE));
7589566063dSJacob Faibussowitsch         if (byteSwap) PetscCall(PetscByteSwap(&nid, PETSC_ENUM, 1));
7599566063dSJacob Faibussowitsch         if (byteSwap) PetscCall(PetscByteSwap(xyz, PETSC_DOUBLE, 3));
7600598e1a2SLisandro Dalcin         nodes->id[n] = nid;
7617d5b9244SMatthew G. Knepley         for (t = 0; t < GMSH_MAX_TAGS; ++t) nodes->tag[n * GMSH_MAX_TAGS + t] = -1;
762de78e4feSLisandro Dalcin       }
763de78e4feSLisandro Dalcin     }
764de78e4feSLisandro Dalcin   }
7653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
766de78e4feSLisandro Dalcin }
767de78e4feSLisandro Dalcin 
768de78e4feSLisandro Dalcin /*
769de78e4feSLisandro Dalcin $Elements
770de78e4feSLisandro Dalcin   numEntityBlocks(unsigned long) numElements(unsigned long)
771de78e4feSLisandro Dalcin   tagEntity(int) dimEntity(int) typeEle(int) numElements(unsigned long)
772de78e4feSLisandro Dalcin     tag(int) numVert[...](int)
773de78e4feSLisandro Dalcin     ...
774de78e4feSLisandro Dalcin   ...
775de78e4feSLisandro Dalcin $EndElements
776de78e4feSLisandro Dalcin */
777d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadElements_v40(GmshFile *gmsh, GmshMesh *mesh)
778d71ae5a4SJacob Faibussowitsch {
779698a79b9SLisandro Dalcin   PetscViewer  viewer   = gmsh->viewer;
780698a79b9SLisandro Dalcin   PetscBool    byteSwap = gmsh->byteSwap;
781de78e4feSLisandro Dalcin   long         c, block, numEntityBlocks, numTotalElements, elem, numElements;
782de78e4feSLisandro Dalcin   int          p, info[3], *ibuf = NULL;
7830598e1a2SLisandro Dalcin   int          eid, dim, cellType, numVerts, numNodes, numTags;
784a5ba3d71SLisandro Dalcin   GmshEntity  *entity = NULL;
785de78e4feSLisandro Dalcin   GmshElement *elements;
7866497c311SBarry Smith   PetscInt    *nodeMap = gmsh->nodeMap, icnt;
787de78e4feSLisandro Dalcin 
788de78e4feSLisandro Dalcin   PetscFunctionBegin;
7899566063dSJacob Faibussowitsch   PetscCall(PetscViewerRead(viewer, &numEntityBlocks, 1, NULL, PETSC_LONG));
7909566063dSJacob Faibussowitsch   if (byteSwap) PetscCall(PetscByteSwap(&numEntityBlocks, PETSC_LONG, 1));
7919566063dSJacob Faibussowitsch   PetscCall(PetscViewerRead(viewer, &numTotalElements, 1, NULL, PETSC_LONG));
7929566063dSJacob Faibussowitsch   if (byteSwap) PetscCall(PetscByteSwap(&numTotalElements, PETSC_LONG, 1));
7939566063dSJacob Faibussowitsch   PetscCall(GmshElementsCreate(numTotalElements, &elements));
7946497c311SBarry Smith   PetscCall(PetscIntCast(numTotalElements, &mesh->numElems));
7950598e1a2SLisandro Dalcin   mesh->elements = elements;
796de78e4feSLisandro Dalcin   for (c = 0, block = 0; block < numEntityBlocks; ++block) {
7979566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, info, 3, NULL, PETSC_ENUM));
7989566063dSJacob Faibussowitsch     if (byteSwap) PetscCall(PetscByteSwap(info, PETSC_ENUM, 3));
7999371c9d4SSatish Balay     eid      = info[0];
8009371c9d4SSatish Balay     dim      = info[1];
8019371c9d4SSatish Balay     cellType = info[2];
8029566063dSJacob Faibussowitsch     PetscCall(GmshEntitiesGet(mesh->entities, dim, eid, &entity));
8039566063dSJacob Faibussowitsch     PetscCall(GmshCellTypeCheck(cellType));
8040598e1a2SLisandro Dalcin     numVerts = GmshCellMap[cellType].numVerts;
8050598e1a2SLisandro Dalcin     numNodes = GmshCellMap[cellType].numNodes;
8066497c311SBarry Smith     numTags  = (int)entity->numTags;
8079566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, &numElements, 1, NULL, PETSC_LONG));
8089566063dSJacob Faibussowitsch     if (byteSwap) PetscCall(PetscByteSwap(&numElements, PETSC_LONG, 1));
8099566063dSJacob Faibussowitsch     PetscCall(GmshBufferGet(gmsh, (1 + numNodes) * numElements, sizeof(int), &ibuf));
8106497c311SBarry Smith     PetscCall(PetscIntCast((1 + numNodes) * numElements, &icnt));
8116497c311SBarry Smith     PetscCall(PetscViewerRead(viewer, ibuf, icnt, NULL, PETSC_ENUM));
8129566063dSJacob Faibussowitsch     if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, (1 + numNodes) * numElements));
813de78e4feSLisandro Dalcin     for (elem = 0; elem < numElements; ++elem, ++c) {
814de78e4feSLisandro Dalcin       GmshElement *element = elements + c;
8150598e1a2SLisandro Dalcin       const int   *id = ibuf + elem * (1 + numNodes), *nodes = id + 1;
8160598e1a2SLisandro Dalcin       element->id       = id[0];
817de78e4feSLisandro Dalcin       element->dim      = dim;
818de78e4feSLisandro Dalcin       element->cellType = cellType;
8190598e1a2SLisandro Dalcin       element->numVerts = numVerts;
820de78e4feSLisandro Dalcin       element->numNodes = numNodes;
821de78e4feSLisandro Dalcin       element->numTags  = numTags;
8229566063dSJacob Faibussowitsch       PetscCall(PetscSegBufferGet(mesh->segbuf, (size_t)element->numNodes, &element->nodes));
8230598e1a2SLisandro Dalcin       for (p = 0; p < element->numNodes; p++) element->nodes[p] = nodeMap[nodes[p]];
8240598e1a2SLisandro Dalcin       for (p = 0; p < element->numTags; p++) element->tags[p] = entity->tags[p];
825de78e4feSLisandro Dalcin     }
826de78e4feSLisandro Dalcin   }
8273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
828698a79b9SLisandro Dalcin }
829698a79b9SLisandro Dalcin 
830d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadPeriodic_v40(GmshFile *gmsh, PetscInt periodicMap[])
831d71ae5a4SJacob Faibussowitsch {
832698a79b9SLisandro Dalcin   PetscViewer viewer     = gmsh->viewer;
833698a79b9SLisandro Dalcin   int         fileFormat = gmsh->fileFormat;
834698a79b9SLisandro Dalcin   PetscBool   binary     = gmsh->binary;
835698a79b9SLisandro Dalcin   PetscBool   byteSwap   = gmsh->byteSwap;
836698a79b9SLisandro Dalcin   int         numPeriodic, snum, i;
837698a79b9SLisandro Dalcin   char        line[PETSC_MAX_PATH_LEN];
8380598e1a2SLisandro Dalcin   PetscInt   *nodeMap = gmsh->nodeMap;
839698a79b9SLisandro Dalcin 
840698a79b9SLisandro Dalcin   PetscFunctionBegin;
841698a79b9SLisandro Dalcin   if (fileFormat == 22 || !binary) {
8429566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING));
843698a79b9SLisandro Dalcin     snum = sscanf(line, "%d", &numPeriodic);
84408401ef6SPierre Jolivet     PetscCheck(snum == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
845698a79b9SLisandro Dalcin   } else {
8469566063dSJacob Faibussowitsch     PetscCall(PetscViewerRead(viewer, &numPeriodic, 1, NULL, PETSC_ENUM));
8479566063dSJacob Faibussowitsch     if (byteSwap) PetscCall(PetscByteSwap(&numPeriodic, PETSC_ENUM, 1));
848698a79b9SLisandro Dalcin   }
849698a79b9SLisandro Dalcin   for (i = 0; i < numPeriodic; i++) {
8509dddd249SSatish Balay     int    ibuf[3], correspondingDim = -1, correspondingTag = -1, primaryTag = -1, correspondingNode, primaryNode;
851698a79b9SLisandro Dalcin     long   j, nNodes;
852698a79b9SLisandro Dalcin     double affine[16];
853698a79b9SLisandro Dalcin 
854698a79b9SLisandro Dalcin     if (fileFormat == 22 || !binary) {
8559566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, line, 3, NULL, PETSC_STRING));
8569dddd249SSatish Balay       snum = sscanf(line, "%d %d %d", &correspondingDim, &correspondingTag, &primaryTag);
85708401ef6SPierre Jolivet       PetscCheck(snum == 3, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
858698a79b9SLisandro Dalcin     } else {
8599566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, ibuf, 3, NULL, PETSC_ENUM));
8609566063dSJacob Faibussowitsch       if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, 3));
8619371c9d4SSatish Balay       correspondingDim = ibuf[0];
8629371c9d4SSatish Balay       correspondingTag = ibuf[1];
8639371c9d4SSatish Balay       primaryTag       = ibuf[2];
864698a79b9SLisandro Dalcin     }
8659371c9d4SSatish Balay     (void)correspondingDim;
8669371c9d4SSatish Balay     (void)correspondingTag;
8679371c9d4SSatish Balay     (void)primaryTag; /* unused */
868698a79b9SLisandro Dalcin 
869698a79b9SLisandro Dalcin     if (fileFormat == 22 || !binary) {
8709566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING));
871698a79b9SLisandro Dalcin       snum = sscanf(line, "%ld", &nNodes);
8724c500f23SPierre Jolivet       if (snum != 1) { /* discard transformation and try again */
8739566063dSJacob Faibussowitsch         PetscCall(PetscViewerRead(viewer, line, -PETSC_MAX_PATH_LEN, NULL, PETSC_STRING));
8749566063dSJacob Faibussowitsch         PetscCall(PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING));
875698a79b9SLisandro Dalcin         snum = sscanf(line, "%ld", &nNodes);
87608401ef6SPierre Jolivet         PetscCheck(snum == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
877698a79b9SLisandro Dalcin       }
878698a79b9SLisandro Dalcin     } else {
8799566063dSJacob Faibussowitsch       PetscCall(PetscViewerRead(viewer, &nNodes, 1, NULL, PETSC_LONG));
8809566063dSJacob Faibussowitsch       if (byteSwap) PetscCall(PetscByteSwap(&nNodes, PETSC_LONG, 1));
8814c500f23SPierre Jolivet       if (nNodes == -1) { /* discard transformation and try again */
8829566063dSJacob Faibussowitsch         PetscCall(PetscViewerRead(viewer, affine, 16, NULL, PETSC_DOUBLE));
8839566063dSJacob Faibussowitsch         PetscCall(PetscViewerRead(viewer, &nNodes, 1, NULL, PETSC_LONG));
8849566063dSJacob Faibussowitsch         if (byteSwap) PetscCall(PetscByteSwap(&nNodes, PETSC_LONG, 1));
885698a79b9SLisandro Dalcin       }
886698a79b9SLisandro Dalcin     }
887698a79b9SLisandro Dalcin 
888698a79b9SLisandro Dalcin     for (j = 0; j < nNodes; j++) {
889698a79b9SLisandro Dalcin       if (fileFormat == 22 || !binary) {
8909566063dSJacob Faibussowitsch         PetscCall(PetscViewerRead(viewer, line, 2, NULL, PETSC_STRING));
8919dddd249SSatish Balay         snum = sscanf(line, "%d %d", &correspondingNode, &primaryNode);
89208401ef6SPierre Jolivet         PetscCheck(snum == 2, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
893698a79b9SLisandro Dalcin       } else {
8949566063dSJacob Faibussowitsch         PetscCall(PetscViewerRead(viewer, ibuf, 2, NULL, PETSC_ENUM));
8959566063dSJacob Faibussowitsch         if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, 2));
8969371c9d4SSatish Balay         correspondingNode = ibuf[0];
8979371c9d4SSatish Balay         primaryNode       = ibuf[1];
898698a79b9SLisandro Dalcin       }
8999dddd249SSatish Balay       correspondingNode              = (int)nodeMap[correspondingNode];
9009dddd249SSatish Balay       primaryNode                    = (int)nodeMap[primaryNode];
9019dddd249SSatish Balay       periodicMap[correspondingNode] = primaryNode;
902698a79b9SLisandro Dalcin     }
903698a79b9SLisandro Dalcin   }
9043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
905698a79b9SLisandro Dalcin }
906698a79b9SLisandro Dalcin 
9070598e1a2SLisandro Dalcin /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
908698a79b9SLisandro Dalcin $Entities
909698a79b9SLisandro Dalcin   numPoints(size_t) numCurves(size_t)
910698a79b9SLisandro Dalcin     numSurfaces(size_t) numVolumes(size_t)
911698a79b9SLisandro Dalcin   pointTag(int) X(double) Y(double) Z(double)
912698a79b9SLisandro Dalcin     numPhysicalTags(size_t) physicalTag(int) ...
913698a79b9SLisandro Dalcin   ...
914698a79b9SLisandro Dalcin   curveTag(int) minX(double) minY(double) minZ(double)
915698a79b9SLisandro Dalcin     maxX(double) maxY(double) maxZ(double)
916698a79b9SLisandro Dalcin     numPhysicalTags(size_t) physicalTag(int) ...
917698a79b9SLisandro Dalcin     numBoundingPoints(size_t) pointTag(int) ...
918698a79b9SLisandro Dalcin   ...
919698a79b9SLisandro Dalcin   surfaceTag(int) minX(double) minY(double) minZ(double)
920698a79b9SLisandro Dalcin     maxX(double) maxY(double) maxZ(double)
921698a79b9SLisandro Dalcin     numPhysicalTags(size_t) physicalTag(int) ...
922698a79b9SLisandro Dalcin     numBoundingCurves(size_t) curveTag(int) ...
923698a79b9SLisandro Dalcin   ...
924698a79b9SLisandro Dalcin   volumeTag(int) minX(double) minY(double) minZ(double)
925698a79b9SLisandro Dalcin     maxX(double) maxY(double) maxZ(double)
926698a79b9SLisandro Dalcin     numPhysicalTags(size_t) physicalTag(int) ...
927698a79b9SLisandro Dalcin     numBoundngSurfaces(size_t) surfaceTag(int) ...
928698a79b9SLisandro Dalcin   ...
929698a79b9SLisandro Dalcin $EndEntities
930698a79b9SLisandro Dalcin */
931d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadEntities_v41(GmshFile *gmsh, GmshMesh *mesh)
932d71ae5a4SJacob Faibussowitsch {
9336497c311SBarry Smith   PetscCount  count[4], index, numTags;
934698a79b9SLisandro Dalcin   int         dim, eid, *tags = NULL;
935698a79b9SLisandro Dalcin   GmshEntity *entity = NULL;
936698a79b9SLisandro Dalcin 
937698a79b9SLisandro Dalcin   PetscFunctionBegin;
9386497c311SBarry Smith   PetscCall(GmshReadPetscCount(gmsh, count, 4));
9399566063dSJacob Faibussowitsch   PetscCall(GmshEntitiesCreate(count, &mesh->entities));
940698a79b9SLisandro Dalcin   for (dim = 0; dim < 4; ++dim) {
941698a79b9SLisandro Dalcin     for (index = 0; index < count[dim]; ++index) {
9429566063dSJacob Faibussowitsch       PetscCall(GmshReadInt(gmsh, &eid, 1));
9439566063dSJacob Faibussowitsch       PetscCall(GmshEntitiesAdd(mesh->entities, (PetscInt)index, dim, eid, &entity));
9449566063dSJacob Faibussowitsch       PetscCall(GmshReadDouble(gmsh, entity->bbox, (dim == 0) ? 3 : 6));
9456497c311SBarry Smith       PetscCall(GmshReadPetscCount(gmsh, &numTags, 1));
9469566063dSJacob Faibussowitsch       PetscCall(GmshBufferGet(gmsh, numTags, sizeof(int), &tags));
9479566063dSJacob Faibussowitsch       PetscCall(GmshReadInt(gmsh, tags, numTags));
9486497c311SBarry 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);
9496497c311SBarry Smith       PetscCall(PetscIntCast(numTags, &entity->numTags));
9506497c311SBarry Smith       for (PetscInt i = 0; i < entity->numTags; ++i) entity->tags[i] = tags[i];
951698a79b9SLisandro Dalcin       if (dim == 0) continue;
9526497c311SBarry Smith       PetscCall(GmshReadPetscCount(gmsh, &numTags, 1));
9539566063dSJacob Faibussowitsch       PetscCall(GmshBufferGet(gmsh, numTags, sizeof(int), &tags));
9549566063dSJacob Faibussowitsch       PetscCall(GmshReadInt(gmsh, tags, numTags));
95581a1af93SMatthew G. Knepley       /* Currently, we do not save the ids for the bounding entities */
956698a79b9SLisandro Dalcin     }
957698a79b9SLisandro Dalcin   }
9583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
959698a79b9SLisandro Dalcin }
960698a79b9SLisandro Dalcin 
96133a088b6SMatthew G. Knepley /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
962698a79b9SLisandro Dalcin $Nodes
963698a79b9SLisandro Dalcin   numEntityBlocks(size_t) numNodes(size_t)
964698a79b9SLisandro Dalcin     minNodeTag(size_t) maxNodeTag(size_t)
965698a79b9SLisandro Dalcin   entityDim(int) entityTag(int) parametric(int; 0 or 1) numNodesBlock(size_t)
966698a79b9SLisandro Dalcin     nodeTag(size_t)
967698a79b9SLisandro Dalcin     ...
968698a79b9SLisandro Dalcin     x(double) y(double) z(double)
969698a79b9SLisandro Dalcin        < u(double; if parametric and entityDim = 1 or entityDim = 2) >
970698a79b9SLisandro Dalcin        < v(double; if parametric and entityDim = 2) >
971698a79b9SLisandro Dalcin     ...
972698a79b9SLisandro Dalcin   ...
973698a79b9SLisandro Dalcin $EndNodes
974698a79b9SLisandro Dalcin */
975d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadNodes_v41(GmshFile *gmsh, GmshMesh *mesh)
976d71ae5a4SJacob Faibussowitsch {
97781a1af93SMatthew G. Knepley   int         info[3], dim, eid, parametric;
9786497c311SBarry Smith   PetscCount  sizes[4], numEntityBlocks, numNodes, numNodesBlock = 0;
9796497c311SBarry Smith   PetscInt    numTags;
98081a1af93SMatthew G. Knepley   GmshEntity *entity = NULL;
9810598e1a2SLisandro Dalcin   GmshNodes  *nodes;
982698a79b9SLisandro Dalcin 
983698a79b9SLisandro Dalcin   PetscFunctionBegin;
9846497c311SBarry Smith   PetscCall(GmshReadPetscCount(gmsh, sizes, 4));
9859371c9d4SSatish Balay   numEntityBlocks = sizes[0];
9869371c9d4SSatish Balay   numNodes        = sizes[1];
9879566063dSJacob Faibussowitsch   PetscCall(GmshNodesCreate(numNodes, &nodes));
9886497c311SBarry Smith   PetscCall(PetscIntCast(numNodes, &mesh->numNodes));
9890598e1a2SLisandro Dalcin   mesh->nodelist = nodes;
9906497c311SBarry Smith   if (numEntityBlocks && !mesh->entities) PetscCall(PetscInfo(NULL, "File specifies %" PetscCount_FMT " entity blocks, but was missing the $Entities section\n", numEntityBlocks));
9916497c311SBarry Smith   for (PetscCount block = 0, node = 0; block < numEntityBlocks; ++block, node += numNodesBlock) {
9929566063dSJacob Faibussowitsch     PetscCall(GmshReadInt(gmsh, info, 3));
9939371c9d4SSatish Balay     dim        = info[0];
9949371c9d4SSatish Balay     eid        = info[1];
9959371c9d4SSatish Balay     parametric = info[2];
996e43c9757SMatthew G. Knepley     if (mesh->entities) PetscCall(GmshEntitiesGet(mesh->entities, dim, eid, &entity));
997e43c9757SMatthew G. Knepley     numTags = entity ? entity->numTags : 0;
99881a1af93SMatthew G. Knepley     PetscCheck(!parametric, PETSC_COMM_SELF, PETSC_ERR_SUP, "Parametric coordinates not supported");
9996497c311SBarry Smith     PetscCall(GmshReadPetscCount(gmsh, &numNodesBlock, 1));
10006497c311SBarry Smith     PetscCall(GmshReadPetscInt(gmsh, nodes->id + node, numNodesBlock));
10019566063dSJacob Faibussowitsch     PetscCall(GmshReadDouble(gmsh, nodes->xyz + node * 3, numNodesBlock * 3));
10026497c311SBarry Smith     for (PetscCount n = 0; n < numNodesBlock; ++n) {
10037d5b9244SMatthew G. Knepley       PetscInt *tags = &nodes->tag[node * GMSH_MAX_TAGS];
10047d5b9244SMatthew G. Knepley 
10056497c311SBarry Smith       for (PetscInt t = 0; t < numTags; ++t) tags[n * GMSH_MAX_TAGS + t] = entity->tags[t];
10066497c311SBarry Smith       for (PetscInt t = numTags; t < GMSH_MAX_TAGS; ++t) tags[n * GMSH_MAX_TAGS + t] = -1;
10077d5b9244SMatthew G. Knepley     }
1008698a79b9SLisandro Dalcin   }
10096497c311SBarry Smith   PetscCall(PetscIntCast(sizes[2], &gmsh->nodeStart));
10106497c311SBarry Smith   PetscCall(PetscIntCast(sizes[3] + 1, &gmsh->nodeEnd));
10113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1012698a79b9SLisandro Dalcin }
1013698a79b9SLisandro Dalcin 
101433a088b6SMatthew G. Knepley /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
1015698a79b9SLisandro Dalcin $Elements
1016698a79b9SLisandro Dalcin   numEntityBlocks(size_t) numElements(size_t)
1017698a79b9SLisandro Dalcin     minElementTag(size_t) maxElementTag(size_t)
1018698a79b9SLisandro Dalcin   entityDim(int) entityTag(int) elementType(int; see below) numElementsBlock(size_t)
1019698a79b9SLisandro Dalcin     elementTag(size_t) nodeTag(size_t) ...
1020698a79b9SLisandro Dalcin     ...
1021698a79b9SLisandro Dalcin   ...
1022698a79b9SLisandro Dalcin $EndElements
1023698a79b9SLisandro Dalcin */
1024d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadElements_v41(GmshFile *gmsh, GmshMesh *mesh)
1025d71ae5a4SJacob Faibussowitsch {
10260598e1a2SLisandro Dalcin   int          info[3], eid, dim, cellType;
10276497c311SBarry Smith   PetscCount   sizes[4], numEntityBlocks, numElements, numBlockElements, numVerts, numNodes, numTags, block, elem, c, p;
1028698a79b9SLisandro Dalcin   GmshEntity  *entity = NULL;
1029698a79b9SLisandro Dalcin   GmshElement *elements;
10306497c311SBarry Smith   PetscInt    *nodeMap = gmsh->nodeMap, *ibuf = NULL;
1031698a79b9SLisandro Dalcin 
1032698a79b9SLisandro Dalcin   PetscFunctionBegin;
10336497c311SBarry Smith   PetscCall(GmshReadPetscCount(gmsh, sizes, 4));
10349371c9d4SSatish Balay   numEntityBlocks = sizes[0];
10359371c9d4SSatish Balay   numElements     = sizes[1];
10369566063dSJacob Faibussowitsch   PetscCall(GmshElementsCreate(numElements, &elements));
10376497c311SBarry Smith   PetscCall(PetscIntCast(numElements, &mesh->numElems));
10380598e1a2SLisandro Dalcin   mesh->elements = elements;
10396497c311SBarry Smith   if (numEntityBlocks && !mesh->entities) PetscCall(PetscInfo(NULL, "File specifies %" PetscCount_FMT " entity blocks, but was missing the $Entities section\n", numEntityBlocks));
1040698a79b9SLisandro Dalcin   for (c = 0, block = 0; block < numEntityBlocks; ++block) {
10419566063dSJacob Faibussowitsch     PetscCall(GmshReadInt(gmsh, info, 3));
10429371c9d4SSatish Balay     dim      = info[0];
10439371c9d4SSatish Balay     eid      = info[1];
10449371c9d4SSatish Balay     cellType = info[2];
1045e43c9757SMatthew G. Knepley     if (mesh->entities) PetscCall(GmshEntitiesGet(mesh->entities, dim, eid, &entity));
10469566063dSJacob Faibussowitsch     PetscCall(GmshCellTypeCheck(cellType));
10470598e1a2SLisandro Dalcin     numVerts = GmshCellMap[cellType].numVerts;
10480598e1a2SLisandro Dalcin     numNodes = GmshCellMap[cellType].numNodes;
1049e43c9757SMatthew G. Knepley     numTags  = entity ? entity->numTags : 0;
10506497c311SBarry Smith     PetscCall(GmshReadPetscCount(gmsh, &numBlockElements, 1));
10519566063dSJacob Faibussowitsch     PetscCall(GmshBufferGet(gmsh, (1 + numNodes) * numBlockElements, sizeof(PetscInt), &ibuf));
10526497c311SBarry Smith     PetscCall(GmshReadPetscInt(gmsh, ibuf, (1 + numNodes) * numBlockElements));
1053698a79b9SLisandro Dalcin     for (elem = 0; elem < numBlockElements; ++elem, ++c) {
1054698a79b9SLisandro Dalcin       GmshElement    *element = elements + c;
10550598e1a2SLisandro Dalcin       const PetscInt *id = ibuf + elem * (1 + numNodes), *nodes = id + 1;
10566497c311SBarry Smith 
1057698a79b9SLisandro Dalcin       element->id       = id[0];
1058698a79b9SLisandro Dalcin       element->dim      = dim;
1059698a79b9SLisandro Dalcin       element->cellType = cellType;
10606497c311SBarry Smith       PetscCall(PetscIntCast(numVerts, &element->numVerts));
10616497c311SBarry Smith       PetscCall(PetscIntCast(numNodes, &element->numNodes));
10626497c311SBarry Smith       PetscCall(PetscIntCast(numTags, &element->numTags));
10636497c311SBarry Smith       PetscCall(PetscSegBufferGet(mesh->segbuf, element->numNodes, &element->nodes));
10640598e1a2SLisandro Dalcin       for (p = 0; p < element->numNodes; p++) element->nodes[p] = nodeMap[nodes[p]];
10650598e1a2SLisandro Dalcin       for (p = 0; p < element->numTags; p++) element->tags[p] = entity->tags[p];
1066698a79b9SLisandro Dalcin     }
1067698a79b9SLisandro Dalcin   }
10683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1069698a79b9SLisandro Dalcin }
1070698a79b9SLisandro Dalcin 
10710598e1a2SLisandro Dalcin /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
1072698a79b9SLisandro Dalcin $Periodic
1073698a79b9SLisandro Dalcin   numPeriodicLinks(size_t)
10749dddd249SSatish Balay   entityDim(int) entityTag(int) entityTagPrimary(int)
1075698a79b9SLisandro Dalcin   numAffine(size_t) value(double) ...
1076698a79b9SLisandro Dalcin   numCorrespondingNodes(size_t)
10779dddd249SSatish Balay     nodeTag(size_t) nodeTagPrimary(size_t)
1078698a79b9SLisandro Dalcin     ...
1079698a79b9SLisandro Dalcin   ...
1080698a79b9SLisandro Dalcin $EndPeriodic
1081698a79b9SLisandro Dalcin */
1082d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadPeriodic_v41(GmshFile *gmsh, PetscInt periodicMap[])
1083d71ae5a4SJacob Faibussowitsch {
1084698a79b9SLisandro Dalcin   int        info[3];
1085698a79b9SLisandro Dalcin   double     dbuf[16];
10866497c311SBarry Smith   PetscCount numPeriodicLinks, numAffine, numCorrespondingNodes;
10876497c311SBarry Smith   PetscInt  *nodeMap = gmsh->nodeMap, *nodeTags = NULL;
1088698a79b9SLisandro Dalcin 
1089698a79b9SLisandro Dalcin   PetscFunctionBegin;
10906497c311SBarry Smith   PetscCall(GmshReadPetscCount(gmsh, &numPeriodicLinks, 1));
10916497c311SBarry Smith   for (PetscCount link = 0; link < numPeriodicLinks; ++link) {
10929566063dSJacob Faibussowitsch     PetscCall(GmshReadInt(gmsh, info, 3));
10936497c311SBarry Smith     PetscCall(GmshReadPetscCount(gmsh, &numAffine, 1));
10949566063dSJacob Faibussowitsch     PetscCall(GmshReadDouble(gmsh, dbuf, numAffine));
10956497c311SBarry Smith     PetscCall(GmshReadPetscCount(gmsh, &numCorrespondingNodes, 1));
10969566063dSJacob Faibussowitsch     PetscCall(GmshBufferGet(gmsh, numCorrespondingNodes, sizeof(PetscInt), &nodeTags));
10976497c311SBarry Smith     PetscCall(GmshReadPetscInt(gmsh, nodeTags, numCorrespondingNodes * 2));
10986497c311SBarry Smith     for (PetscCount node = 0; node < numCorrespondingNodes; ++node) {
10999dddd249SSatish Balay       PetscInt correspondingNode = nodeMap[nodeTags[node * 2 + 0]];
11009dddd249SSatish Balay       PetscInt primaryNode       = nodeMap[nodeTags[node * 2 + 1]];
11016497c311SBarry Smith 
11029dddd249SSatish Balay       periodicMap[correspondingNode] = primaryNode;
1103698a79b9SLisandro Dalcin     }
1104698a79b9SLisandro Dalcin   }
11053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1106698a79b9SLisandro Dalcin }
1107698a79b9SLisandro Dalcin 
11080598e1a2SLisandro Dalcin /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
1109d6689ca9SLisandro Dalcin $MeshFormat // same as MSH version 2
1110d6689ca9SLisandro Dalcin   version(ASCII double; currently 4.1)
1111d6689ca9SLisandro Dalcin   file-type(ASCII int; 0 for ASCII mode, 1 for binary mode)
1112d6689ca9SLisandro Dalcin   data-size(ASCII int; sizeof(size_t))
1113d6689ca9SLisandro Dalcin   < int with value one; only in binary mode, to detect endianness >
1114d6689ca9SLisandro Dalcin $EndMeshFormat
1115d6689ca9SLisandro Dalcin */
1116d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadMeshFormat(GmshFile *gmsh)
1117d71ae5a4SJacob Faibussowitsch {
1118698a79b9SLisandro Dalcin   char  line[PETSC_MAX_PATH_LEN];
1119698a79b9SLisandro Dalcin   int   snum, fileType, fileFormat, dataSize, checkEndian;
1120698a79b9SLisandro Dalcin   float version;
1121698a79b9SLisandro Dalcin 
1122698a79b9SLisandro Dalcin   PetscFunctionBegin;
11239566063dSJacob Faibussowitsch   PetscCall(GmshReadString(gmsh, line, 3));
1124698a79b9SLisandro Dalcin   snum       = sscanf(line, "%f %d %d", &version, &fileType, &dataSize);
1125a8d4e440SJunchao Zhang   fileFormat = (int)roundf(version * 10);
112608401ef6SPierre Jolivet   PetscCheck(snum == 3, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to parse Gmsh file header: %s", line);
1127a8d4e440SJunchao Zhang   PetscCheck(fileFormat >= 22, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at least 2.2", (double)version);
11281dca8a05SBarry Smith   PetscCheck((int)version != 3, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f not supported", (double)version);
1129a8d4e440SJunchao Zhang   PetscCheck(fileFormat <= 41, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at most 4.1", (double)version);
113008401ef6SPierre Jolivet   PetscCheck(!gmsh->binary || fileType, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Viewer is binary but Gmsh file is ASCII");
113108401ef6SPierre Jolivet   PetscCheck(gmsh->binary || !fileType, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Viewer is ASCII but Gmsh file is binary");
11321dca8a05SBarry 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);
11331dca8a05SBarry 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);
1134698a79b9SLisandro Dalcin   gmsh->fileFormat = fileFormat;
1135698a79b9SLisandro Dalcin   gmsh->dataSize   = dataSize;
1136698a79b9SLisandro Dalcin   gmsh->byteSwap   = PETSC_FALSE;
1137698a79b9SLisandro Dalcin   if (gmsh->binary) {
11389566063dSJacob Faibussowitsch     PetscCall(GmshReadInt(gmsh, &checkEndian, 1));
1139698a79b9SLisandro Dalcin     if (checkEndian != 1) {
11409566063dSJacob Faibussowitsch       PetscCall(PetscByteSwap(&checkEndian, PETSC_ENUM, 1));
114108401ef6SPierre Jolivet       PetscCheck(checkEndian == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to detect endianness in Gmsh file header: %s", line);
1142698a79b9SLisandro Dalcin       gmsh->byteSwap = PETSC_TRUE;
1143698a79b9SLisandro Dalcin     }
1144698a79b9SLisandro Dalcin   }
11453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1146698a79b9SLisandro Dalcin }
1147698a79b9SLisandro Dalcin 
11488749820aSMatthew G. Knepley /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
11498749820aSMatthew G. Knepley Neper: https://neper.info/ adds this section
11508749820aSMatthew G. Knepley 
11518749820aSMatthew G. Knepley $MeshVersion
11528749820aSMatthew G. Knepley   <major>.<minor>,<patch>
11538749820aSMatthew G. Knepley $EndMeshVersion
11548749820aSMatthew G. Knepley */
11558749820aSMatthew G. Knepley static PetscErrorCode GmshReadMeshVersion(GmshFile *gmsh)
11568749820aSMatthew G. Knepley {
11578749820aSMatthew G. Knepley   char line[PETSC_MAX_PATH_LEN];
11588749820aSMatthew G. Knepley   int  snum, major, minor, patch;
11598749820aSMatthew G. Knepley 
11608749820aSMatthew G. Knepley   PetscFunctionBegin;
11618749820aSMatthew G. Knepley   PetscCall(GmshReadString(gmsh, line, 1));
11628749820aSMatthew G. Knepley   snum = sscanf(line, "%d.%d.%d", &major, &minor, &patch);
11638749820aSMatthew G. Knepley   PetscCheck(snum == 3, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to parse Gmsh file header: %s", line);
11648749820aSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
11658749820aSMatthew G. Knepley }
11668749820aSMatthew G. Knepley 
11678749820aSMatthew G. Knepley /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
11688749820aSMatthew G. Knepley Neper: https://neper.info/ adds this section
11698749820aSMatthew G. Knepley 
11708749820aSMatthew G. Knepley $Domain
11718749820aSMatthew G. Knepley   <shape>
11728749820aSMatthew G. Knepley $EndDomain
11738749820aSMatthew G. Knepley */
11748749820aSMatthew G. Knepley static PetscErrorCode GmshReadMeshDomain(GmshFile *gmsh)
11758749820aSMatthew G. Knepley {
11768749820aSMatthew G. Knepley   char line[PETSC_MAX_PATH_LEN];
11778749820aSMatthew G. Knepley 
11788749820aSMatthew G. Knepley   PetscFunctionBegin;
11798749820aSMatthew G. Knepley   PetscCall(GmshReadString(gmsh, line, 1));
11808749820aSMatthew G. Knepley   PetscFunctionReturn(PETSC_SUCCESS);
11818749820aSMatthew G. Knepley }
11828749820aSMatthew G. Knepley 
11831f643af3SLisandro Dalcin /*
11841f643af3SLisandro Dalcin PhysicalNames
11851f643af3SLisandro Dalcin   numPhysicalNames(ASCII int)
11861f643af3SLisandro Dalcin   dimension(ASCII int) physicalTag(ASCII int) "name"(127 characters max)
11871f643af3SLisandro Dalcin   ...
11881f643af3SLisandro Dalcin $EndPhysicalNames
11891f643af3SLisandro Dalcin */
1190d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadPhysicalNames(GmshFile *gmsh, GmshMesh *mesh)
1191d71ae5a4SJacob Faibussowitsch {
1192bbcf679cSJacob Faibussowitsch   char line[PETSC_MAX_PATH_LEN], name[128 + 2], *p = NULL, *q = NULL, *r = NULL;
1193a45dabc8SMatthew G. Knepley   int  snum, region, dim, tag;
1194698a79b9SLisandro Dalcin 
1195698a79b9SLisandro Dalcin   PetscFunctionBegin;
11969566063dSJacob Faibussowitsch   PetscCall(GmshReadString(gmsh, line, 1));
1197a45dabc8SMatthew G. Knepley   snum             = sscanf(line, "%d", &region);
1198a45dabc8SMatthew G. Knepley   mesh->numRegions = region;
119908401ef6SPierre Jolivet   PetscCheck(snum == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
120090d778b8SLisandro Dalcin   PetscCall(PetscMalloc3(mesh->numRegions, &mesh->regionDims, mesh->numRegions, &mesh->regionTags, mesh->numRegions, &mesh->regionNames));
1201a45dabc8SMatthew G. Knepley   for (region = 0; region < mesh->numRegions; ++region) {
12029566063dSJacob Faibussowitsch     PetscCall(GmshReadString(gmsh, line, 2));
12031f643af3SLisandro Dalcin     snum = sscanf(line, "%d %d", &dim, &tag);
120408401ef6SPierre Jolivet     PetscCheck(snum == 2, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
12059566063dSJacob Faibussowitsch     PetscCall(GmshReadString(gmsh, line, -(PetscInt)sizeof(line)));
12069566063dSJacob Faibussowitsch     PetscCall(PetscStrchr(line, '"', &p));
120728b400f6SJacob Faibussowitsch     PetscCheck(p, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
12089566063dSJacob Faibussowitsch     PetscCall(PetscStrrchr(line, '"', &q));
120908401ef6SPierre Jolivet     PetscCheck(q != p, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
12105f5cd6d5SMatthew G. Knepley     PetscCall(PetscStrrchr(line, ':', &r));
12115f5cd6d5SMatthew G. Knepley     if (p != r) q = r;
12129566063dSJacob Faibussowitsch     PetscCall(PetscStrncpy(name, p + 1, (size_t)(q - p - 1)));
121390d778b8SLisandro Dalcin     mesh->regionDims[region] = dim;
1214a45dabc8SMatthew G. Knepley     mesh->regionTags[region] = tag;
12159566063dSJacob Faibussowitsch     PetscCall(PetscStrallocpy(name, &mesh->regionNames[region]));
1216698a79b9SLisandro Dalcin   }
12173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1218de78e4feSLisandro Dalcin }
1219de78e4feSLisandro Dalcin 
1220d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadEntities(GmshFile *gmsh, GmshMesh *mesh)
1221d71ae5a4SJacob Faibussowitsch {
12220598e1a2SLisandro Dalcin   PetscFunctionBegin;
12230598e1a2SLisandro Dalcin   switch (gmsh->fileFormat) {
1224d71ae5a4SJacob Faibussowitsch   case 41:
1225d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadEntities_v41(gmsh, mesh));
1226d71ae5a4SJacob Faibussowitsch     break;
1227d71ae5a4SJacob Faibussowitsch   default:
1228d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadEntities_v40(gmsh, mesh));
1229d71ae5a4SJacob Faibussowitsch     break;
123096ca5757SLisandro Dalcin   }
12313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12320598e1a2SLisandro Dalcin }
12330598e1a2SLisandro Dalcin 
1234d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadNodes(GmshFile *gmsh, GmshMesh *mesh)
1235d71ae5a4SJacob Faibussowitsch {
12360598e1a2SLisandro Dalcin   PetscFunctionBegin;
12370598e1a2SLisandro Dalcin   switch (gmsh->fileFormat) {
1238d71ae5a4SJacob Faibussowitsch   case 41:
1239d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadNodes_v41(gmsh, mesh));
1240d71ae5a4SJacob Faibussowitsch     break;
1241d71ae5a4SJacob Faibussowitsch   case 40:
1242d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadNodes_v40(gmsh, mesh));
1243d71ae5a4SJacob Faibussowitsch     break;
1244d71ae5a4SJacob Faibussowitsch   default:
1245d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadNodes_v22(gmsh, mesh));
1246d71ae5a4SJacob Faibussowitsch     break;
12470598e1a2SLisandro Dalcin   }
12480598e1a2SLisandro Dalcin 
12490598e1a2SLisandro Dalcin   { /* Gmsh v2.2/v4.0 does not provide min/max node tags */
12500598e1a2SLisandro Dalcin     if (mesh->numNodes > 0 && gmsh->nodeEnd >= gmsh->nodeStart) {
12511690c2aeSBarry Smith       PetscInt   tagMin = PETSC_INT_MAX, tagMax = PETSC_INT_MIN, n;
12520598e1a2SLisandro Dalcin       GmshNodes *nodes = mesh->nodelist;
12530598e1a2SLisandro Dalcin       for (n = 0; n < mesh->numNodes; ++n) {
12540598e1a2SLisandro Dalcin         const PetscInt tag = nodes->id[n];
12550598e1a2SLisandro Dalcin         tagMin             = PetscMin(tag, tagMin);
12560598e1a2SLisandro Dalcin         tagMax             = PetscMax(tag, tagMax);
12570598e1a2SLisandro Dalcin       }
12580598e1a2SLisandro Dalcin       gmsh->nodeStart = tagMin;
12590598e1a2SLisandro Dalcin       gmsh->nodeEnd   = tagMax + 1;
12600598e1a2SLisandro Dalcin     }
12610598e1a2SLisandro Dalcin   }
12620598e1a2SLisandro Dalcin 
12630598e1a2SLisandro Dalcin   { /* Support for sparse node tags */
12640598e1a2SLisandro Dalcin     PetscInt   n, t;
12650598e1a2SLisandro Dalcin     GmshNodes *nodes = mesh->nodelist;
12669566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(gmsh->nodeEnd - gmsh->nodeStart, &gmsh->nbuf));
12671690c2aeSBarry Smith     for (t = 0; t < gmsh->nodeEnd - gmsh->nodeStart; ++t) gmsh->nbuf[t] = PETSC_INT_MIN;
12680598e1a2SLisandro Dalcin     gmsh->nodeMap = gmsh->nbuf - gmsh->nodeStart;
12690598e1a2SLisandro Dalcin     for (n = 0; n < mesh->numNodes; ++n) {
12700598e1a2SLisandro Dalcin       const PetscInt tag = nodes->id[n];
127163a3b9bcSJacob Faibussowitsch       PetscCheck(gmsh->nodeMap[tag] < 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Repeated node tag %" PetscInt_FMT, tag);
12720598e1a2SLisandro Dalcin       gmsh->nodeMap[tag] = n;
12730598e1a2SLisandro Dalcin     }
12740598e1a2SLisandro Dalcin   }
12753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12760598e1a2SLisandro Dalcin }
12770598e1a2SLisandro Dalcin 
1278d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadElements(GmshFile *gmsh, GmshMesh *mesh)
1279d71ae5a4SJacob Faibussowitsch {
12800598e1a2SLisandro Dalcin   PetscFunctionBegin;
12810598e1a2SLisandro Dalcin   switch (gmsh->fileFormat) {
1282d71ae5a4SJacob Faibussowitsch   case 41:
1283d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadElements_v41(gmsh, mesh));
1284d71ae5a4SJacob Faibussowitsch     break;
1285d71ae5a4SJacob Faibussowitsch   case 40:
1286d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadElements_v40(gmsh, mesh));
1287d71ae5a4SJacob Faibussowitsch     break;
1288d71ae5a4SJacob Faibussowitsch   default:
1289d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadElements_v22(gmsh, mesh));
1290d71ae5a4SJacob Faibussowitsch     break;
12910598e1a2SLisandro Dalcin   }
12920598e1a2SLisandro Dalcin 
12930598e1a2SLisandro Dalcin   { /* Reorder elements by codimension and polytope type */
12940598e1a2SLisandro Dalcin     PetscInt     ne       = mesh->numElems;
12950598e1a2SLisandro Dalcin     GmshElement *elements = mesh->elements;
1296066ea43fSLisandro Dalcin     PetscInt     keymap[GMSH_NUM_POLYTOPES], nk = 0;
1297066ea43fSLisandro Dalcin     PetscInt     offset[GMSH_NUM_POLYTOPES + 1], e, k;
12980598e1a2SLisandro Dalcin 
12991690c2aeSBarry Smith     for (k = 0; k < GMSH_NUM_POLYTOPES; ++k) keymap[k] = PETSC_INT_MIN;
13009566063dSJacob Faibussowitsch     PetscCall(PetscMemzero(offset, sizeof(offset)));
13010598e1a2SLisandro Dalcin 
1302066ea43fSLisandro Dalcin     keymap[GMSH_TET] = nk++;
1303066ea43fSLisandro Dalcin     keymap[GMSH_HEX] = nk++;
1304066ea43fSLisandro Dalcin     keymap[GMSH_PRI] = nk++;
1305066ea43fSLisandro Dalcin     keymap[GMSH_PYR] = nk++;
1306066ea43fSLisandro Dalcin     keymap[GMSH_TRI] = nk++;
1307066ea43fSLisandro Dalcin     keymap[GMSH_QUA] = nk++;
1308066ea43fSLisandro Dalcin     keymap[GMSH_SEG] = nk++;
1309066ea43fSLisandro Dalcin     keymap[GMSH_VTX] = nk++;
13100598e1a2SLisandro Dalcin 
13119566063dSJacob Faibussowitsch     PetscCall(GmshElementsCreate(mesh->numElems, &mesh->elements));
13124ad8454bSPierre Jolivet #define key(eid) keymap[GmshCellMap[elements[eid].cellType].polytope]
13130598e1a2SLisandro Dalcin     for (e = 0; e < ne; ++e) offset[1 + key(e)]++;
13140598e1a2SLisandro Dalcin     for (k = 1; k < nk; ++k) offset[k] += offset[k - 1];
13150598e1a2SLisandro Dalcin     for (e = 0; e < ne; ++e) mesh->elements[offset[key(e)]++] = elements[e];
13160598e1a2SLisandro Dalcin #undef key
13179566063dSJacob Faibussowitsch     PetscCall(GmshElementsDestroy(&elements));
1318066ea43fSLisandro Dalcin   }
13190598e1a2SLisandro Dalcin 
1320066ea43fSLisandro Dalcin   { /* Mesh dimension and order */
1321066ea43fSLisandro Dalcin     GmshElement *elem = mesh->numElems ? mesh->elements : NULL;
1322066ea43fSLisandro Dalcin     mesh->dim         = elem ? GmshCellMap[elem->cellType].dim : 0;
1323066ea43fSLisandro Dalcin     mesh->order       = elem ? GmshCellMap[elem->cellType].order : 0;
13240598e1a2SLisandro Dalcin   }
13250598e1a2SLisandro Dalcin 
13260598e1a2SLisandro Dalcin   {
13270598e1a2SLisandro Dalcin     PetscBT  vtx;
13280598e1a2SLisandro Dalcin     PetscInt dim = mesh->dim, e, n, v;
13290598e1a2SLisandro Dalcin 
13309566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(mesh->numNodes, &vtx));
13310598e1a2SLisandro Dalcin 
13320598e1a2SLisandro Dalcin     /* Compute number of cells and set of vertices */
13330598e1a2SLisandro Dalcin     mesh->numCells = 0;
13340598e1a2SLisandro Dalcin     for (e = 0; e < mesh->numElems; ++e) {
13350598e1a2SLisandro Dalcin       GmshElement *elem = mesh->elements + e;
13360598e1a2SLisandro Dalcin       if (elem->dim == dim && dim > 0) mesh->numCells++;
133748a46eb9SPierre Jolivet       for (v = 0; v < elem->numVerts; v++) PetscCall(PetscBTSet(vtx, elem->nodes[v]));
13380598e1a2SLisandro Dalcin     }
13390598e1a2SLisandro Dalcin 
13400598e1a2SLisandro Dalcin     /* Compute numbering for vertices */
13410598e1a2SLisandro Dalcin     mesh->numVerts = 0;
13429566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(mesh->numNodes, &mesh->vertexMap));
13431690c2aeSBarry Smith     for (n = 0; n < mesh->numNodes; ++n) mesh->vertexMap[n] = PetscBTLookup(vtx, n) ? mesh->numVerts++ : PETSC_INT_MIN;
13440598e1a2SLisandro Dalcin 
13459566063dSJacob Faibussowitsch     PetscCall(PetscBTDestroy(&vtx));
13460598e1a2SLisandro Dalcin   }
13473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13480598e1a2SLisandro Dalcin }
13490598e1a2SLisandro Dalcin 
1350d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshReadPeriodic(GmshFile *gmsh, GmshMesh *mesh)
1351d71ae5a4SJacob Faibussowitsch {
13520598e1a2SLisandro Dalcin   PetscInt n;
13530598e1a2SLisandro Dalcin 
13540598e1a2SLisandro Dalcin   PetscFunctionBegin;
13559566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(mesh->numNodes, &mesh->periodMap));
13560598e1a2SLisandro Dalcin   for (n = 0; n < mesh->numNodes; ++n) mesh->periodMap[n] = n;
13570598e1a2SLisandro Dalcin   switch (gmsh->fileFormat) {
1358d71ae5a4SJacob Faibussowitsch   case 41:
1359d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadPeriodic_v41(gmsh, mesh->periodMap));
1360d71ae5a4SJacob Faibussowitsch     break;
1361d71ae5a4SJacob Faibussowitsch   default:
1362d71ae5a4SJacob Faibussowitsch     PetscCall(GmshReadPeriodic_v40(gmsh, mesh->periodMap));
1363d71ae5a4SJacob Faibussowitsch     break;
13640598e1a2SLisandro Dalcin   }
13650598e1a2SLisandro Dalcin 
13669dddd249SSatish Balay   /* Find canonical primary nodes */
13670598e1a2SLisandro Dalcin   for (n = 0; n < mesh->numNodes; ++n)
13689371c9d4SSatish Balay     while (mesh->periodMap[n] != mesh->periodMap[mesh->periodMap[n]]) mesh->periodMap[n] = mesh->periodMap[mesh->periodMap[n]];
13690598e1a2SLisandro Dalcin 
13709dddd249SSatish Balay   /* Renumber vertices (filter out correspondings) */
13710598e1a2SLisandro Dalcin   mesh->numVerts = 0;
13720598e1a2SLisandro Dalcin   for (n = 0; n < mesh->numNodes; ++n)
13730598e1a2SLisandro Dalcin     if (mesh->vertexMap[n] >= 0)   /* is vertex */
13749dddd249SSatish Balay       if (mesh->periodMap[n] == n) /* is primary */
13750598e1a2SLisandro Dalcin         mesh->vertexMap[n] = mesh->numVerts++;
13760598e1a2SLisandro Dalcin   for (n = 0; n < mesh->numNodes; ++n)
13770598e1a2SLisandro Dalcin     if (mesh->vertexMap[n] >= 0)   /* is vertex */
13789dddd249SSatish Balay       if (mesh->periodMap[n] != n) /* is corresponding  */
13790598e1a2SLisandro Dalcin         mesh->vertexMap[n] = mesh->vertexMap[mesh->periodMap[n]];
13803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13810598e1a2SLisandro Dalcin }
13820598e1a2SLisandro Dalcin 
1383066ea43fSLisandro Dalcin #define DM_POLYTOPE_VERTEX DM_POLYTOPE_POINT
1384066ea43fSLisandro Dalcin static const DMPolytopeType DMPolytopeMap[] = {
1385066ea43fSLisandro Dalcin   /* GMSH_VTX */ DM_POLYTOPE_VERTEX,
1386066ea43fSLisandro Dalcin   /* GMSH_SEG */ DM_POLYTOPE_SEGMENT,
1387066ea43fSLisandro Dalcin   /* GMSH_TRI */ DM_POLYTOPE_TRIANGLE,
1388066ea43fSLisandro Dalcin   /* GMSH_QUA */ DM_POLYTOPE_QUADRILATERAL,
1389066ea43fSLisandro Dalcin   /* GMSH_TET */ DM_POLYTOPE_TETRAHEDRON,
1390066ea43fSLisandro Dalcin   /* GMSH_HEX */ DM_POLYTOPE_HEXAHEDRON,
1391066ea43fSLisandro Dalcin   /* GMSH_PRI */ DM_POLYTOPE_TRI_PRISM,
13929371c9d4SSatish Balay   /* GMSH_PYR */ DM_POLYTOPE_PYRAMID,       DM_POLYTOPE_UNKNOWN};
13930598e1a2SLisandro Dalcin 
1394d71ae5a4SJacob Faibussowitsch static inline DMPolytopeType DMPolytopeTypeFromGmsh(PetscInt cellType)
1395d71ae5a4SJacob Faibussowitsch {
1396066ea43fSLisandro Dalcin   return DMPolytopeMap[GmshCellMap[cellType].polytope];
1397066ea43fSLisandro Dalcin }
1398066ea43fSLisandro Dalcin 
1399d71ae5a4SJacob Faibussowitsch static PetscErrorCode GmshCreateFE(MPI_Comm comm, const char prefix[], PetscBool isSimplex, PetscBool continuity, PetscDTNodeType nodeType, PetscInt dim, PetscInt Nc, PetscInt k, PetscFE *fem)
1400d71ae5a4SJacob Faibussowitsch {
1401066ea43fSLisandro Dalcin   DM              K;
1402066ea43fSLisandro Dalcin   PetscSpace      P;
1403066ea43fSLisandro Dalcin   PetscDualSpace  Q;
1404066ea43fSLisandro Dalcin   PetscQuadrature q, fq;
1405066ea43fSLisandro Dalcin   PetscBool       isTensor = isSimplex ? PETSC_FALSE : PETSC_TRUE;
1406066ea43fSLisandro Dalcin   PetscBool       endpoint = PETSC_TRUE;
1407066ea43fSLisandro Dalcin   char            name[32];
1408066ea43fSLisandro Dalcin 
1409066ea43fSLisandro Dalcin   PetscFunctionBegin;
1410066ea43fSLisandro Dalcin   /* Create space */
14119566063dSJacob Faibussowitsch   PetscCall(PetscSpaceCreate(comm, &P));
14129566063dSJacob Faibussowitsch   PetscCall(PetscSpaceSetType(P, PETSCSPACEPOLYNOMIAL));
14139566063dSJacob Faibussowitsch   PetscCall(PetscSpacePolynomialSetTensor(P, isTensor));
14149566063dSJacob Faibussowitsch   PetscCall(PetscSpaceSetNumComponents(P, Nc));
14159566063dSJacob Faibussowitsch   PetscCall(PetscSpaceSetNumVariables(P, dim));
14169566063dSJacob Faibussowitsch   PetscCall(PetscSpaceSetDegree(P, k, PETSC_DETERMINE));
1417066ea43fSLisandro Dalcin   if (prefix) {
14189566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)P, prefix));
14199566063dSJacob Faibussowitsch     PetscCall(PetscSpaceSetFromOptions(P));
14209566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)P, NULL));
14219566063dSJacob Faibussowitsch     PetscCall(PetscSpaceGetDegree(P, &k, NULL));
1422066ea43fSLisandro Dalcin   }
14239566063dSJacob Faibussowitsch   PetscCall(PetscSpaceSetUp(P));
1424066ea43fSLisandro Dalcin   /* Create dual space */
14259566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceCreate(comm, &Q));
14269566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetType(Q, PETSCDUALSPACELAGRANGE));
14279566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceLagrangeSetTensor(Q, isTensor));
14289566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceLagrangeSetContinuity(Q, continuity));
14299566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceLagrangeSetNodeType(Q, nodeType, endpoint, 0));
14309566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetNumComponents(Q, Nc));
14319566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetOrder(Q, k));
14329566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceCell(PETSC_COMM_SELF, DMPolytopeTypeSimpleShape(dim, isSimplex), &K));
14339566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetDM(Q, K));
14349566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&K));
1435066ea43fSLisandro Dalcin   if (prefix) {
14369566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)Q, prefix));
14379566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceSetFromOptions(Q));
14389566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)Q, NULL));
1439066ea43fSLisandro Dalcin   }
14409566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceSetUp(Q));
1441066ea43fSLisandro Dalcin   /* Create quadrature */
1442066ea43fSLisandro Dalcin   if (isSimplex) {
14439566063dSJacob Faibussowitsch     PetscCall(PetscDTStroudConicalQuadrature(dim, 1, k + 1, -1, +1, &q));
14449566063dSJacob Faibussowitsch     PetscCall(PetscDTStroudConicalQuadrature(dim - 1, 1, k + 1, -1, +1, &fq));
1445066ea43fSLisandro Dalcin   } else {
14469566063dSJacob Faibussowitsch     PetscCall(PetscDTGaussTensorQuadrature(dim, 1, k + 1, -1, +1, &q));
14479566063dSJacob Faibussowitsch     PetscCall(PetscDTGaussTensorQuadrature(dim - 1, 1, k + 1, -1, +1, &fq));
1448066ea43fSLisandro Dalcin   }
1449066ea43fSLisandro Dalcin   /* Create finite element */
14509566063dSJacob Faibussowitsch   PetscCall(PetscFECreate(comm, fem));
14519566063dSJacob Faibussowitsch   PetscCall(PetscFESetType(*fem, PETSCFEBASIC));
14529566063dSJacob Faibussowitsch   PetscCall(PetscFESetNumComponents(*fem, Nc));
14539566063dSJacob Faibussowitsch   PetscCall(PetscFESetBasisSpace(*fem, P));
14549566063dSJacob Faibussowitsch   PetscCall(PetscFESetDualSpace(*fem, Q));
14559566063dSJacob Faibussowitsch   PetscCall(PetscFESetQuadrature(*fem, q));
14569566063dSJacob Faibussowitsch   PetscCall(PetscFESetFaceQuadrature(*fem, fq));
1457066ea43fSLisandro Dalcin   if (prefix) {
14589566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*fem, prefix));
14599566063dSJacob Faibussowitsch     PetscCall(PetscFESetFromOptions(*fem));
14609566063dSJacob Faibussowitsch     PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*fem, NULL));
1461066ea43fSLisandro Dalcin   }
14629566063dSJacob Faibussowitsch   PetscCall(PetscFESetUp(*fem));
1463066ea43fSLisandro Dalcin   /* Cleanup */
14649566063dSJacob Faibussowitsch   PetscCall(PetscSpaceDestroy(&P));
14659566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceDestroy(&Q));
14669566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureDestroy(&q));
14679566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureDestroy(&fq));
1468066ea43fSLisandro Dalcin   /* Set finite element name */
146963a3b9bcSJacob Faibussowitsch   PetscCall(PetscSNPrintf(name, sizeof(name), "%s%" PetscInt_FMT, isSimplex ? "P" : "Q", k));
14709566063dSJacob Faibussowitsch   PetscCall(PetscFESetName(*fem, name));
14713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
147296ca5757SLisandro Dalcin }
147396ca5757SLisandro Dalcin 
1474cc4c1da9SBarry Smith /*@
1475a1cb98faSBarry Smith   DMPlexCreateGmshFromFile - Create a `DMPLEX` mesh from a Gmsh file
1476d6689ca9SLisandro Dalcin 
1477a4e35b19SJacob Faibussowitsch   Input Parameters:
1478d6689ca9SLisandro Dalcin + comm        - The MPI communicator
1479d6689ca9SLisandro Dalcin . filename    - Name of the Gmsh file
1480d6689ca9SLisandro Dalcin - interpolate - Create faces and edges in the mesh
1481d6689ca9SLisandro Dalcin 
1482d6689ca9SLisandro Dalcin   Output Parameter:
1483a1cb98faSBarry Smith . dm - The `DM` object representing the mesh
1484d6689ca9SLisandro Dalcin 
1485d6689ca9SLisandro Dalcin   Level: beginner
1486d6689ca9SLisandro Dalcin 
14871cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromFile()`, `DMPlexCreateGmsh()`, `DMPlexCreate()`
1488d6689ca9SLisandro Dalcin @*/
1489d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateGmshFromFile(MPI_Comm comm, const char filename[], PetscBool interpolate, DM *dm)
1490d71ae5a4SJacob Faibussowitsch {
1491d6689ca9SLisandro Dalcin   PetscViewer     viewer;
1492d6689ca9SLisandro Dalcin   PetscMPIInt     rank;
1493d6689ca9SLisandro Dalcin   int             fileType;
1494d6689ca9SLisandro Dalcin   PetscViewerType vtype;
1495d6689ca9SLisandro Dalcin 
1496d6689ca9SLisandro Dalcin   PetscFunctionBegin;
14979566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1498d6689ca9SLisandro Dalcin 
1499d6689ca9SLisandro Dalcin   /* Determine Gmsh file type (ASCII or binary) from file header */
1500dd400576SPatrick Sanan   if (rank == 0) {
15010598e1a2SLisandro Dalcin     GmshFile gmsh[1];
1502d6689ca9SLisandro Dalcin     char     line[PETSC_MAX_PATH_LEN];
1503d6689ca9SLisandro Dalcin     int      snum;
1504d6689ca9SLisandro Dalcin     float    version;
1505a8d4e440SJunchao Zhang     int      fileFormat;
1506d6689ca9SLisandro Dalcin 
15079566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(gmsh, 1));
15089566063dSJacob Faibussowitsch     PetscCall(PetscViewerCreate(PETSC_COMM_SELF, &gmsh->viewer));
15099566063dSJacob Faibussowitsch     PetscCall(PetscViewerSetType(gmsh->viewer, PETSCVIEWERASCII));
15109566063dSJacob Faibussowitsch     PetscCall(PetscViewerFileSetMode(gmsh->viewer, FILE_MODE_READ));
15119566063dSJacob Faibussowitsch     PetscCall(PetscViewerFileSetName(gmsh->viewer, filename));
1512d6689ca9SLisandro Dalcin     /* Read only the first two lines of the Gmsh file */
15139566063dSJacob Faibussowitsch     PetscCall(GmshReadSection(gmsh, line));
15149566063dSJacob Faibussowitsch     PetscCall(GmshExpect(gmsh, "$MeshFormat", line));
15159566063dSJacob Faibussowitsch     PetscCall(GmshReadString(gmsh, line, 2));
1516d6689ca9SLisandro Dalcin     snum       = sscanf(line, "%f %d", &version, &fileType);
1517a8d4e440SJunchao Zhang     fileFormat = (int)roundf(version * 10);
151808401ef6SPierre Jolivet     PetscCheck(snum == 2, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to parse Gmsh file header: %s", line);
1519a8d4e440SJunchao Zhang     PetscCheck(fileFormat >= 22, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at least 2.2", (double)version);
15201dca8a05SBarry Smith     PetscCheck((int)version != 3, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f not supported", (double)version);
1521a8d4e440SJunchao Zhang     PetscCheck(fileFormat <= 41, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at most 4.1", (double)version);
15229566063dSJacob Faibussowitsch     PetscCall(PetscViewerDestroy(&gmsh->viewer));
1523d6689ca9SLisandro Dalcin   }
15249566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Bcast(&fileType, 1, MPI_INT, 0, comm));
1525d6689ca9SLisandro Dalcin   vtype = (fileType == 0) ? PETSCVIEWERASCII : PETSCVIEWERBINARY;
1526d6689ca9SLisandro Dalcin 
1527d6689ca9SLisandro Dalcin   /* Create appropriate viewer and build plex */
15289566063dSJacob Faibussowitsch   PetscCall(PetscViewerCreate(comm, &viewer));
15299566063dSJacob Faibussowitsch   PetscCall(PetscViewerSetType(viewer, vtype));
15309566063dSJacob Faibussowitsch   PetscCall(PetscViewerFileSetMode(viewer, FILE_MODE_READ));
15319566063dSJacob Faibussowitsch   PetscCall(PetscViewerFileSetName(viewer, filename));
15329566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateGmsh(comm, viewer, interpolate, dm));
15339566063dSJacob Faibussowitsch   PetscCall(PetscViewerDestroy(&viewer));
15343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1535d6689ca9SLisandro Dalcin }
1536d6689ca9SLisandro Dalcin 
1537331830f3SMatthew G. Knepley /*@
1538a1cb98faSBarry Smith   DMPlexCreateGmsh - Create a `DMPLEX` mesh from a Gmsh file viewer
1539331830f3SMatthew G. Knepley 
1540d083f849SBarry Smith   Collective
1541331830f3SMatthew G. Knepley 
1542331830f3SMatthew G. Knepley   Input Parameters:
1543331830f3SMatthew G. Knepley + comm        - The MPI communicator
1544a1cb98faSBarry Smith . viewer      - The `PetscViewer` associated with a Gmsh file
1545331830f3SMatthew G. Knepley - interpolate - Create faces and edges in the mesh
1546331830f3SMatthew G. Knepley 
1547331830f3SMatthew G. Knepley   Output Parameter:
1548a1cb98faSBarry Smith . dm - The `DM` object representing the mesh
1549331830f3SMatthew G. Knepley 
1550a1cb98faSBarry Smith   Options Database Keys:
1551df93260fSMatthew G. Knepley + -dm_plex_gmsh_hybrid               - Force triangular prisms to use tensor order
1552df93260fSMatthew G. Knepley . -dm_plex_gmsh_periodic             - Read Gmsh periodic section and construct a periodic Plex
1553df93260fSMatthew G. Knepley . -dm_plex_gmsh_highorder            - Generate high-order coordinates
1554df93260fSMatthew 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
15552b205333SMatthew G. Knepley . -dm_plex_gmsh_use_generic          - Generate generic labels, i.e. Cell Sets, Face Sets, etc.
1556df93260fSMatthew G. Knepley . -dm_plex_gmsh_use_regions          - Generate labels with region names
1557df93260fSMatthew G. Knepley . -dm_plex_gmsh_mark_vertices        - Add vertices to generated labels
15584c375d72SMatthew G. Knepley . -dm_plex_gmsh_mark_vertices_strict - Add vertices included in a region to generated labels
1559df93260fSMatthew G. Knepley . -dm_plex_gmsh_multiple_tags        - Allow multiple tags for default labels
1560df93260fSMatthew G. Knepley - -dm_plex_gmsh_spacedim <d>         - Embedding space dimension, if different from topological dimension
1561df93260fSMatthew G. Knepley 
15621d27aa22SBarry Smith   Level: beginner
15631d27aa22SBarry Smith 
15641d27aa22SBarry Smith   Notes:
15651d27aa22SBarry Smith   The Gmsh file format is described in <http://gmsh.info/doc/texinfo/gmsh.html#MSH-file-format>
1566df93260fSMatthew G. Knepley 
15676497c311SBarry 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`.
1568331830f3SMatthew G. Knepley 
15691cc06b55SBarry Smith .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`
1570331830f3SMatthew G. Knepley @*/
1571d71ae5a4SJacob Faibussowitsch PetscErrorCode DMPlexCreateGmsh(MPI_Comm comm, PetscViewer viewer, PetscBool interpolate, DM *dm)
1572d71ae5a4SJacob Faibussowitsch {
15730598e1a2SLisandro Dalcin   GmshMesh    *mesh          = NULL;
157411c56cb0SLisandro Dalcin   PetscViewer  parentviewer  = NULL;
15750598e1a2SLisandro Dalcin   PetscBT      periodicVerts = NULL;
1576eae3dc7dSJacob Faibussowitsch   PetscBT     *periodicCells = NULL;
15776858538eSMatthew G. Knepley   DM           cdm, cdmCell = NULL;
15786858538eSMatthew G. Knepley   PetscSection cs, csCell   = NULL;
15796858538eSMatthew G. Knepley   Vec          coordinates, coordinatesCell;
15800444adf6SMatthew G. Knepley   DMLabel      cellSets = NULL, faceSets = NULL, edgeSets = NULL, vertSets = NULL, marker = NULL, *regionSets;
15819db5b827SMatthew G. Knepley   PetscInt     dim = 0, coordDim = -1, order = 0, maxHeight = 0;
15829db5b827SMatthew G. Knepley   PetscInt     numNodes = 0, numElems = 0, numVerts = 0, numCells = 0, vStart, vEnd;
1583066ea43fSLisandro Dalcin   PetscInt     cell, cone[8], e, n, v, d;
15844c375d72SMatthew G. Knepley   PetscBool    usegeneric = PETSC_TRUE, useregions = PETSC_FALSE, markvertices = PETSC_FALSE, markverticesstrict = PETSC_FALSE, multipleTags = PETSC_FALSE;
15852b205333SMatthew G. Knepley   PetscBool    flg, binary, hybrid = interpolate, periodic = PETSC_TRUE;
1586066ea43fSLisandro Dalcin   PetscBool    highOrder = PETSC_TRUE, highOrderSet, project = PETSC_FALSE;
1587066ea43fSLisandro Dalcin   PetscBool    isSimplex = PETSC_FALSE, isHybrid = PETSC_FALSE, hasTetra = PETSC_FALSE;
15880598e1a2SLisandro Dalcin   PetscMPIInt  rank;
1589331830f3SMatthew G. Knepley 
1590331830f3SMatthew G. Knepley   PetscFunctionBegin;
15919566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
1592d0609cedSBarry Smith   PetscObjectOptionsBegin((PetscObject)viewer);
1593d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "DMPlex Gmsh options");
1594df93260fSMatthew G. Knepley   PetscCall(PetscOptionsBool("-dm_plex_gmsh_hybrid", "Force triangular prisms to use tensor order", "DMPlexCreateGmsh", hybrid, &hybrid, NULL));
15959566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_plex_gmsh_periodic", "Read Gmsh periodic section", "DMPlexCreateGmsh", periodic, &periodic, NULL));
15969566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_plex_gmsh_highorder", "Generate high-order coordinates", "DMPlexCreateGmsh", highOrder, &highOrder, &highOrderSet));
15979566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_plex_gmsh_project", "Project high-order coordinates to a different space", "DMPlexCreateGmsh", project, &project, NULL));
15989566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_plex_gmsh_use_regions", "Generate labels with region names", "DMPlexCreateGmsh", useregions, &useregions, NULL));
15992b205333SMatthew G. Knepley   PetscCall(PetscOptionsBool("-dm_plex_gmsh_use_generic", "Generate generic labels, i.e. Cell Sets, Face Sets, etc", "DMPlexCreateGmsh", usegeneric, &usegeneric, &flg));
16002b205333SMatthew G. Knepley   if (!flg && useregions) usegeneric = PETSC_FALSE;
16019566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_plex_gmsh_mark_vertices", "Add vertices to generated labels", "DMPlexCreateGmsh", markvertices, &markvertices, NULL));
16024c375d72SMatthew G. Knepley   PetscCall(PetscOptionsBool("-dm_plex_gmsh_mark_vertices_strict", "Add only directly tagged vertices to generated labels", "DMPlexCreateGmsh", markverticesstrict, &markverticesstrict, 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 */
18744c375d72SMatthew G. Knepley       if (elem->numTags && elem->dim == 0 && (markverticesstrict || markvertices)) {
18750598e1a2SLisandro Dalcin         const PetscInt nn = elem->nodes[0];
18760598e1a2SLisandro Dalcin         const PetscInt vv = mesh->vertexMap[nn];
1877*bb3f7942SBrad Aagaard         PetscInt       Nt = elem->numTags;
1878*bb3f7942SBrad Aagaard 
1879*bb3f7942SBrad Aagaard         for (PetscInt t = 0; t < Nt; ++t) {
1880*bb3f7942SBrad Aagaard           const PetscInt tag = elem->tags[t];
1881a45dabc8SMatthew G. Knepley 
18828a3d9825SMatthew G. Knepley           if (vv < 0) continue;
18832b205333SMatthew G. Knepley           if (usegeneric) PetscCall(DMSetLabelValue_Fast(*dm, &vertSets, "Vertex Sets", vStart + vv, tag));
1884*bb3f7942SBrad Aagaard           for (PetscInt r = 0; r < Nr; ++r) {
1885df93260fSMatthew G. Knepley             if (mesh->regionDims[r] != 0) continue;
18869566063dSJacob Faibussowitsch             if (mesh->regionTags[r] == tag) PetscCall(DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], vStart + vv, tag));
188781a1af93SMatthew G. Knepley           }
188881a1af93SMatthew G. Knepley         }
188981a1af93SMatthew G. Knepley       }
1890*bb3f7942SBrad Aagaard     }
189181a1af93SMatthew G. Knepley     if (markvertices) {
189281a1af93SMatthew G. Knepley       for (v = 0; v < numNodes; ++v) {
189381a1af93SMatthew G. Knepley         const PetscInt  vv   = mesh->vertexMap[v];
18947d5b9244SMatthew G. Knepley         const PetscInt *tags = &mesh->nodelist->tag[v * GMSH_MAX_TAGS];
18957d5b9244SMatthew G. Knepley         PetscInt        r, t;
189681a1af93SMatthew G. Knepley 
18978a3d9825SMatthew G. Knepley         if (vv < 0) continue;
18987d5b9244SMatthew G. Knepley         for (t = 0; t < GMSH_MAX_TAGS; ++t) {
18997d5b9244SMatthew G. Knepley           const PetscInt  tag     = tags[t];
19002b205333SMatthew G. Knepley           const PetscBool generic = usegeneric && (!t || multipleTags) ? PETSC_TRUE : PETSC_FALSE;
19017d5b9244SMatthew G. Knepley 
19027d5b9244SMatthew G. Knepley           if (tag == -1) continue;
1903df93260fSMatthew G. Knepley           if (generic) PetscCall(DMSetLabelValue_Fast(*dm, &vertSets, "Vertex Sets", vStart + vv, tag));
1904a45dabc8SMatthew G. Knepley           for (r = 0; r < Nr; ++r) {
19059566063dSJacob Faibussowitsch             if (mesh->regionTags[r] == tag) PetscCall(DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], vStart + vv, tag));
19060598e1a2SLisandro Dalcin           }
19070598e1a2SLisandro Dalcin         }
19080598e1a2SLisandro Dalcin       }
19090598e1a2SLisandro Dalcin     }
19109566063dSJacob Faibussowitsch     PetscCall(PetscFree(regionSets));
1911a45dabc8SMatthew G. Knepley   }
19120598e1a2SLisandro Dalcin 
19130444adf6SMatthew G. Knepley   { /* Create Cell/Face/Edge/Vertex Sets labels at all processes */
19149371c9d4SSatish Balay     enum {
19150444adf6SMatthew G. Knepley       n = 5
19169371c9d4SSatish Balay     };
19177dd454faSLisandro Dalcin     PetscBool flag[n];
19187dd454faSLisandro Dalcin 
19197dd454faSLisandro Dalcin     flag[0] = cellSets ? PETSC_TRUE : PETSC_FALSE;
19207dd454faSLisandro Dalcin     flag[1] = faceSets ? PETSC_TRUE : PETSC_FALSE;
19210444adf6SMatthew G. Knepley     flag[2] = edgeSets ? PETSC_TRUE : PETSC_FALSE;
19220444adf6SMatthew G. Knepley     flag[3] = vertSets ? PETSC_TRUE : PETSC_FALSE;
19230444adf6SMatthew G. Knepley     flag[4] = marker ? PETSC_TRUE : PETSC_FALSE;
19249566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Bcast(flag, n, MPIU_BOOL, 0, comm));
19259566063dSJacob Faibussowitsch     if (flag[0]) PetscCall(DMCreateLabel(*dm, "Cell Sets"));
19269566063dSJacob Faibussowitsch     if (flag[1]) PetscCall(DMCreateLabel(*dm, "Face Sets"));
19270444adf6SMatthew G. Knepley     if (flag[2]) PetscCall(DMCreateLabel(*dm, "Edge Sets"));
19280444adf6SMatthew G. Knepley     if (flag[3]) PetscCall(DMCreateLabel(*dm, "Vertex Sets"));
19290444adf6SMatthew G. Knepley     if (flag[4]) PetscCall(DMCreateLabel(*dm, "marker"));
19307dd454faSLisandro Dalcin   }
19317dd454faSLisandro Dalcin 
19320598e1a2SLisandro Dalcin   if (periodic) {
19339566063dSJacob Faibussowitsch     PetscCall(PetscBTCreate(numVerts, &periodicVerts));
19340598e1a2SLisandro Dalcin     for (n = 0; n < numNodes; ++n) {
19350598e1a2SLisandro Dalcin       if (mesh->vertexMap[n] >= 0) {
19360598e1a2SLisandro Dalcin         if (PetscUnlikely(mesh->periodMap[n] != n)) {
19370598e1a2SLisandro Dalcin           PetscInt m = mesh->periodMap[n];
19389566063dSJacob Faibussowitsch           PetscCall(PetscBTSet(periodicVerts, mesh->vertexMap[n]));
19399566063dSJacob Faibussowitsch           PetscCall(PetscBTSet(periodicVerts, mesh->vertexMap[m]));
19400598e1a2SLisandro Dalcin         }
19410598e1a2SLisandro Dalcin       }
19420598e1a2SLisandro Dalcin     }
19439db5b827SMatthew G. Knepley     PetscCall(DMGetCoordinateDM(*dm, &cdm));
1944eae3dc7dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxHeight + 1, &periodicCells));
19459db5b827SMatthew G. Knepley     for (PetscInt h = 0; h <= maxHeight; ++h) {
19469db5b827SMatthew G. Knepley       PetscInt pStart, pEnd;
19479db5b827SMatthew G. Knepley 
19489db5b827SMatthew G. Knepley       PetscCall(DMPlexGetHeightStratum(*dm, h, &pStart, &pEnd));
19499db5b827SMatthew G. Knepley       PetscCall(PetscBTCreate(pEnd - pStart, &periodicCells[h]));
19509db5b827SMatthew G. Knepley       for (PetscInt p = pStart; p < pEnd; ++p) {
19519db5b827SMatthew G. Knepley         PetscInt *closure = NULL;
19529db5b827SMatthew G. Knepley         PetscInt  Ncl;
19539db5b827SMatthew G. Knepley 
19549db5b827SMatthew G. Knepley         PetscCall(DMPlexGetTransitiveClosure(*dm, p, PETSC_TRUE, &Ncl, &closure));
19559db5b827SMatthew G. Knepley         for (PetscInt cl = 0; cl < Ncl * 2; cl += 2) {
19569db5b827SMatthew G. Knepley           if (closure[cl] >= vStart && closure[cl] < vEnd) {
19579db5b827SMatthew G. Knepley             if (PetscUnlikely(PetscBTLookup(periodicVerts, closure[cl] - vStart))) {
19589db5b827SMatthew G. Knepley               PetscCall(PetscBTSet(periodicCells[h], p - pStart));
19599371c9d4SSatish Balay               break;
19600c070f12SSander Arens             }
19610c070f12SSander Arens           }
19620c070f12SSander Arens         }
19639db5b827SMatthew G. Knepley         PetscCall(DMPlexRestoreTransitiveClosure(*dm, p, PETSC_TRUE, &Ncl, &closure));
19649db5b827SMatthew G. Knepley       }
19659db5b827SMatthew G. Knepley     }
196616ad7e67SMichael Lange   }
196716ad7e67SMichael Lange 
1968066ea43fSLisandro Dalcin   /* Setup coordinate DM */
19690598e1a2SLisandro Dalcin   if (coordDim < 0) coordDim = dim;
19709566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinateDim(*dm, coordDim));
19719566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(*dm, &cdm));
1972066ea43fSLisandro Dalcin   if (highOrder) {
1973066ea43fSLisandro Dalcin     PetscFE         fe;
1974066ea43fSLisandro Dalcin     PetscBool       continuity = periodic ? PETSC_FALSE : PETSC_TRUE;
1975066ea43fSLisandro Dalcin     PetscDTNodeType nodeType   = PETSCDTNODES_EQUISPACED;
1976066ea43fSLisandro Dalcin 
1977066ea43fSLisandro Dalcin     if (isSimplex) continuity = PETSC_FALSE; /* XXX FIXME Requires DMPlexSetClosurePermutationLexicographic() */
1978066ea43fSLisandro Dalcin 
19799566063dSJacob Faibussowitsch     PetscCall(GmshCreateFE(comm, NULL, isSimplex, continuity, nodeType, dim, coordDim, order, &fe));
19809566063dSJacob Faibussowitsch     PetscCall(PetscFEViewFromOptions(fe, NULL, "-dm_plex_gmsh_fe_view"));
19819566063dSJacob Faibussowitsch     PetscCall(DMSetField(cdm, 0, NULL, (PetscObject)fe));
19829566063dSJacob Faibussowitsch     PetscCall(PetscFEDestroy(&fe));
19839566063dSJacob Faibussowitsch     PetscCall(DMCreateDS(cdm));
1984066ea43fSLisandro Dalcin   }
19856858538eSMatthew G. Knepley   if (periodic) {
19866858538eSMatthew G. Knepley     PetscCall(DMClone(cdm, &cdmCell));
19876858538eSMatthew G. Knepley     PetscCall(DMSetCellCoordinateDM(*dm, cdmCell));
19886858538eSMatthew G. Knepley   }
1989066ea43fSLisandro Dalcin 
1990066ea43fSLisandro Dalcin   /* Create coordinates */
1991066ea43fSLisandro Dalcin   if (highOrder) {
1992066ea43fSLisandro Dalcin     PetscInt     maxDof = GmshNumNodes_HEX(order) * coordDim;
1993066ea43fSLisandro Dalcin     double      *coords = mesh ? mesh->nodelist->xyz : NULL;
1994066ea43fSLisandro Dalcin     PetscSection section;
1995066ea43fSLisandro Dalcin     PetscScalar *cellCoords;
1996066ea43fSLisandro Dalcin 
19979566063dSJacob Faibussowitsch     PetscCall(DMSetLocalSection(cdm, NULL));
19986858538eSMatthew G. Knepley     PetscCall(DMGetLocalSection(cdm, &cs));
19996858538eSMatthew G. Knepley     PetscCall(PetscSectionClone(cs, &section));
20009566063dSJacob Faibussowitsch     PetscCall(DMPlexSetClosurePermutationTensor(cdm, 0, section)); /* XXX Implement DMPlexSetClosurePermutationLexicographic() */
2001066ea43fSLisandro Dalcin 
20029566063dSJacob Faibussowitsch     PetscCall(DMCreateLocalVector(cdm, &coordinates));
20039566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(maxDof, &cellCoords));
2004066ea43fSLisandro Dalcin     for (cell = 0; cell < numCells; ++cell) {
2005066ea43fSLisandro Dalcin       GmshElement *elem     = mesh->elements + cell;
2006066ea43fSLisandro Dalcin       const int   *lexorder = GmshCellMap[elem->cellType].lexorder();
2007b9bf55e5SMatthew G. Knepley       int          s        = 0;
2008066ea43fSLisandro Dalcin       for (n = 0; n < elem->numNodes; ++n) {
2009b9bf55e5SMatthew G. Knepley         while (lexorder[n + s] < 0) ++s;
2010b9bf55e5SMatthew G. Knepley         const PetscInt node = elem->nodes[lexorder[n + s]];
2011b9bf55e5SMatthew G. Knepley         for (d = 0; d < coordDim; ++d) cellCoords[(n + s) * coordDim + d] = (PetscReal)coords[node * 3 + d];
2012b9bf55e5SMatthew G. Knepley       }
2013b9bf55e5SMatthew G. Knepley       if (s) {
2014b9bf55e5SMatthew G. Knepley         /* For the coordinate mapping we weight vertices by -1/4 and edges by 1/2, which we get from Q_2 interpolation */
2015b9bf55e5SMatthew G. Knepley         PetscReal quaCenterWeights[9] = {-0.25, 0.5, -0.25, 0.5, 0.0, 0.5, -0.25, 0.5, -0.25};
2016b9bf55e5SMatthew G. Knepley         /* For the coordinate mapping we weight vertices by -1/4 and edges by 1/2, which we get from Q_2 interpolation */
20179371c9d4SSatish 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};
20189371c9d4SSatish 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};
20199371c9d4SSatish 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};
20209371c9d4SSatish 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};
20219371c9d4SSatish 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};
20229371c9d4SSatish 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};
20239371c9d4SSatish 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};
2024b9bf55e5SMatthew G. Knepley         PetscReal  *sdWeights2[9]        = {NULL, NULL, NULL, NULL, quaCenterWeights, NULL, NULL, NULL, NULL};
20259371c9d4SSatish Balay         PetscReal  *sdWeights3[27]       = {NULL, NULL, NULL, NULL, hexBottomWeights, NULL, NULL, NULL, NULL, NULL, hexFrontWeights, NULL, hexLeftWeights, hexCenterWeights, hexRightWeights, NULL, hexBackWeights, NULL,
2026b9bf55e5SMatthew G. Knepley                                             NULL, NULL, NULL, NULL, hexTopWeights,    NULL, NULL, NULL, NULL};
2027b9bf55e5SMatthew G. Knepley         PetscReal **sdWeights[4]         = {NULL, NULL, sdWeights2, sdWeights3};
2028b9bf55e5SMatthew G. Knepley 
2029b9bf55e5SMatthew G. Knepley         /* Missing entries in serendipity cell, only works for 8-node quad and 20-node hex */
2030b9bf55e5SMatthew G. Knepley         for (n = 0; n < elem->numNodes + s; ++n) {
2031b9bf55e5SMatthew G. Knepley           if (lexorder[n] >= 0) continue;
2032b9bf55e5SMatthew G. Knepley           for (d = 0; d < coordDim; ++d) cellCoords[n * coordDim + d] = 0.0;
2033b9bf55e5SMatthew G. Knepley           for (int bn = 0; bn < elem->numNodes + s; ++bn) {
2034b9bf55e5SMatthew G. Knepley             if (lexorder[bn] < 0) continue;
2035b9bf55e5SMatthew G. Knepley             const PetscReal *weights = sdWeights[coordDim][n];
2036b9bf55e5SMatthew G. Knepley             const PetscInt   bnode   = elem->nodes[lexorder[bn]];
2037b9bf55e5SMatthew G. Knepley             for (d = 0; d < coordDim; ++d) cellCoords[n * coordDim + d] += weights[bn] * (PetscReal)coords[bnode * 3 + d];
2038b9bf55e5SMatthew G. Knepley           }
2039b9bf55e5SMatthew G. Knepley         }
2040066ea43fSLisandro Dalcin       }
20419566063dSJacob Faibussowitsch       PetscCall(DMPlexVecSetClosure(cdm, section, coordinates, cell, cellCoords, INSERT_VALUES));
2042066ea43fSLisandro Dalcin     }
20439566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&section));
20449566063dSJacob Faibussowitsch     PetscCall(PetscFree(cellCoords));
2045066ea43fSLisandro Dalcin   } else {
2046066ea43fSLisandro Dalcin     PetscInt    *nodeMap;
2047066ea43fSLisandro Dalcin     double      *coords = mesh ? mesh->nodelist->xyz : NULL;
2048066ea43fSLisandro Dalcin     PetscScalar *pointCoords;
2049066ea43fSLisandro Dalcin 
20506858538eSMatthew G. Knepley     PetscCall(DMGetCoordinateSection(*dm, &cs));
20516858538eSMatthew G. Knepley     PetscCall(PetscSectionSetNumFields(cs, 1));
20526858538eSMatthew G. Knepley     PetscCall(PetscSectionSetFieldComponents(cs, 0, coordDim));
20536858538eSMatthew G. Knepley     PetscCall(PetscSectionSetChart(cs, numCells, numCells + numVerts));
20546858538eSMatthew G. Knepley     for (v = numCells; v < numCells + numVerts; ++v) {
20556858538eSMatthew G. Knepley       PetscCall(PetscSectionSetDof(cs, v, coordDim));
20566858538eSMatthew G. Knepley       PetscCall(PetscSectionSetFieldDof(cs, v, 0, coordDim));
2057f45c9589SStefano Zampini     }
20586858538eSMatthew G. Knepley     PetscCall(PetscSectionSetUp(cs));
20596858538eSMatthew G. Knepley 
20606858538eSMatthew G. Knepley     /* We need to localize coordinates on cells */
20610598e1a2SLisandro Dalcin     if (periodic) {
20621690c2aeSBarry Smith       PetscInt newStart = PETSC_INT_MAX, newEnd = -1, pStart, pEnd;
20639db5b827SMatthew G. Knepley 
20646858538eSMatthew G. Knepley       PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)cdmCell), &csCell));
20656858538eSMatthew G. Knepley       PetscCall(PetscSectionSetNumFields(csCell, 1));
20666858538eSMatthew G. Knepley       PetscCall(PetscSectionSetFieldComponents(csCell, 0, coordDim));
20679db5b827SMatthew G. Knepley       for (PetscInt h = 0; h <= maxHeight; h++) {
20689db5b827SMatthew G. Knepley         PetscCall(DMPlexGetHeightStratum(cdmCell, h, &pStart, &pEnd));
20699db5b827SMatthew G. Knepley         newStart = PetscMin(newStart, pStart);
20709db5b827SMatthew G. Knepley         newEnd   = PetscMax(newEnd, pEnd);
20719db5b827SMatthew G. Knepley       }
20729db5b827SMatthew G. Knepley       PetscCall(PetscSectionSetChart(csCell, newStart, newEnd));
20739db5b827SMatthew G. Knepley       for (PetscInt h = 0; h <= maxHeight; h++) {
20749db5b827SMatthew G. Knepley         PetscCall(DMPlexGetHeightStratum(cdmCell, h, &pStart, &pEnd));
20759db5b827SMatthew G. Knepley         for (PetscInt p = pStart; p < pEnd; ++p) {
20769db5b827SMatthew G. Knepley           PetscInt *closure = NULL;
20779db5b827SMatthew G. Knepley           PetscInt  Ncl, Nv = 0;
20786858538eSMatthew G. Knepley 
20799db5b827SMatthew G. Knepley           if (PetscUnlikely(PetscBTLookup(periodicCells[h], p - pStart))) {
20809db5b827SMatthew G. Knepley             PetscCall(DMPlexGetTransitiveClosure(*dm, p, PETSC_TRUE, &Ncl, &closure));
20819db5b827SMatthew G. Knepley             for (PetscInt cl = 0; cl < Ncl * 2; cl += 2) {
20829db5b827SMatthew G. Knepley               if (closure[cl] >= vStart && closure[cl] < vEnd) ++Nv;
20839db5b827SMatthew G. Knepley             }
20849db5b827SMatthew G. Knepley             PetscCall(DMPlexRestoreTransitiveClosure(*dm, p, PETSC_TRUE, &Ncl, &closure));
20859db5b827SMatthew G. Knepley             PetscCall(PetscSectionSetDof(csCell, p, Nv * coordDim));
20869db5b827SMatthew G. Knepley             PetscCall(PetscSectionSetFieldDof(csCell, p, 0, Nv * coordDim));
20879db5b827SMatthew G. Knepley           }
2088f45c9589SStefano Zampini         }
2089f45c9589SStefano Zampini       }
20906858538eSMatthew G. Knepley       PetscCall(PetscSectionSetUp(csCell));
20916858538eSMatthew G. Knepley       PetscCall(DMSetCellCoordinateSection(*dm, PETSC_DETERMINE, csCell));
2092f45c9589SStefano Zampini     }
2093066ea43fSLisandro Dalcin 
20949566063dSJacob Faibussowitsch     PetscCall(DMCreateLocalVector(cdm, &coordinates));
20959566063dSJacob Faibussowitsch     PetscCall(VecGetArray(coordinates, &pointCoords));
20966858538eSMatthew G. Knepley     PetscCall(PetscMalloc1(numVerts, &nodeMap));
20976858538eSMatthew G. Knepley     for (n = 0; n < numNodes; n++)
20986858538eSMatthew G. Knepley       if (mesh->vertexMap[n] >= 0) nodeMap[mesh->vertexMap[n]] = n;
20996858538eSMatthew G. Knepley     for (v = 0; v < numVerts; ++v) {
21006858538eSMatthew G. Knepley       PetscInt off, node = nodeMap[v];
21016858538eSMatthew G. Knepley 
21026858538eSMatthew G. Knepley       PetscCall(PetscSectionGetOffset(cs, numCells + v, &off));
21036858538eSMatthew G. Knepley       for (d = 0; d < coordDim; ++d) pointCoords[off + d] = (PetscReal)coords[node * 3 + d];
21046858538eSMatthew G. Knepley     }
21056858538eSMatthew G. Knepley     PetscCall(VecRestoreArray(coordinates, &pointCoords));
21066858538eSMatthew G. Knepley 
21070598e1a2SLisandro Dalcin     if (periodic) {
21089db5b827SMatthew G. Knepley       PetscInt cStart, cEnd;
21099db5b827SMatthew G. Knepley 
21109db5b827SMatthew G. Knepley       PetscCall(DMPlexGetHeightStratum(cdmCell, 0, &cStart, &cEnd));
21116858538eSMatthew G. Knepley       PetscCall(DMCreateLocalVector(cdmCell, &coordinatesCell));
21126858538eSMatthew G. Knepley       PetscCall(VecGetArray(coordinatesCell, &pointCoords));
21139db5b827SMatthew G. Knepley       for (PetscInt c = cStart; c < cEnd; ++c) {
21149db5b827SMatthew G. Knepley         GmshElement *elem    = mesh->elements + c - cStart;
21159db5b827SMatthew G. Knepley         PetscInt    *closure = NULL;
21169db5b827SMatthew G. Knepley         PetscInt     verts[8];
21179db5b827SMatthew G. Knepley         PetscInt     Ncl, Nv = 0;
21189db5b827SMatthew G. Knepley 
21199db5b827SMatthew G. Knepley         for (PetscInt v = 0; v < elem->numVerts; ++v) cone[v] = elem->nodes[v];
21209db5b827SMatthew G. Knepley         PetscCall(DMPlexReorderCell(cdmCell, c, cone));
21219db5b827SMatthew G. Knepley         PetscCall(DMPlexGetTransitiveClosure(cdmCell, c, PETSC_TRUE, &Ncl, &closure));
21229db5b827SMatthew G. Knepley         for (PetscInt cl = 0; cl < Ncl * 2; cl += 2) {
21239db5b827SMatthew G. Knepley           if (closure[cl] >= vStart && closure[cl] < vEnd) verts[Nv++] = closure[cl];
2124331830f3SMatthew G. Knepley         }
21259db5b827SMatthew 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);
21269db5b827SMatthew G. Knepley         for (PetscInt cl = 0; cl < Ncl * 2; cl += 2) {
21279db5b827SMatthew G. Knepley           const PetscInt point = closure[cl];
21289db5b827SMatthew G. Knepley           PetscInt       hStart, h;
21299db5b827SMatthew G. Knepley 
21309db5b827SMatthew G. Knepley           PetscCall(DMPlexGetPointHeight(cdmCell, point, &h));
21319db5b827SMatthew G. Knepley           if (h > maxHeight) continue;
21329db5b827SMatthew G. Knepley           PetscCall(DMPlexGetHeightStratum(cdmCell, h, &hStart, NULL));
21339db5b827SMatthew G. Knepley           if (PetscUnlikely(PetscBTLookup(periodicCells[h], point - hStart))) {
21349db5b827SMatthew G. Knepley             PetscInt *pclosure = NULL;
21359db5b827SMatthew G. Knepley             PetscInt  Npcl, off, v;
21369db5b827SMatthew G. Knepley 
21379db5b827SMatthew G. Knepley             PetscCall(PetscSectionGetOffset(csCell, point, &off));
21389db5b827SMatthew G. Knepley             PetscCall(DMPlexGetTransitiveClosure(cdmCell, point, PETSC_TRUE, &Npcl, &pclosure));
21399db5b827SMatthew G. Knepley             for (PetscInt pcl = 0; pcl < Npcl * 2; pcl += 2) {
21409db5b827SMatthew G. Knepley               if (pclosure[pcl] >= vStart && pclosure[pcl] < vEnd) {
21419db5b827SMatthew G. Knepley                 for (v = 0; v < Nv; ++v)
21429db5b827SMatthew G. Knepley                   if (verts[v] == pclosure[pcl]) break;
21439db5b827SMatthew 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);
21449db5b827SMatthew G. Knepley                 for (PetscInt d = 0; d < coordDim; ++d) pointCoords[off++] = (PetscReal)coords[cone[v] * 3 + d];
21459db5b827SMatthew G. Knepley                 ++v;
21469db5b827SMatthew G. Knepley               }
21479db5b827SMatthew G. Knepley             }
21489db5b827SMatthew G. Knepley             PetscCall(DMPlexRestoreTransitiveClosure(cdmCell, point, PETSC_TRUE, &Npcl, &pclosure));
21499db5b827SMatthew G. Knepley           }
21509db5b827SMatthew G. Knepley         }
21519db5b827SMatthew G. Knepley         PetscCall(DMPlexRestoreTransitiveClosure(cdmCell, c, PETSC_TRUE, &Ncl, &closure));
2152331830f3SMatthew G. Knepley       }
21536858538eSMatthew G. Knepley       PetscCall(VecSetBlockSize(coordinatesCell, coordDim));
21546858538eSMatthew G. Knepley       PetscCall(VecRestoreArray(coordinatesCell, &pointCoords));
21556858538eSMatthew G. Knepley       PetscCall(DMSetCellCoordinatesLocal(*dm, coordinatesCell));
21566858538eSMatthew G. Knepley       PetscCall(VecDestroy(&coordinatesCell));
2157331830f3SMatthew G. Knepley     }
21589db5b827SMatthew G. Knepley     PetscCall(PetscFree(nodeMap));
21596858538eSMatthew G. Knepley     PetscCall(PetscSectionDestroy(&csCell));
21606858538eSMatthew G. Knepley     PetscCall(DMDestroy(&cdmCell));
2161066ea43fSLisandro Dalcin   }
2162066ea43fSLisandro Dalcin 
21639566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates"));
21649566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(coordinates, coordDim));
21659566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinatesLocal(*dm, coordinates));
21669566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&coordinates));
216711c56cb0SLisandro Dalcin 
21689566063dSJacob Faibussowitsch   PetscCall(GmshMeshDestroy(&mesh));
21699566063dSJacob Faibussowitsch   PetscCall(PetscBTDestroy(&periodicVerts));
2170eae3dc7dSJacob Faibussowitsch   if (periodic) {
2171eae3dc7dSJacob Faibussowitsch     for (PetscInt h = 0; h <= maxHeight; ++h) PetscCall(PetscBTDestroy(periodicCells + h));
2172eae3dc7dSJacob Faibussowitsch     PetscCall(PetscFree(periodicCells));
2173eae3dc7dSJacob Faibussowitsch   }
217411c56cb0SLisandro Dalcin 
2175066ea43fSLisandro Dalcin   if (highOrder && project) {
2176066ea43fSLisandro Dalcin     PetscFE         fe;
2177066ea43fSLisandro Dalcin     const char      prefix[]   = "dm_plex_gmsh_project_";
2178066ea43fSLisandro Dalcin     PetscBool       continuity = periodic ? PETSC_FALSE : PETSC_TRUE;
2179066ea43fSLisandro Dalcin     PetscDTNodeType nodeType   = PETSCDTNODES_GAUSSJACOBI;
2180066ea43fSLisandro Dalcin 
2181066ea43fSLisandro Dalcin     if (isSimplex) continuity = PETSC_FALSE; /* XXX FIXME Requires DMPlexSetClosurePermutationLexicographic() */
21829566063dSJacob Faibussowitsch     PetscCall(GmshCreateFE(comm, prefix, isSimplex, continuity, nodeType, dim, coordDim, order, &fe));
21839566063dSJacob Faibussowitsch     PetscCall(PetscFEViewFromOptions(fe, NULL, "-dm_plex_gmsh_project_fe_view"));
2184e44f6aebSMatthew G. Knepley     PetscCall(DMSetCoordinateDisc(*dm, fe, PETSC_TRUE));
21859566063dSJacob Faibussowitsch     PetscCall(PetscFEDestroy(&fe));
2186066ea43fSLisandro Dalcin   }
2187066ea43fSLisandro Dalcin 
21889566063dSJacob Faibussowitsch   PetscCall(PetscLogEventEnd(DMPLEX_CreateGmsh, *dm, NULL, NULL, NULL));
21893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2190331830f3SMatthew G. Knepley }
2191