xref: /petsc/src/dm/impls/plex/plexgmsh.c (revision 5f80ce2ab25dff0f4601e710601cbbcecf323266)
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)                                   \
8066ea43fSLisandro Dalcin static int *GmshLexOrder_##T##_##p(void)                           \
9066ea43fSLisandro Dalcin {                                                                  \
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 
16b9bf55e5SMatthew G. Knepley static int *GmshLexOrder_QUA_2_Serendipity(void)
17b9bf55e5SMatthew G. Knepley {
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 */
22b9bf55e5SMatthew G. Knepley     lex[0] = 0; lex[2] = 1; lex[8] = 2; lex[6] = 3;
23b9bf55e5SMatthew G. Knepley     /* Edges */
24b9bf55e5SMatthew G. Knepley     lex[1] = 4; lex[5] = 5; lex[7] = 6; lex[3] = 7;
25b9bf55e5SMatthew G. Knepley     /* Cell */
26b9bf55e5SMatthew G. Knepley     lex[4] = -8;
27b9bf55e5SMatthew G. Knepley   }
28b9bf55e5SMatthew G. Knepley   return lex;
29b9bf55e5SMatthew G. Knepley }
30b9bf55e5SMatthew G. Knepley 
31b9bf55e5SMatthew G. Knepley static int *GmshLexOrder_HEX_2_Serendipity(void)
32b9bf55e5SMatthew G. Knepley {
33b9bf55e5SMatthew G. Knepley   static int Gmsh_LexOrder_HEX_2_Serendipity[27] = {-1};
34b9bf55e5SMatthew G. Knepley   int *lex = Gmsh_LexOrder_HEX_2_Serendipity;
35b9bf55e5SMatthew G. Knepley   if (lex[0] == -1) {
36b9bf55e5SMatthew G. Knepley     /* Vertices */
37b9bf55e5SMatthew G. Knepley     lex[ 0] =   0; lex[ 2] =   1; lex[ 8] =   2; lex[ 6] =   3;
38b9bf55e5SMatthew G. Knepley     lex[18] =   4; lex[20] =   5; lex[26] =   6; lex[24] =   7;
39b9bf55e5SMatthew G. Knepley     /* Edges */
40b9bf55e5SMatthew G. Knepley     lex[ 1] =   8; lex[ 3] =   9; lex[ 9] =  10; lex[ 5] =  11;
41b9bf55e5SMatthew G. Knepley     lex[11] =  12; lex[ 7] =  13; lex[17] =  14; lex[15] =  15;
42b9bf55e5SMatthew G. Knepley     lex[19] =  16; lex[21] =  17; lex[23] =  18; lex[25] =  19;
43b9bf55e5SMatthew G. Knepley     /* Faces */
44b9bf55e5SMatthew G. Knepley     lex[ 4] = -20; lex[10] = -21; lex[12] = -22; lex[14] = -23;
45b9bf55e5SMatthew G. Knepley     lex[16] = -24; lex[22] = -25;
46b9bf55e5SMatthew G. Knepley     /* Cell */
47b9bf55e5SMatthew G. Knepley     lex[13] = -26;
48b9bf55e5SMatthew G. Knepley   }
49b9bf55e5SMatthew G. Knepley   return lex;
50b9bf55e5SMatthew G. Knepley }
51b9bf55e5SMatthew G. Knepley 
52066ea43fSLisandro Dalcin #define GMSH_LEXORDER_LIST(T) \
53066ea43fSLisandro Dalcin GMSH_LEXORDER_ITEM(T,  1)     \
54066ea43fSLisandro Dalcin GMSH_LEXORDER_ITEM(T,  2)     \
55066ea43fSLisandro Dalcin GMSH_LEXORDER_ITEM(T,  3)     \
56066ea43fSLisandro Dalcin GMSH_LEXORDER_ITEM(T,  4)     \
57066ea43fSLisandro Dalcin GMSH_LEXORDER_ITEM(T,  5)     \
58066ea43fSLisandro Dalcin GMSH_LEXORDER_ITEM(T,  6)     \
59066ea43fSLisandro Dalcin GMSH_LEXORDER_ITEM(T,  7)     \
60066ea43fSLisandro Dalcin GMSH_LEXORDER_ITEM(T,  8)     \
61066ea43fSLisandro Dalcin GMSH_LEXORDER_ITEM(T,  9)     \
62066ea43fSLisandro Dalcin GMSH_LEXORDER_ITEM(T, 10)
63066ea43fSLisandro Dalcin 
64066ea43fSLisandro Dalcin GMSH_LEXORDER_ITEM(VTX, 0)
65066ea43fSLisandro Dalcin GMSH_LEXORDER_LIST(SEG)
66066ea43fSLisandro Dalcin GMSH_LEXORDER_LIST(TRI)
67066ea43fSLisandro Dalcin GMSH_LEXORDER_LIST(QUA)
68066ea43fSLisandro Dalcin GMSH_LEXORDER_LIST(TET)
69066ea43fSLisandro Dalcin GMSH_LEXORDER_LIST(HEX)
70066ea43fSLisandro Dalcin GMSH_LEXORDER_LIST(PRI)
71066ea43fSLisandro Dalcin GMSH_LEXORDER_LIST(PYR)
72066ea43fSLisandro Dalcin 
73066ea43fSLisandro Dalcin typedef enum {
74066ea43fSLisandro Dalcin   GMSH_VTX = 0,
75066ea43fSLisandro Dalcin   GMSH_SEG = 1,
76066ea43fSLisandro Dalcin   GMSH_TRI = 2,
77066ea43fSLisandro Dalcin   GMSH_QUA = 3,
78066ea43fSLisandro Dalcin   GMSH_TET = 4,
79066ea43fSLisandro Dalcin   GMSH_HEX = 5,
80066ea43fSLisandro Dalcin   GMSH_PRI = 6,
81066ea43fSLisandro Dalcin   GMSH_PYR = 7,
82066ea43fSLisandro Dalcin   GMSH_NUM_POLYTOPES = 8
83066ea43fSLisandro Dalcin } GmshPolytopeType;
84066ea43fSLisandro Dalcin 
85de78e4feSLisandro Dalcin typedef struct {
860598e1a2SLisandro Dalcin   int   cellType;
87066ea43fSLisandro Dalcin   int   polytope;
880598e1a2SLisandro Dalcin   int   dim;
890598e1a2SLisandro Dalcin   int   order;
90066ea43fSLisandro Dalcin   int   numVerts;
910598e1a2SLisandro Dalcin   int   numNodes;
92066ea43fSLisandro Dalcin   int* (*lexorder)(void);
930598e1a2SLisandro Dalcin } GmshCellInfo;
940598e1a2SLisandro Dalcin 
95066ea43fSLisandro Dalcin #define GmshCellEntry(cellType, polytope, dim, order) \
96066ea43fSLisandro Dalcin   {cellType, GMSH_##polytope, dim, order, \
97066ea43fSLisandro Dalcin    GmshNumNodes_##polytope(1), \
98066ea43fSLisandro Dalcin    GmshNumNodes_##polytope(order), \
99066ea43fSLisandro Dalcin    GmshLexOrder_##polytope##_##order}
1000598e1a2SLisandro Dalcin 
1010598e1a2SLisandro Dalcin static const GmshCellInfo GmshCellTable[] = {
102066ea43fSLisandro Dalcin   GmshCellEntry( 15, VTX, 0,  0),
1030598e1a2SLisandro Dalcin 
104066ea43fSLisandro Dalcin   GmshCellEntry(  1, SEG, 1,  1),
105066ea43fSLisandro Dalcin   GmshCellEntry(  8, SEG, 1,  2),
106066ea43fSLisandro Dalcin   GmshCellEntry( 26, SEG, 1,  3),
107066ea43fSLisandro Dalcin   GmshCellEntry( 27, SEG, 1,  4),
108066ea43fSLisandro Dalcin   GmshCellEntry( 28, SEG, 1,  5),
109066ea43fSLisandro Dalcin   GmshCellEntry( 62, SEG, 1,  6),
110066ea43fSLisandro Dalcin   GmshCellEntry( 63, SEG, 1,  7),
111066ea43fSLisandro Dalcin   GmshCellEntry( 64, SEG, 1,  8),
112066ea43fSLisandro Dalcin   GmshCellEntry( 65, SEG, 1,  9),
113066ea43fSLisandro Dalcin   GmshCellEntry( 66, SEG, 1, 10),
1140598e1a2SLisandro Dalcin 
115066ea43fSLisandro Dalcin   GmshCellEntry(  2, TRI, 2,  1),
116066ea43fSLisandro Dalcin   GmshCellEntry(  9, TRI, 2,  2),
117066ea43fSLisandro Dalcin   GmshCellEntry( 21, TRI, 2,  3),
118066ea43fSLisandro Dalcin   GmshCellEntry( 23, TRI, 2,  4),
119066ea43fSLisandro Dalcin   GmshCellEntry( 25, TRI, 2,  5),
120066ea43fSLisandro Dalcin   GmshCellEntry( 42, TRI, 2,  6),
121066ea43fSLisandro Dalcin   GmshCellEntry( 43, TRI, 2,  7),
122066ea43fSLisandro Dalcin   GmshCellEntry( 44, TRI, 2,  8),
123066ea43fSLisandro Dalcin   GmshCellEntry( 45, TRI, 2,  9),
124066ea43fSLisandro Dalcin   GmshCellEntry( 46, TRI, 2, 10),
1250598e1a2SLisandro Dalcin 
126066ea43fSLisandro Dalcin   GmshCellEntry(  3, QUA, 2,  1),
127066ea43fSLisandro Dalcin   GmshCellEntry( 10, QUA, 2,  2),
128b9bf55e5SMatthew G. Knepley   {16, GMSH_QUA, 2, 2, 4, 8, GmshLexOrder_QUA_2_Serendipity},
129066ea43fSLisandro Dalcin   GmshCellEntry( 36, QUA, 2,  3),
130066ea43fSLisandro Dalcin   GmshCellEntry( 37, QUA, 2,  4),
131066ea43fSLisandro Dalcin   GmshCellEntry( 38, QUA, 2,  5),
132066ea43fSLisandro Dalcin   GmshCellEntry( 47, QUA, 2,  6),
133066ea43fSLisandro Dalcin   GmshCellEntry( 48, QUA, 2,  7),
134066ea43fSLisandro Dalcin   GmshCellEntry( 49, QUA, 2,  8),
135066ea43fSLisandro Dalcin   GmshCellEntry( 50, QUA, 2,  9),
136066ea43fSLisandro Dalcin   GmshCellEntry( 51, QUA, 2, 10),
1370598e1a2SLisandro Dalcin 
138066ea43fSLisandro Dalcin   GmshCellEntry(  4, TET, 3,  1),
139066ea43fSLisandro Dalcin   GmshCellEntry( 11, TET, 3,  2),
140066ea43fSLisandro Dalcin   GmshCellEntry( 29, TET, 3,  3),
141066ea43fSLisandro Dalcin   GmshCellEntry( 30, TET, 3,  4),
142066ea43fSLisandro Dalcin   GmshCellEntry( 31, TET, 3,  5),
143066ea43fSLisandro Dalcin   GmshCellEntry( 71, TET, 3,  6),
144066ea43fSLisandro Dalcin   GmshCellEntry( 72, TET, 3,  7),
145066ea43fSLisandro Dalcin   GmshCellEntry( 73, TET, 3,  8),
146066ea43fSLisandro Dalcin   GmshCellEntry( 74, TET, 3,  9),
147066ea43fSLisandro Dalcin   GmshCellEntry( 75, TET, 3, 10),
1480598e1a2SLisandro Dalcin 
149066ea43fSLisandro Dalcin   GmshCellEntry(  5, HEX, 3,  1),
150066ea43fSLisandro Dalcin   GmshCellEntry( 12, HEX, 3,  2),
151b9bf55e5SMatthew G. Knepley   {17, GMSH_HEX, 3, 2, 8, 20, GmshLexOrder_HEX_2_Serendipity},
152066ea43fSLisandro Dalcin   GmshCellEntry( 92, HEX, 3,  3),
153066ea43fSLisandro Dalcin   GmshCellEntry( 93, HEX, 3,  4),
154066ea43fSLisandro Dalcin   GmshCellEntry( 94, HEX, 3,  5),
155066ea43fSLisandro Dalcin   GmshCellEntry( 95, HEX, 3,  6),
156066ea43fSLisandro Dalcin   GmshCellEntry( 96, HEX, 3,  7),
157066ea43fSLisandro Dalcin   GmshCellEntry( 97, HEX, 3,  8),
158066ea43fSLisandro Dalcin   GmshCellEntry( 98, HEX, 3,  9),
159066ea43fSLisandro Dalcin   GmshCellEntry( -1, HEX, 3, 10),
1600598e1a2SLisandro Dalcin 
161066ea43fSLisandro Dalcin   GmshCellEntry(  6, PRI, 3,  1),
162066ea43fSLisandro Dalcin   GmshCellEntry( 13, PRI, 3,  2),
163066ea43fSLisandro Dalcin   GmshCellEntry( 90, PRI, 3,  3),
164066ea43fSLisandro Dalcin   GmshCellEntry( 91, PRI, 3,  4),
165066ea43fSLisandro Dalcin   GmshCellEntry(106, PRI, 3,  5),
166066ea43fSLisandro Dalcin   GmshCellEntry(107, PRI, 3,  6),
167066ea43fSLisandro Dalcin   GmshCellEntry(108, PRI, 3,  7),
168066ea43fSLisandro Dalcin   GmshCellEntry(109, PRI, 3,  8),
169066ea43fSLisandro Dalcin   GmshCellEntry(110, PRI, 3,  9),
170066ea43fSLisandro Dalcin   GmshCellEntry( -1, PRI, 3, 10),
1710598e1a2SLisandro Dalcin 
172066ea43fSLisandro Dalcin   GmshCellEntry(  7, PYR, 3,  1),
173066ea43fSLisandro Dalcin   GmshCellEntry( 14, PYR, 3,  2),
174066ea43fSLisandro Dalcin   GmshCellEntry(118, PYR, 3,  3),
175066ea43fSLisandro Dalcin   GmshCellEntry(119, PYR, 3,  4),
176066ea43fSLisandro Dalcin   GmshCellEntry(120, PYR, 3,  5),
177066ea43fSLisandro Dalcin   GmshCellEntry(121, PYR, 3,  6),
178066ea43fSLisandro Dalcin   GmshCellEntry(122, PYR, 3,  7),
179066ea43fSLisandro Dalcin   GmshCellEntry(123, PYR, 3,  8),
180066ea43fSLisandro Dalcin   GmshCellEntry(124, PYR, 3,  9),
181066ea43fSLisandro Dalcin   GmshCellEntry( -1, PYR, 3, 10)
1820598e1a2SLisandro Dalcin 
1830598e1a2SLisandro Dalcin #if 0
184066ea43fSLisandro Dalcin   {20, GMSH_TRI, 2, 3, 3,  9, NULL},
185066ea43fSLisandro Dalcin   {18, GMSH_PRI, 3, 2, 6, 15, NULL},
186066ea43fSLisandro Dalcin   {19, GMSH_PYR, 3, 2, 5, 13, NULL},
1870598e1a2SLisandro Dalcin #endif
1880598e1a2SLisandro Dalcin };
1890598e1a2SLisandro Dalcin 
1900598e1a2SLisandro Dalcin static GmshCellInfo GmshCellMap[150];
1910598e1a2SLisandro Dalcin 
1920598e1a2SLisandro Dalcin static PetscErrorCode GmshCellInfoSetUp(void)
1930598e1a2SLisandro Dalcin {
1940598e1a2SLisandro Dalcin   size_t           i, n;
1950598e1a2SLisandro Dalcin   static PetscBool called = PETSC_FALSE;
1960598e1a2SLisandro Dalcin 
1970598e1a2SLisandro Dalcin   if (called) return 0;
1980598e1a2SLisandro Dalcin   PetscFunctionBegin;
1990598e1a2SLisandro Dalcin   called = PETSC_TRUE;
2000598e1a2SLisandro Dalcin   n = sizeof(GmshCellMap)/sizeof(GmshCellMap[0]);
2010598e1a2SLisandro Dalcin   for (i = 0; i < n; ++i) {
2020598e1a2SLisandro Dalcin     GmshCellMap[i].cellType = -1;
203066ea43fSLisandro Dalcin     GmshCellMap[i].polytope = -1;
2040598e1a2SLisandro Dalcin   }
2050598e1a2SLisandro Dalcin   n = sizeof(GmshCellTable)/sizeof(GmshCellTable[0]);
206066ea43fSLisandro Dalcin   for (i = 0; i < n; ++i) {
207066ea43fSLisandro Dalcin     if (GmshCellTable[i].cellType <= 0) continue;
208066ea43fSLisandro Dalcin     GmshCellMap[GmshCellTable[i].cellType] = GmshCellTable[i];
209066ea43fSLisandro Dalcin   }
2100598e1a2SLisandro Dalcin   PetscFunctionReturn(0);
2110598e1a2SLisandro Dalcin }
2120598e1a2SLisandro Dalcin 
2130598e1a2SLisandro Dalcin #define GmshCellTypeCheck(ct) 0; do { \
2140598e1a2SLisandro Dalcin     const int _ct_ = (int)ct; \
2150598e1a2SLisandro Dalcin     if (_ct_ < 0 || _ct_ >= (int)(sizeof(GmshCellMap)/sizeof(GmshCellMap[0]))) \
21698921bdaSJacob Faibussowitsch       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid Gmsh element type %d", _ct_); \
2170598e1a2SLisandro Dalcin     if (GmshCellMap[_ct_].cellType != _ct_) \
21898921bdaSJacob Faibussowitsch       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported Gmsh element type %d", _ct_); \
219066ea43fSLisandro Dalcin     if (GmshCellMap[_ct_].polytope == -1) \
22098921bdaSJacob Faibussowitsch       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported Gmsh element type %d", _ct_); \
2210598e1a2SLisandro Dalcin   } while (0)
2220598e1a2SLisandro Dalcin 
2230598e1a2SLisandro Dalcin typedef struct {
224698a79b9SLisandro Dalcin   PetscViewer  viewer;
225698a79b9SLisandro Dalcin   int          fileFormat;
226698a79b9SLisandro Dalcin   int          dataSize;
227698a79b9SLisandro Dalcin   PetscBool    binary;
228698a79b9SLisandro Dalcin   PetscBool    byteSwap;
229698a79b9SLisandro Dalcin   size_t       wlen;
230698a79b9SLisandro Dalcin   void        *wbuf;
231698a79b9SLisandro Dalcin   size_t       slen;
232698a79b9SLisandro Dalcin   void        *sbuf;
2330598e1a2SLisandro Dalcin   PetscInt    *nbuf;
2340598e1a2SLisandro Dalcin   PetscInt     nodeStart;
2350598e1a2SLisandro Dalcin   PetscInt     nodeEnd;
23633a088b6SMatthew G. Knepley   PetscInt    *nodeMap;
237698a79b9SLisandro Dalcin } GmshFile;
238de78e4feSLisandro Dalcin 
239698a79b9SLisandro Dalcin static PetscErrorCode GmshBufferGet(GmshFile *gmsh, size_t count, size_t eltsize, void *buf)
240de78e4feSLisandro Dalcin {
241de78e4feSLisandro Dalcin   size_t         size = count * eltsize;
24211c56cb0SLisandro Dalcin 
24311c56cb0SLisandro Dalcin   PetscFunctionBegin;
244698a79b9SLisandro Dalcin   if (gmsh->wlen < size) {
245*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(gmsh->wbuf));
246*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc(size, &gmsh->wbuf));
247698a79b9SLisandro Dalcin     gmsh->wlen = size;
248de78e4feSLisandro Dalcin   }
249698a79b9SLisandro Dalcin   *(void**)buf = size ? gmsh->wbuf : NULL;
250de78e4feSLisandro Dalcin   PetscFunctionReturn(0);
251de78e4feSLisandro Dalcin }
252de78e4feSLisandro Dalcin 
253698a79b9SLisandro Dalcin static PetscErrorCode GmshBufferSizeGet(GmshFile *gmsh, size_t count, void *buf)
254698a79b9SLisandro Dalcin {
255698a79b9SLisandro Dalcin   size_t         dataSize = (size_t)gmsh->dataSize;
256698a79b9SLisandro Dalcin   size_t         size = count * dataSize;
257698a79b9SLisandro Dalcin 
258698a79b9SLisandro Dalcin   PetscFunctionBegin;
259698a79b9SLisandro Dalcin   if (gmsh->slen < size) {
260*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(gmsh->sbuf));
261*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc(size, &gmsh->sbuf));
262698a79b9SLisandro Dalcin     gmsh->slen = size;
263698a79b9SLisandro Dalcin   }
264698a79b9SLisandro Dalcin   *(void**)buf = size ? gmsh->sbuf : NULL;
265698a79b9SLisandro Dalcin   PetscFunctionReturn(0);
266698a79b9SLisandro Dalcin }
267698a79b9SLisandro Dalcin 
268698a79b9SLisandro Dalcin static PetscErrorCode GmshRead(GmshFile *gmsh, void *buf, PetscInt count, PetscDataType dtype)
269de78e4feSLisandro Dalcin {
270de78e4feSLisandro Dalcin   PetscFunctionBegin;
271*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscViewerRead(gmsh->viewer, buf, count, NULL, dtype));
272*5f80ce2aSJacob Faibussowitsch   if (gmsh->byteSwap) CHKERRQ(PetscByteSwap(buf, dtype, count));
273698a79b9SLisandro Dalcin   PetscFunctionReturn(0);
274698a79b9SLisandro Dalcin }
275698a79b9SLisandro Dalcin 
276698a79b9SLisandro Dalcin static PetscErrorCode GmshReadString(GmshFile *gmsh, char *buf, PetscInt count)
277698a79b9SLisandro Dalcin {
278698a79b9SLisandro Dalcin   PetscFunctionBegin;
279*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscViewerRead(gmsh->viewer, buf, count, NULL, PETSC_STRING));
280698a79b9SLisandro Dalcin   PetscFunctionReturn(0);
281698a79b9SLisandro Dalcin }
282698a79b9SLisandro Dalcin 
283d6689ca9SLisandro Dalcin static PetscErrorCode GmshMatch(PETSC_UNUSED GmshFile *gmsh, const char Section[], char line[PETSC_MAX_PATH_LEN], PetscBool *match)
284d6689ca9SLisandro Dalcin {
285d6689ca9SLisandro Dalcin   PetscFunctionBegin;
286*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscStrcmp(line, Section, match));
287d6689ca9SLisandro Dalcin   PetscFunctionReturn(0);
288d6689ca9SLisandro Dalcin }
289d6689ca9SLisandro Dalcin 
290d6689ca9SLisandro Dalcin static PetscErrorCode GmshExpect(GmshFile *gmsh, const char Section[], char line[PETSC_MAX_PATH_LEN])
291d6689ca9SLisandro Dalcin {
292d6689ca9SLisandro Dalcin   PetscBool      match;
293d6689ca9SLisandro Dalcin 
294d6689ca9SLisandro Dalcin   PetscFunctionBegin;
295*5f80ce2aSJacob Faibussowitsch   CHKERRQ(GmshMatch(gmsh, Section, line, &match));
2962c71b3e2SJacob Faibussowitsch   PetscCheckFalse(!match,PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file, expecting %s",Section);
297d6689ca9SLisandro Dalcin   PetscFunctionReturn(0);
298d6689ca9SLisandro Dalcin }
299d6689ca9SLisandro Dalcin 
300d6689ca9SLisandro Dalcin static PetscErrorCode GmshReadSection(GmshFile *gmsh, char line[PETSC_MAX_PATH_LEN])
301d6689ca9SLisandro Dalcin {
302d6689ca9SLisandro Dalcin   PetscBool      match;
303d6689ca9SLisandro Dalcin 
304d6689ca9SLisandro Dalcin   PetscFunctionBegin;
305d6689ca9SLisandro Dalcin   while (PETSC_TRUE) {
306*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshReadString(gmsh, line, 1));
307*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshMatch(gmsh, "$Comments", line, &match));
308d6689ca9SLisandro Dalcin     if (!match) break;
309d6689ca9SLisandro Dalcin     while (PETSC_TRUE) {
310*5f80ce2aSJacob Faibussowitsch       CHKERRQ(GmshReadString(gmsh, line, 1));
311*5f80ce2aSJacob Faibussowitsch       CHKERRQ(GmshMatch(gmsh, "$EndComments", line, &match));
312d6689ca9SLisandro Dalcin       if (match) break;
313d6689ca9SLisandro Dalcin     }
314d6689ca9SLisandro Dalcin   }
315d6689ca9SLisandro Dalcin   PetscFunctionReturn(0);
316d6689ca9SLisandro Dalcin }
317d6689ca9SLisandro Dalcin 
318d6689ca9SLisandro Dalcin static PetscErrorCode GmshReadEndSection(GmshFile *gmsh, const char EndSection[], char line[PETSC_MAX_PATH_LEN])
319d6689ca9SLisandro Dalcin {
320d6689ca9SLisandro Dalcin   PetscFunctionBegin;
321*5f80ce2aSJacob Faibussowitsch   CHKERRQ(GmshReadString(gmsh, line, 1));
322*5f80ce2aSJacob Faibussowitsch   CHKERRQ(GmshExpect(gmsh, EndSection, line));
323d6689ca9SLisandro Dalcin   PetscFunctionReturn(0);
324d6689ca9SLisandro Dalcin }
325d6689ca9SLisandro Dalcin 
326698a79b9SLisandro Dalcin static PetscErrorCode GmshReadSize(GmshFile *gmsh, PetscInt *buf, PetscInt count)
327698a79b9SLisandro Dalcin {
328698a79b9SLisandro Dalcin   PetscInt       i;
329698a79b9SLisandro Dalcin   size_t         dataSize = (size_t)gmsh->dataSize;
330698a79b9SLisandro Dalcin 
331698a79b9SLisandro Dalcin   PetscFunctionBegin;
332698a79b9SLisandro Dalcin   if (dataSize == sizeof(PetscInt)) {
333*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshRead(gmsh, buf, count, PETSC_INT));
334698a79b9SLisandro Dalcin   } else  if (dataSize == sizeof(int)) {
335698a79b9SLisandro Dalcin     int *ibuf = NULL;
336*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshBufferSizeGet(gmsh, count, &ibuf));
337*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshRead(gmsh, ibuf, count, PETSC_ENUM));
338698a79b9SLisandro Dalcin     for (i = 0; i < count; ++i) buf[i] = (PetscInt)ibuf[i];
339698a79b9SLisandro Dalcin   } else  if (dataSize == sizeof(long)) {
340698a79b9SLisandro Dalcin     long *ibuf = NULL;
341*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshBufferSizeGet(gmsh, count, &ibuf));
342*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshRead(gmsh, ibuf, count, PETSC_LONG));
343698a79b9SLisandro Dalcin     for (i = 0; i < count; ++i) buf[i] = (PetscInt)ibuf[i];
344698a79b9SLisandro Dalcin   } else if (dataSize == sizeof(PetscInt64)) {
345698a79b9SLisandro Dalcin     PetscInt64 *ibuf = NULL;
346*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshBufferSizeGet(gmsh, count, &ibuf));
347*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshRead(gmsh, ibuf, count, PETSC_INT64));
348698a79b9SLisandro Dalcin     for (i = 0; i < count; ++i) buf[i] = (PetscInt)ibuf[i];
349698a79b9SLisandro Dalcin   }
350698a79b9SLisandro Dalcin   PetscFunctionReturn(0);
351698a79b9SLisandro Dalcin }
352698a79b9SLisandro Dalcin 
353698a79b9SLisandro Dalcin static PetscErrorCode GmshReadInt(GmshFile *gmsh, int *buf, PetscInt count)
354698a79b9SLisandro Dalcin {
355698a79b9SLisandro Dalcin   PetscFunctionBegin;
356*5f80ce2aSJacob Faibussowitsch   CHKERRQ(GmshRead(gmsh, buf, count, PETSC_ENUM));
357698a79b9SLisandro Dalcin   PetscFunctionReturn(0);
358698a79b9SLisandro Dalcin }
359698a79b9SLisandro Dalcin 
360698a79b9SLisandro Dalcin static PetscErrorCode GmshReadDouble(GmshFile *gmsh, double *buf, PetscInt count)
361698a79b9SLisandro Dalcin {
362698a79b9SLisandro Dalcin   PetscFunctionBegin;
363*5f80ce2aSJacob Faibussowitsch   CHKERRQ(GmshRead(gmsh, buf, count, PETSC_DOUBLE));
364de78e4feSLisandro Dalcin   PetscFunctionReturn(0);
365de78e4feSLisandro Dalcin }
366de78e4feSLisandro Dalcin 
367de78e4feSLisandro Dalcin typedef struct {
3680598e1a2SLisandro Dalcin   PetscInt id;       /* Entity ID */
3690598e1a2SLisandro Dalcin   PetscInt dim;      /* Dimension */
370de78e4feSLisandro Dalcin   double   bbox[6];  /* Bounding box */
371de78e4feSLisandro Dalcin   PetscInt numTags;  /* Size of tag array */
372de78e4feSLisandro Dalcin   int      tags[4];  /* Tag array */
373de78e4feSLisandro Dalcin } GmshEntity;
374de78e4feSLisandro Dalcin 
375de78e4feSLisandro Dalcin typedef struct {
376730356f6SLisandro Dalcin   GmshEntity *entity[4];
377730356f6SLisandro Dalcin   PetscHMapI  entityMap[4];
378730356f6SLisandro Dalcin } GmshEntities;
379730356f6SLisandro Dalcin 
380698a79b9SLisandro Dalcin static PetscErrorCode GmshEntitiesCreate(PetscInt count[4], GmshEntities **entities)
381730356f6SLisandro Dalcin {
382730356f6SLisandro Dalcin   PetscInt       dim;
383730356f6SLisandro Dalcin 
384730356f6SLisandro Dalcin   PetscFunctionBegin;
385*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscNew(entities));
386730356f6SLisandro Dalcin   for (dim = 0; dim < 4; ++dim) {
387*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscCalloc1(count[dim], &(*entities)->entity[dim]));
388*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscHMapICreate(&(*entities)->entityMap[dim]));
389730356f6SLisandro Dalcin   }
390730356f6SLisandro Dalcin   PetscFunctionReturn(0);
391730356f6SLisandro Dalcin }
392730356f6SLisandro Dalcin 
3930598e1a2SLisandro Dalcin static PetscErrorCode GmshEntitiesDestroy(GmshEntities **entities)
3940598e1a2SLisandro Dalcin {
3950598e1a2SLisandro Dalcin   PetscInt       dim;
3960598e1a2SLisandro Dalcin 
3970598e1a2SLisandro Dalcin   PetscFunctionBegin;
3980598e1a2SLisandro Dalcin   if (!*entities) PetscFunctionReturn(0);
3990598e1a2SLisandro Dalcin   for (dim = 0; dim < 4; ++dim) {
400*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree((*entities)->entity[dim]));
401*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscHMapIDestroy(&(*entities)->entityMap[dim]));
4020598e1a2SLisandro Dalcin   }
403*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree((*entities)));
4040598e1a2SLisandro Dalcin   PetscFunctionReturn(0);
4050598e1a2SLisandro Dalcin }
4060598e1a2SLisandro Dalcin 
407730356f6SLisandro Dalcin static PetscErrorCode GmshEntitiesAdd(GmshEntities *entities, PetscInt index, PetscInt dim, PetscInt eid, GmshEntity** entity)
408730356f6SLisandro Dalcin {
409730356f6SLisandro Dalcin   PetscFunctionBegin;
410*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscHMapISet(entities->entityMap[dim], eid, index));
411730356f6SLisandro Dalcin   entities->entity[dim][index].dim = dim;
412730356f6SLisandro Dalcin   entities->entity[dim][index].id  = eid;
413730356f6SLisandro Dalcin   if (entity) *entity = &entities->entity[dim][index];
414730356f6SLisandro Dalcin   PetscFunctionReturn(0);
415730356f6SLisandro Dalcin }
416730356f6SLisandro Dalcin 
417730356f6SLisandro Dalcin static PetscErrorCode GmshEntitiesGet(GmshEntities *entities, PetscInt dim, PetscInt eid, GmshEntity** entity)
418730356f6SLisandro Dalcin {
419730356f6SLisandro Dalcin   PetscInt       index;
420730356f6SLisandro Dalcin 
421730356f6SLisandro Dalcin   PetscFunctionBegin;
422*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscHMapIGet(entities->entityMap[dim], eid, &index));
423730356f6SLisandro Dalcin   *entity = &entities->entity[dim][index];
424730356f6SLisandro Dalcin   PetscFunctionReturn(0);
425730356f6SLisandro Dalcin }
426730356f6SLisandro Dalcin 
4270598e1a2SLisandro Dalcin typedef struct {
4280598e1a2SLisandro Dalcin   PetscInt *id;  /* Node IDs */
4290598e1a2SLisandro Dalcin   double   *xyz; /* Coordinates */
43081a1af93SMatthew G. Knepley   PetscInt *tag; /* Physical tag */
4310598e1a2SLisandro Dalcin } GmshNodes;
4320598e1a2SLisandro Dalcin 
4330598e1a2SLisandro Dalcin static PetscErrorCode GmshNodesCreate(PetscInt count, GmshNodes **nodes)
434730356f6SLisandro Dalcin {
435730356f6SLisandro Dalcin   PetscFunctionBegin;
436*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscNew(nodes));
437*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(count*1, &(*nodes)->id));
438*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(count*3, &(*nodes)->xyz));
439*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(count*1, &(*nodes)->tag));
4400598e1a2SLisandro Dalcin   PetscFunctionReturn(0);
441730356f6SLisandro Dalcin }
4420598e1a2SLisandro Dalcin 
4430598e1a2SLisandro Dalcin static PetscErrorCode GmshNodesDestroy(GmshNodes **nodes)
4440598e1a2SLisandro Dalcin {
4450598e1a2SLisandro Dalcin   PetscFunctionBegin;
4460598e1a2SLisandro Dalcin   if (!*nodes) PetscFunctionReturn(0);
447*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree((*nodes)->id));
448*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree((*nodes)->xyz));
449*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree((*nodes)->tag));
450*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree((*nodes)));
451730356f6SLisandro Dalcin   PetscFunctionReturn(0);
452730356f6SLisandro Dalcin }
453730356f6SLisandro Dalcin 
454730356f6SLisandro Dalcin typedef struct {
4550598e1a2SLisandro Dalcin   PetscInt id;       /* Element ID */
4560598e1a2SLisandro Dalcin   PetscInt dim;      /* Dimension */
457de78e4feSLisandro Dalcin   PetscInt cellType; /* Cell type */
4580598e1a2SLisandro Dalcin   PetscInt numVerts; /* Size of vertex array */
459de78e4feSLisandro Dalcin   PetscInt numNodes; /* Size of node array */
4600598e1a2SLisandro Dalcin   PetscInt *nodes;   /* Vertex/Node array */
46181a1af93SMatthew G. Knepley   PetscInt numTags;  /* Size of physical tag array */
46281a1af93SMatthew G. Knepley   int      tags[4];  /* Physical tag array */
463de78e4feSLisandro Dalcin } GmshElement;
464de78e4feSLisandro Dalcin 
4650598e1a2SLisandro Dalcin static PetscErrorCode GmshElementsCreate(PetscInt count, GmshElement **elements)
4660598e1a2SLisandro Dalcin {
4670598e1a2SLisandro Dalcin   PetscFunctionBegin;
468*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscCalloc1(count, elements));
4690598e1a2SLisandro Dalcin   PetscFunctionReturn(0);
4700598e1a2SLisandro Dalcin }
4710598e1a2SLisandro Dalcin 
4720598e1a2SLisandro Dalcin static PetscErrorCode GmshElementsDestroy(GmshElement **elements)
4730598e1a2SLisandro Dalcin {
4740598e1a2SLisandro Dalcin   PetscFunctionBegin;
4750598e1a2SLisandro Dalcin   if (!*elements) PetscFunctionReturn(0);
476*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(*elements));
4770598e1a2SLisandro Dalcin   PetscFunctionReturn(0);
4780598e1a2SLisandro Dalcin }
4790598e1a2SLisandro Dalcin 
4800598e1a2SLisandro Dalcin typedef struct {
4810598e1a2SLisandro Dalcin   PetscInt       dim;
482066ea43fSLisandro Dalcin   PetscInt       order;
4830598e1a2SLisandro Dalcin   GmshEntities  *entities;
4840598e1a2SLisandro Dalcin   PetscInt       numNodes;
4850598e1a2SLisandro Dalcin   GmshNodes     *nodelist;
4860598e1a2SLisandro Dalcin   PetscInt       numElems;
4870598e1a2SLisandro Dalcin   GmshElement   *elements;
4880598e1a2SLisandro Dalcin   PetscInt       numVerts;
4890598e1a2SLisandro Dalcin   PetscInt       numCells;
4900598e1a2SLisandro Dalcin   PetscInt      *periodMap;
4910598e1a2SLisandro Dalcin   PetscInt      *vertexMap;
4920598e1a2SLisandro Dalcin   PetscSegBuffer segbuf;
493a45dabc8SMatthew G. Knepley   PetscInt       numRegions;
494a45dabc8SMatthew G. Knepley   PetscInt      *regionTags;
495a45dabc8SMatthew G. Knepley   char         **regionNames;
4960598e1a2SLisandro Dalcin } GmshMesh;
4970598e1a2SLisandro Dalcin 
4980598e1a2SLisandro Dalcin static PetscErrorCode GmshMeshCreate(GmshMesh **mesh)
4990598e1a2SLisandro Dalcin {
5000598e1a2SLisandro Dalcin   PetscFunctionBegin;
501*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscNew(mesh));
502*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSegBufferCreate(sizeof(PetscInt), 0, &(*mesh)->segbuf));
5030598e1a2SLisandro Dalcin   PetscFunctionReturn(0);
5040598e1a2SLisandro Dalcin }
5050598e1a2SLisandro Dalcin 
5060598e1a2SLisandro Dalcin static PetscErrorCode GmshMeshDestroy(GmshMesh **mesh)
5070598e1a2SLisandro Dalcin {
508a45dabc8SMatthew G. Knepley   PetscInt       r;
5090598e1a2SLisandro Dalcin 
5100598e1a2SLisandro Dalcin   PetscFunctionBegin;
5110598e1a2SLisandro Dalcin   if (!*mesh) PetscFunctionReturn(0);
512*5f80ce2aSJacob Faibussowitsch   CHKERRQ(GmshEntitiesDestroy(&(*mesh)->entities));
513*5f80ce2aSJacob Faibussowitsch   CHKERRQ(GmshNodesDestroy(&(*mesh)->nodelist));
514*5f80ce2aSJacob Faibussowitsch   CHKERRQ(GmshElementsDestroy(&(*mesh)->elements));
515*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree((*mesh)->periodMap));
516*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree((*mesh)->vertexMap));
517*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSegBufferDestroy(&(*mesh)->segbuf));
518*5f80ce2aSJacob Faibussowitsch   for (r = 0; r < (*mesh)->numRegions; ++r) CHKERRQ(PetscFree((*mesh)->regionNames[r]));
519*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree2((*mesh)->regionTags, (*mesh)->regionNames));
520*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree((*mesh)));
5210598e1a2SLisandro Dalcin   PetscFunctionReturn(0);
5220598e1a2SLisandro Dalcin }
5230598e1a2SLisandro Dalcin 
5240598e1a2SLisandro Dalcin static PetscErrorCode GmshReadNodes_v22(GmshFile *gmsh, GmshMesh *mesh)
525de78e4feSLisandro Dalcin {
526698a79b9SLisandro Dalcin   PetscViewer    viewer = gmsh->viewer;
527698a79b9SLisandro Dalcin   PetscBool      byteSwap = gmsh->byteSwap;
528de78e4feSLisandro Dalcin   char           line[PETSC_MAX_PATH_LEN];
5290598e1a2SLisandro Dalcin   int            n, num, nid, snum;
5300598e1a2SLisandro Dalcin   GmshNodes      *nodes;
531de78e4feSLisandro Dalcin 
532de78e4feSLisandro Dalcin   PetscFunctionBegin;
533*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING));
534698a79b9SLisandro Dalcin   snum = sscanf(line, "%d", &num);
5352c71b3e2SJacob Faibussowitsch   PetscCheckFalse(snum != 1,PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
536*5f80ce2aSJacob Faibussowitsch   CHKERRQ(GmshNodesCreate(num, &nodes));
5370598e1a2SLisandro Dalcin   mesh->numNodes = num;
5380598e1a2SLisandro Dalcin   mesh->nodelist = nodes;
5390598e1a2SLisandro Dalcin   for (n = 0; n < num; ++n) {
5400598e1a2SLisandro Dalcin     double *xyz = nodes->xyz + n*3;
541*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerRead(viewer, &nid, 1, NULL, PETSC_ENUM));
542*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerRead(viewer, xyz, 3, NULL, PETSC_DOUBLE));
543*5f80ce2aSJacob Faibussowitsch     if (byteSwap) CHKERRQ(PetscByteSwap(&nid, PETSC_ENUM, 1));
544*5f80ce2aSJacob Faibussowitsch     if (byteSwap) CHKERRQ(PetscByteSwap(xyz, PETSC_DOUBLE, 3));
5450598e1a2SLisandro Dalcin     nodes->id[n] = nid;
54681a1af93SMatthew G. Knepley     nodes->tag[n] = -1;
54711c56cb0SLisandro Dalcin   }
54811c56cb0SLisandro Dalcin   PetscFunctionReturn(0);
54911c56cb0SLisandro Dalcin }
55011c56cb0SLisandro Dalcin 
551de78e4feSLisandro Dalcin /* Gmsh elements can be of any dimension/co-dimension, so we need to traverse the
552de78e4feSLisandro Dalcin    file contents multiple times to figure out the true number of cells and facets
553de78e4feSLisandro Dalcin    in the given mesh. To make this more efficient we read the file contents only
554de78e4feSLisandro Dalcin    once and store them in memory, while determining the true number of cells. */
5550598e1a2SLisandro Dalcin static PetscErrorCode GmshReadElements_v22(GmshFile* gmsh, GmshMesh *mesh)
55611c56cb0SLisandro Dalcin {
557698a79b9SLisandro Dalcin   PetscViewer    viewer = gmsh->viewer;
558698a79b9SLisandro Dalcin   PetscBool      binary = gmsh->binary;
559698a79b9SLisandro Dalcin   PetscBool      byteSwap = gmsh->byteSwap;
560de78e4feSLisandro Dalcin   char           line[PETSC_MAX_PATH_LEN];
5610598e1a2SLisandro Dalcin   int            i, c, p, num, ibuf[1+4+1000], snum;
5620598e1a2SLisandro Dalcin   int            cellType, numElem, numVerts, numNodes, numTags;
563df032b82SMatthew G. Knepley   GmshElement   *elements;
5640598e1a2SLisandro Dalcin   PetscInt      *nodeMap = gmsh->nodeMap;
565df032b82SMatthew G. Knepley 
566df032b82SMatthew G. Knepley   PetscFunctionBegin;
567*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING));
568698a79b9SLisandro Dalcin   snum = sscanf(line, "%d", &num);
5692c71b3e2SJacob Faibussowitsch   PetscCheckFalse(snum != 1,PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
570*5f80ce2aSJacob Faibussowitsch   CHKERRQ(GmshElementsCreate(num, &elements));
5710598e1a2SLisandro Dalcin   mesh->numElems = num;
5720598e1a2SLisandro Dalcin   mesh->elements = elements;
573698a79b9SLisandro Dalcin   for (c = 0; c < num;) {
574*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerRead(viewer, ibuf, 3, NULL, PETSC_ENUM));
575*5f80ce2aSJacob Faibussowitsch     if (byteSwap) CHKERRQ(PetscByteSwap(ibuf, PETSC_ENUM, 3));
5760598e1a2SLisandro Dalcin 
5770598e1a2SLisandro Dalcin     cellType = binary ? ibuf[0] : ibuf[1];
5780598e1a2SLisandro Dalcin     numElem  = binary ? ibuf[1] : 1;
579df032b82SMatthew G. Knepley     numTags  = ibuf[2];
5800598e1a2SLisandro Dalcin 
581*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshCellTypeCheck(cellType));
5820598e1a2SLisandro Dalcin     numVerts = GmshCellMap[cellType].numVerts;
5830598e1a2SLisandro Dalcin     numNodes = GmshCellMap[cellType].numNodes;
5840598e1a2SLisandro Dalcin 
585df032b82SMatthew G. Knepley     for (i = 0; i < numElem; ++i, ++c) {
5860598e1a2SLisandro Dalcin       GmshElement *element = elements + c;
5870598e1a2SLisandro Dalcin       const int off = binary ? 0 : 1, nint = 1 + numTags + numNodes - off;
5880598e1a2SLisandro Dalcin       const int *id = ibuf, *nodes = ibuf + 1 + numTags, *tags = ibuf + 1;
589*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscViewerRead(viewer, ibuf+off, nint, NULL, PETSC_ENUM));
590*5f80ce2aSJacob Faibussowitsch       if (byteSwap) CHKERRQ(PetscByteSwap(ibuf+off, PETSC_ENUM, nint));
5910598e1a2SLisandro Dalcin       element->id  = id[0];
5920598e1a2SLisandro Dalcin       element->dim = GmshCellMap[cellType].dim;
5930598e1a2SLisandro Dalcin       element->cellType = cellType;
5940598e1a2SLisandro Dalcin       element->numVerts = numVerts;
5950598e1a2SLisandro Dalcin       element->numNodes = numNodes;
5960598e1a2SLisandro Dalcin       element->numTags  = PetscMin(numTags, 4);
597*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSegBufferGet(mesh->segbuf, (size_t)element->numNodes, &element->nodes));
5980598e1a2SLisandro Dalcin       for (p = 0; p < element->numNodes; p++) element->nodes[p] = nodeMap[nodes[p]];
5990598e1a2SLisandro Dalcin       for (p = 0; p < element->numTags;  p++) element->tags[p]  = tags[p];
600df032b82SMatthew G. Knepley     }
601df032b82SMatthew G. Knepley   }
602df032b82SMatthew G. Knepley   PetscFunctionReturn(0);
603df032b82SMatthew G. Knepley }
6047d282ae0SMichael Lange 
605de78e4feSLisandro Dalcin /*
606de78e4feSLisandro Dalcin $Entities
607de78e4feSLisandro Dalcin   numPoints(unsigned long) numCurves(unsigned long)
608de78e4feSLisandro Dalcin     numSurfaces(unsigned long) numVolumes(unsigned long)
609de78e4feSLisandro Dalcin   // points
610de78e4feSLisandro Dalcin   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
611de78e4feSLisandro Dalcin     boxMaxX(double) boxMaxY(double) boxMaxZ(double)
612de78e4feSLisandro Dalcin     numPhysicals(unsigned long) phyisicalTag[...](int)
613de78e4feSLisandro Dalcin   ...
614de78e4feSLisandro Dalcin   // curves
615de78e4feSLisandro Dalcin   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
616de78e4feSLisandro Dalcin      boxMaxX(double) boxMaxY(double) boxMaxZ(double)
617de78e4feSLisandro Dalcin      numPhysicals(unsigned long) physicalTag[...](int)
618de78e4feSLisandro Dalcin      numBREPVert(unsigned long) tagBREPVert[...](int)
619de78e4feSLisandro Dalcin   ...
620de78e4feSLisandro Dalcin   // surfaces
621de78e4feSLisandro Dalcin   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
622de78e4feSLisandro Dalcin     boxMaxX(double) boxMaxY(double) boxMaxZ(double)
623de78e4feSLisandro Dalcin     numPhysicals(unsigned long) physicalTag[...](int)
624de78e4feSLisandro Dalcin     numBREPCurve(unsigned long) tagBREPCurve[...](int)
625de78e4feSLisandro Dalcin   ...
626de78e4feSLisandro Dalcin   // volumes
627de78e4feSLisandro Dalcin   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
628de78e4feSLisandro Dalcin     boxMaxX(double) boxMaxY(double) boxMaxZ(double)
629de78e4feSLisandro Dalcin     numPhysicals(unsigned long) physicalTag[...](int)
630de78e4feSLisandro Dalcin     numBREPSurfaces(unsigned long) tagBREPSurfaces[...](int)
631de78e4feSLisandro Dalcin   ...
632de78e4feSLisandro Dalcin $EndEntities
633de78e4feSLisandro Dalcin */
6340598e1a2SLisandro Dalcin static PetscErrorCode GmshReadEntities_v40(GmshFile *gmsh, GmshMesh *mesh)
635de78e4feSLisandro Dalcin {
636698a79b9SLisandro Dalcin   PetscViewer    viewer = gmsh->viewer;
637698a79b9SLisandro Dalcin   PetscBool      byteSwap = gmsh->byteSwap;
638698a79b9SLisandro Dalcin   long           index, num, lbuf[4];
639730356f6SLisandro Dalcin   int            dim, eid, numTags, *ibuf, t;
640698a79b9SLisandro Dalcin   PetscInt       count[4], i;
641a5ba3d71SLisandro Dalcin   GmshEntity     *entity = NULL;
642de78e4feSLisandro Dalcin 
643de78e4feSLisandro Dalcin   PetscFunctionBegin;
644*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscViewerRead(viewer, lbuf, 4, NULL, PETSC_LONG));
645*5f80ce2aSJacob Faibussowitsch   if (byteSwap) CHKERRQ(PetscByteSwap(lbuf, PETSC_LONG, 4));
646698a79b9SLisandro Dalcin   for (i = 0; i < 4; ++i) count[i] = lbuf[i];
647*5f80ce2aSJacob Faibussowitsch   CHKERRQ(GmshEntitiesCreate(count, &mesh->entities));
648de78e4feSLisandro Dalcin   for (dim = 0; dim < 4; ++dim) {
649730356f6SLisandro Dalcin     for (index = 0; index < count[dim]; ++index) {
650*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscViewerRead(viewer, &eid, 1, NULL, PETSC_ENUM));
651*5f80ce2aSJacob Faibussowitsch       if (byteSwap) CHKERRQ(PetscByteSwap(&eid, PETSC_ENUM, 1));
652*5f80ce2aSJacob Faibussowitsch       CHKERRQ(GmshEntitiesAdd(mesh->entities, (PetscInt)index, dim, eid, &entity));
653*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscViewerRead(viewer, entity->bbox, 6, NULL, PETSC_DOUBLE));
654*5f80ce2aSJacob Faibussowitsch       if (byteSwap) CHKERRQ(PetscByteSwap(entity->bbox, PETSC_DOUBLE, 6));
655*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscViewerRead(viewer, &num, 1, NULL, PETSC_LONG));
656*5f80ce2aSJacob Faibussowitsch       if (byteSwap) CHKERRQ(PetscByteSwap(&num, PETSC_LONG, 1));
657*5f80ce2aSJacob Faibussowitsch       CHKERRQ(GmshBufferGet(gmsh, num, sizeof(int), &ibuf));
658*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscViewerRead(viewer, ibuf, num, NULL, PETSC_ENUM));
659*5f80ce2aSJacob Faibussowitsch       if (byteSwap) CHKERRQ(PetscByteSwap(ibuf, PETSC_ENUM, num));
660de78e4feSLisandro Dalcin       entity->numTags = numTags = (int) PetscMin(num, 4);
661de78e4feSLisandro Dalcin       for (t = 0; t < numTags; ++t) entity->tags[t] = ibuf[t];
662de78e4feSLisandro Dalcin       if (dim == 0) continue;
663*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscViewerRead(viewer, &num, 1, NULL, PETSC_LONG));
664*5f80ce2aSJacob Faibussowitsch       if (byteSwap) CHKERRQ(PetscByteSwap(&num, PETSC_LONG, 1));
665*5f80ce2aSJacob Faibussowitsch       CHKERRQ(GmshBufferGet(gmsh, num, sizeof(int), &ibuf));
666*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscViewerRead(viewer, ibuf, num, NULL, PETSC_ENUM));
667*5f80ce2aSJacob Faibussowitsch       if (byteSwap) CHKERRQ(PetscByteSwap(ibuf, PETSC_ENUM, num));
668de78e4feSLisandro Dalcin     }
669de78e4feSLisandro Dalcin   }
670de78e4feSLisandro Dalcin   PetscFunctionReturn(0);
671de78e4feSLisandro Dalcin }
672de78e4feSLisandro Dalcin 
673de78e4feSLisandro Dalcin /*
674de78e4feSLisandro Dalcin $Nodes
675de78e4feSLisandro Dalcin   numEntityBlocks(unsigned long) numNodes(unsigned long)
676de78e4feSLisandro Dalcin   tagEntity(int) dimEntity(int) typeNode(int) numNodes(unsigned long)
677de78e4feSLisandro Dalcin     tag(int) x(double) y(double) z(double)
678de78e4feSLisandro Dalcin     ...
679de78e4feSLisandro Dalcin   ...
680de78e4feSLisandro Dalcin $EndNodes
681de78e4feSLisandro Dalcin */
6820598e1a2SLisandro Dalcin static PetscErrorCode GmshReadNodes_v40(GmshFile *gmsh, GmshMesh *mesh)
683de78e4feSLisandro Dalcin {
684698a79b9SLisandro Dalcin   PetscViewer    viewer = gmsh->viewer;
685698a79b9SLisandro Dalcin   PetscBool      byteSwap = gmsh->byteSwap;
6860598e1a2SLisandro Dalcin   long           block, node, n, numEntityBlocks, numTotalNodes, numNodes;
687de78e4feSLisandro Dalcin   int            info[3], nid;
6880598e1a2SLisandro Dalcin   GmshNodes      *nodes;
689de78e4feSLisandro Dalcin 
690de78e4feSLisandro Dalcin   PetscFunctionBegin;
691*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscViewerRead(viewer, &numEntityBlocks, 1, NULL, PETSC_LONG));
692*5f80ce2aSJacob Faibussowitsch   if (byteSwap) CHKERRQ(PetscByteSwap(&numEntityBlocks, PETSC_LONG, 1));
693*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscViewerRead(viewer, &numTotalNodes, 1, NULL, PETSC_LONG));
694*5f80ce2aSJacob Faibussowitsch   if (byteSwap) CHKERRQ(PetscByteSwap(&numTotalNodes, PETSC_LONG, 1));
695*5f80ce2aSJacob Faibussowitsch   CHKERRQ(GmshNodesCreate(numTotalNodes, &nodes));
6960598e1a2SLisandro Dalcin   mesh->numNodes = numTotalNodes;
6970598e1a2SLisandro Dalcin   mesh->nodelist = nodes;
6980598e1a2SLisandro Dalcin   for (n = 0, block = 0; block < numEntityBlocks; ++block) {
699*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerRead(viewer, info, 3, NULL, PETSC_ENUM));
700*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerRead(viewer, &numNodes, 1, NULL, PETSC_LONG));
701*5f80ce2aSJacob Faibussowitsch     if (byteSwap) CHKERRQ(PetscByteSwap(&numNodes, PETSC_LONG, 1));
702698a79b9SLisandro Dalcin     if (gmsh->binary) {
703277f51e8SBarry Smith       size_t nbytes = sizeof(int) + 3*sizeof(double);
704277f51e8SBarry Smith       char   *cbuf = NULL; /* dummy value to prevent warning from compiler about possible unitilized value */
705*5f80ce2aSJacob Faibussowitsch       CHKERRQ(GmshBufferGet(gmsh, numNodes, nbytes, &cbuf));
706*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscViewerRead(viewer, cbuf, numNodes*nbytes, NULL, PETSC_CHAR));
7070598e1a2SLisandro Dalcin       for (node = 0; node < numNodes; ++node, ++n) {
708de78e4feSLisandro Dalcin         char   *cnid = cbuf + node*nbytes, *cxyz = cnid + sizeof(int);
7090598e1a2SLisandro Dalcin         double *xyz = nodes->xyz + n*3;
710*5f80ce2aSJacob Faibussowitsch         if (!PetscBinaryBigEndian()) CHKERRQ(PetscByteSwap(cnid, PETSC_ENUM, 1));
711*5f80ce2aSJacob Faibussowitsch         if (!PetscBinaryBigEndian()) CHKERRQ(PetscByteSwap(cxyz, PETSC_DOUBLE, 3));
712*5f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscMemcpy(&nid, cnid, sizeof(int)));
713*5f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscMemcpy(xyz, cxyz, 3*sizeof(double)));
714*5f80ce2aSJacob Faibussowitsch         if (byteSwap) CHKERRQ(PetscByteSwap(&nid, PETSC_ENUM, 1));
715*5f80ce2aSJacob Faibussowitsch         if (byteSwap) CHKERRQ(PetscByteSwap(xyz, PETSC_DOUBLE, 3));
7160598e1a2SLisandro Dalcin         nodes->id[n] = nid;
71781a1af93SMatthew G. Knepley         nodes->tag[n] = -1;
718de78e4feSLisandro Dalcin       }
719de78e4feSLisandro Dalcin     } else {
7200598e1a2SLisandro Dalcin       for (node = 0; node < numNodes; ++node, ++n) {
7210598e1a2SLisandro Dalcin         double *xyz = nodes->xyz + n*3;
722*5f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscViewerRead(viewer, &nid, 1, NULL, PETSC_ENUM));
723*5f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscViewerRead(viewer, xyz, 3, NULL, PETSC_DOUBLE));
724*5f80ce2aSJacob Faibussowitsch         if (byteSwap) CHKERRQ(PetscByteSwap(&nid, PETSC_ENUM, 1));
725*5f80ce2aSJacob Faibussowitsch         if (byteSwap) CHKERRQ(PetscByteSwap(xyz, PETSC_DOUBLE, 3));
7260598e1a2SLisandro Dalcin         nodes->id[n] = nid;
72781a1af93SMatthew G. Knepley         nodes->tag[n] = -1;
728de78e4feSLisandro Dalcin       }
729de78e4feSLisandro Dalcin     }
730de78e4feSLisandro Dalcin   }
731de78e4feSLisandro Dalcin   PetscFunctionReturn(0);
732de78e4feSLisandro Dalcin }
733de78e4feSLisandro Dalcin 
734de78e4feSLisandro Dalcin /*
735de78e4feSLisandro Dalcin $Elements
736de78e4feSLisandro Dalcin   numEntityBlocks(unsigned long) numElements(unsigned long)
737de78e4feSLisandro Dalcin   tagEntity(int) dimEntity(int) typeEle(int) numElements(unsigned long)
738de78e4feSLisandro Dalcin     tag(int) numVert[...](int)
739de78e4feSLisandro Dalcin     ...
740de78e4feSLisandro Dalcin   ...
741de78e4feSLisandro Dalcin $EndElements
742de78e4feSLisandro Dalcin */
7430598e1a2SLisandro Dalcin static PetscErrorCode GmshReadElements_v40(GmshFile *gmsh, GmshMesh *mesh)
744de78e4feSLisandro Dalcin {
745698a79b9SLisandro Dalcin   PetscViewer    viewer = gmsh->viewer;
746698a79b9SLisandro Dalcin   PetscBool      byteSwap = gmsh->byteSwap;
747de78e4feSLisandro Dalcin   long           c, block, numEntityBlocks, numTotalElements, elem, numElements;
748de78e4feSLisandro Dalcin   int            p, info[3], *ibuf = NULL;
7490598e1a2SLisandro Dalcin   int            eid, dim, cellType, numVerts, numNodes, numTags;
750a5ba3d71SLisandro Dalcin   GmshEntity     *entity = NULL;
751de78e4feSLisandro Dalcin   GmshElement    *elements;
7520598e1a2SLisandro Dalcin   PetscInt       *nodeMap = gmsh->nodeMap;
753de78e4feSLisandro Dalcin 
754de78e4feSLisandro Dalcin   PetscFunctionBegin;
755*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscViewerRead(viewer, &numEntityBlocks, 1, NULL, PETSC_LONG));
756*5f80ce2aSJacob Faibussowitsch   if (byteSwap) CHKERRQ(PetscByteSwap(&numEntityBlocks, PETSC_LONG, 1));
757*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscViewerRead(viewer, &numTotalElements, 1, NULL, PETSC_LONG));
758*5f80ce2aSJacob Faibussowitsch   if (byteSwap) CHKERRQ(PetscByteSwap(&numTotalElements, PETSC_LONG, 1));
759*5f80ce2aSJacob Faibussowitsch   CHKERRQ(GmshElementsCreate(numTotalElements, &elements));
7600598e1a2SLisandro Dalcin   mesh->numElems = numTotalElements;
7610598e1a2SLisandro Dalcin   mesh->elements = elements;
762de78e4feSLisandro Dalcin   for (c = 0, block = 0; block < numEntityBlocks; ++block) {
763*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerRead(viewer, info, 3, NULL, PETSC_ENUM));
764*5f80ce2aSJacob Faibussowitsch     if (byteSwap) CHKERRQ(PetscByteSwap(info, PETSC_ENUM, 3));
765de78e4feSLisandro Dalcin     eid = info[0]; dim = info[1]; cellType = info[2];
766*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshEntitiesGet(mesh->entities, dim, eid, &entity));
767*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshCellTypeCheck(cellType));
7680598e1a2SLisandro Dalcin     numVerts = GmshCellMap[cellType].numVerts;
7690598e1a2SLisandro Dalcin     numNodes = GmshCellMap[cellType].numNodes;
770730356f6SLisandro Dalcin     numTags  = entity->numTags;
771*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerRead(viewer, &numElements, 1, NULL, PETSC_LONG));
772*5f80ce2aSJacob Faibussowitsch     if (byteSwap) CHKERRQ(PetscByteSwap(&numElements, PETSC_LONG, 1));
773*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshBufferGet(gmsh, (1+numNodes)*numElements, sizeof(int), &ibuf));
774*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerRead(viewer, ibuf, (1+numNodes)*numElements, NULL, PETSC_ENUM));
775*5f80ce2aSJacob Faibussowitsch     if (byteSwap) CHKERRQ(PetscByteSwap(ibuf, PETSC_ENUM, (1+numNodes)*numElements));
776de78e4feSLisandro Dalcin     for (elem = 0; elem < numElements; ++elem, ++c) {
777de78e4feSLisandro Dalcin       GmshElement *element = elements + c;
7780598e1a2SLisandro Dalcin       const int *id = ibuf + elem*(1+numNodes), *nodes = id + 1;
7790598e1a2SLisandro Dalcin       element->id  = id[0];
780de78e4feSLisandro Dalcin       element->dim = dim;
781de78e4feSLisandro Dalcin       element->cellType = cellType;
7820598e1a2SLisandro Dalcin       element->numVerts = numVerts;
783de78e4feSLisandro Dalcin       element->numNodes = numNodes;
784de78e4feSLisandro Dalcin       element->numTags  = numTags;
785*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSegBufferGet(mesh->segbuf, (size_t)element->numNodes, &element->nodes));
7860598e1a2SLisandro Dalcin       for (p = 0; p < element->numNodes; p++) element->nodes[p] = nodeMap[nodes[p]];
7870598e1a2SLisandro Dalcin       for (p = 0; p < element->numTags;  p++) element->tags[p]  = entity->tags[p];
788de78e4feSLisandro Dalcin     }
789de78e4feSLisandro Dalcin   }
790698a79b9SLisandro Dalcin   PetscFunctionReturn(0);
791698a79b9SLisandro Dalcin }
792698a79b9SLisandro Dalcin 
7930598e1a2SLisandro Dalcin static PetscErrorCode GmshReadPeriodic_v40(GmshFile *gmsh, PetscInt periodicMap[])
794698a79b9SLisandro Dalcin {
795698a79b9SLisandro Dalcin   PetscViewer    viewer = gmsh->viewer;
796698a79b9SLisandro Dalcin   int            fileFormat = gmsh->fileFormat;
797698a79b9SLisandro Dalcin   PetscBool      binary = gmsh->binary;
798698a79b9SLisandro Dalcin   PetscBool      byteSwap = gmsh->byteSwap;
799698a79b9SLisandro Dalcin   int            numPeriodic, snum, i;
800698a79b9SLisandro Dalcin   char           line[PETSC_MAX_PATH_LEN];
8010598e1a2SLisandro Dalcin   PetscInt       *nodeMap = gmsh->nodeMap;
802698a79b9SLisandro Dalcin 
803698a79b9SLisandro Dalcin   PetscFunctionBegin;
804698a79b9SLisandro Dalcin   if (fileFormat == 22 || !binary) {
805*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING));
806698a79b9SLisandro Dalcin     snum = sscanf(line, "%d", &numPeriodic);
8072c71b3e2SJacob Faibussowitsch     PetscCheckFalse(snum != 1,PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
808698a79b9SLisandro Dalcin   } else {
809*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerRead(viewer, &numPeriodic, 1, NULL, PETSC_ENUM));
810*5f80ce2aSJacob Faibussowitsch     if (byteSwap) CHKERRQ(PetscByteSwap(&numPeriodic, PETSC_ENUM, 1));
811698a79b9SLisandro Dalcin   }
812698a79b9SLisandro Dalcin   for (i = 0; i < numPeriodic; i++) {
8139dddd249SSatish Balay     int    ibuf[3], correspondingDim = -1, correspondingTag = -1, primaryTag = -1, correspondingNode, primaryNode;
814698a79b9SLisandro Dalcin     long   j, nNodes;
815698a79b9SLisandro Dalcin     double affine[16];
816698a79b9SLisandro Dalcin 
817698a79b9SLisandro Dalcin     if (fileFormat == 22 || !binary) {
818*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscViewerRead(viewer, line, 3, NULL, PETSC_STRING));
8199dddd249SSatish Balay       snum = sscanf(line, "%d %d %d", &correspondingDim, &correspondingTag, &primaryTag);
8202c71b3e2SJacob Faibussowitsch       PetscCheckFalse(snum != 3,PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
821698a79b9SLisandro Dalcin     } else {
822*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscViewerRead(viewer, ibuf, 3, NULL, PETSC_ENUM));
823*5f80ce2aSJacob Faibussowitsch       if (byteSwap) CHKERRQ(PetscByteSwap(ibuf, PETSC_ENUM, 3));
8249dddd249SSatish Balay       correspondingDim = ibuf[0]; correspondingTag = ibuf[1]; primaryTag = ibuf[2];
825698a79b9SLisandro Dalcin     }
8269dddd249SSatish Balay     (void)correspondingDim; (void)correspondingTag; (void)primaryTag; /* unused */
827698a79b9SLisandro Dalcin 
828698a79b9SLisandro Dalcin     if (fileFormat == 22 || !binary) {
829*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING));
830698a79b9SLisandro Dalcin       snum = sscanf(line, "%ld", &nNodes);
8314c500f23SPierre Jolivet       if (snum != 1) { /* discard transformation and try again */
832*5f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscViewerRead(viewer, line, -PETSC_MAX_PATH_LEN, NULL, PETSC_STRING));
833*5f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING));
834698a79b9SLisandro Dalcin         snum = sscanf(line, "%ld", &nNodes);
8352c71b3e2SJacob Faibussowitsch         PetscCheckFalse(snum != 1,PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
836698a79b9SLisandro Dalcin       }
837698a79b9SLisandro Dalcin     } else {
838*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscViewerRead(viewer, &nNodes, 1, NULL, PETSC_LONG));
839*5f80ce2aSJacob Faibussowitsch       if (byteSwap) CHKERRQ(PetscByteSwap(&nNodes, PETSC_LONG, 1));
8404c500f23SPierre Jolivet       if (nNodes == -1) { /* discard transformation and try again */
841*5f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscViewerRead(viewer, affine, 16, NULL, PETSC_DOUBLE));
842*5f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscViewerRead(viewer, &nNodes, 1, NULL, PETSC_LONG));
843*5f80ce2aSJacob Faibussowitsch         if (byteSwap) CHKERRQ(PetscByteSwap(&nNodes, PETSC_LONG, 1));
844698a79b9SLisandro Dalcin       }
845698a79b9SLisandro Dalcin     }
846698a79b9SLisandro Dalcin 
847698a79b9SLisandro Dalcin     for (j = 0; j < nNodes; j++) {
848698a79b9SLisandro Dalcin       if (fileFormat == 22 || !binary) {
849*5f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscViewerRead(viewer, line, 2, NULL, PETSC_STRING));
8509dddd249SSatish Balay         snum = sscanf(line, "%d %d", &correspondingNode, &primaryNode);
8512c71b3e2SJacob Faibussowitsch         PetscCheckFalse(snum != 2,PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
852698a79b9SLisandro Dalcin       } else {
853*5f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscViewerRead(viewer, ibuf, 2, NULL, PETSC_ENUM));
854*5f80ce2aSJacob Faibussowitsch         if (byteSwap) CHKERRQ(PetscByteSwap(ibuf, PETSC_ENUM, 2));
8559dddd249SSatish Balay         correspondingNode = ibuf[0]; primaryNode = ibuf[1];
856698a79b9SLisandro Dalcin       }
8579dddd249SSatish Balay       correspondingNode  = (int) nodeMap[correspondingNode];
8589dddd249SSatish Balay       primaryNode = (int) nodeMap[primaryNode];
8599dddd249SSatish Balay       periodicMap[correspondingNode] = primaryNode;
860698a79b9SLisandro Dalcin     }
861698a79b9SLisandro Dalcin   }
862698a79b9SLisandro Dalcin   PetscFunctionReturn(0);
863698a79b9SLisandro Dalcin }
864698a79b9SLisandro Dalcin 
8650598e1a2SLisandro Dalcin /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
866698a79b9SLisandro Dalcin $Entities
867698a79b9SLisandro Dalcin   numPoints(size_t) numCurves(size_t)
868698a79b9SLisandro Dalcin     numSurfaces(size_t) numVolumes(size_t)
869698a79b9SLisandro Dalcin   pointTag(int) X(double) Y(double) Z(double)
870698a79b9SLisandro Dalcin     numPhysicalTags(size_t) physicalTag(int) ...
871698a79b9SLisandro Dalcin   ...
872698a79b9SLisandro Dalcin   curveTag(int) minX(double) minY(double) minZ(double)
873698a79b9SLisandro Dalcin     maxX(double) maxY(double) maxZ(double)
874698a79b9SLisandro Dalcin     numPhysicalTags(size_t) physicalTag(int) ...
875698a79b9SLisandro Dalcin     numBoundingPoints(size_t) pointTag(int) ...
876698a79b9SLisandro Dalcin   ...
877698a79b9SLisandro Dalcin   surfaceTag(int) minX(double) minY(double) minZ(double)
878698a79b9SLisandro Dalcin     maxX(double) maxY(double) maxZ(double)
879698a79b9SLisandro Dalcin     numPhysicalTags(size_t) physicalTag(int) ...
880698a79b9SLisandro Dalcin     numBoundingCurves(size_t) curveTag(int) ...
881698a79b9SLisandro Dalcin   ...
882698a79b9SLisandro Dalcin   volumeTag(int) minX(double) minY(double) minZ(double)
883698a79b9SLisandro Dalcin     maxX(double) maxY(double) maxZ(double)
884698a79b9SLisandro Dalcin     numPhysicalTags(size_t) physicalTag(int) ...
885698a79b9SLisandro Dalcin     numBoundngSurfaces(size_t) surfaceTag(int) ...
886698a79b9SLisandro Dalcin   ...
887698a79b9SLisandro Dalcin $EndEntities
888698a79b9SLisandro Dalcin */
8890598e1a2SLisandro Dalcin static PetscErrorCode GmshReadEntities_v41(GmshFile *gmsh, GmshMesh *mesh)
890698a79b9SLisandro Dalcin {
891698a79b9SLisandro Dalcin   PetscInt       count[4], index, numTags, i;
892698a79b9SLisandro Dalcin   int            dim, eid, *tags = NULL;
893698a79b9SLisandro Dalcin   GmshEntity     *entity = NULL;
894698a79b9SLisandro Dalcin 
895698a79b9SLisandro Dalcin   PetscFunctionBegin;
896*5f80ce2aSJacob Faibussowitsch   CHKERRQ(GmshReadSize(gmsh, count, 4));
897*5f80ce2aSJacob Faibussowitsch   CHKERRQ(GmshEntitiesCreate(count, &mesh->entities));
898698a79b9SLisandro Dalcin   for (dim = 0; dim < 4; ++dim) {
899698a79b9SLisandro Dalcin     for (index = 0; index < count[dim]; ++index) {
900*5f80ce2aSJacob Faibussowitsch       CHKERRQ(GmshReadInt(gmsh, &eid, 1));
901*5f80ce2aSJacob Faibussowitsch       CHKERRQ(GmshEntitiesAdd(mesh->entities, (PetscInt)index, dim, eid, &entity));
902*5f80ce2aSJacob Faibussowitsch       CHKERRQ(GmshReadDouble(gmsh, entity->bbox, (dim == 0) ? 3 : 6));
903*5f80ce2aSJacob Faibussowitsch       CHKERRQ(GmshReadSize(gmsh, &numTags, 1));
904*5f80ce2aSJacob Faibussowitsch       CHKERRQ(GmshBufferGet(gmsh, numTags, sizeof(int), &tags));
905*5f80ce2aSJacob Faibussowitsch       CHKERRQ(GmshReadInt(gmsh, tags, numTags));
906698a79b9SLisandro Dalcin       entity->numTags = PetscMin(numTags, 4);
907698a79b9SLisandro Dalcin       for (i = 0; i < entity->numTags; ++i) entity->tags[i] = tags[i];
908698a79b9SLisandro Dalcin       if (dim == 0) continue;
909*5f80ce2aSJacob Faibussowitsch       CHKERRQ(GmshReadSize(gmsh, &numTags, 1));
910*5f80ce2aSJacob Faibussowitsch       CHKERRQ(GmshBufferGet(gmsh, numTags, sizeof(int), &tags));
911*5f80ce2aSJacob Faibussowitsch       CHKERRQ(GmshReadInt(gmsh, tags, numTags));
91281a1af93SMatthew G. Knepley       /* Currently, we do not save the ids for the bounding entities */
913698a79b9SLisandro Dalcin     }
914698a79b9SLisandro Dalcin   }
915698a79b9SLisandro Dalcin   PetscFunctionReturn(0);
916698a79b9SLisandro Dalcin }
917698a79b9SLisandro Dalcin 
91833a088b6SMatthew G. Knepley /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
919698a79b9SLisandro Dalcin $Nodes
920698a79b9SLisandro Dalcin   numEntityBlocks(size_t) numNodes(size_t)
921698a79b9SLisandro Dalcin     minNodeTag(size_t) maxNodeTag(size_t)
922698a79b9SLisandro Dalcin   entityDim(int) entityTag(int) parametric(int; 0 or 1) numNodesBlock(size_t)
923698a79b9SLisandro Dalcin     nodeTag(size_t)
924698a79b9SLisandro Dalcin     ...
925698a79b9SLisandro Dalcin     x(double) y(double) z(double)
926698a79b9SLisandro Dalcin        < u(double; if parametric and entityDim = 1 or entityDim = 2) >
927698a79b9SLisandro Dalcin        < v(double; if parametric and entityDim = 2) >
928698a79b9SLisandro Dalcin     ...
929698a79b9SLisandro Dalcin   ...
930698a79b9SLisandro Dalcin $EndNodes
931698a79b9SLisandro Dalcin */
9320598e1a2SLisandro Dalcin static PetscErrorCode GmshReadNodes_v41(GmshFile *gmsh, GmshMesh *mesh)
933698a79b9SLisandro Dalcin {
93481a1af93SMatthew G. Knepley   int            info[3], dim, eid, parametric;
93581a1af93SMatthew G. Knepley   PetscInt       sizes[4], numEntityBlocks, numTags, numNodes, numNodesBlock = 0, block, node, n;
93681a1af93SMatthew G. Knepley   GmshEntity     *entity = NULL;
9370598e1a2SLisandro Dalcin   GmshNodes      *nodes;
938698a79b9SLisandro Dalcin 
939698a79b9SLisandro Dalcin   PetscFunctionBegin;
940*5f80ce2aSJacob Faibussowitsch   CHKERRQ(GmshReadSize(gmsh, sizes, 4));
9410598e1a2SLisandro Dalcin   numEntityBlocks = sizes[0]; numNodes = sizes[1];
942*5f80ce2aSJacob Faibussowitsch   CHKERRQ(GmshNodesCreate(numNodes, &nodes));
9430598e1a2SLisandro Dalcin   mesh->numNodes = numNodes;
9440598e1a2SLisandro Dalcin   mesh->nodelist = nodes;
945698a79b9SLisandro Dalcin   for (block = 0, node = 0; block < numEntityBlocks; ++block, node += numNodesBlock) {
946*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshReadInt(gmsh, info, 3));
94781a1af93SMatthew G. Knepley     dim = info[0]; eid = info[1]; parametric = info[2];
948*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshEntitiesGet(mesh->entities, dim, eid, &entity));
94981a1af93SMatthew G. Knepley     numTags = PetscMin(1, entity->numTags);
95081a1af93SMatthew G. Knepley     if (entity->numTags > 1) PetscInfo(NULL, "Entity %d has more than %d physical tags, assigning only the first to nodes", eid, 1);
95181a1af93SMatthew G. Knepley     PetscCheck(!parametric, PETSC_COMM_SELF, PETSC_ERR_SUP, "Parametric coordinates not supported");
952*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshReadSize(gmsh, &numNodesBlock, 1));
953*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshReadSize(gmsh, nodes->id+node, numNodesBlock));
954*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshReadDouble(gmsh, nodes->xyz+node*3, numNodesBlock*3));
95581a1af93SMatthew G. Knepley     for (n = 0; n < numNodesBlock; ++n) nodes->tag[node+n] = numTags ? entity->tags[0] : -1;
956698a79b9SLisandro Dalcin   }
9570598e1a2SLisandro Dalcin   gmsh->nodeStart = sizes[2];
9580598e1a2SLisandro Dalcin   gmsh->nodeEnd   = sizes[3]+1;
959698a79b9SLisandro Dalcin   PetscFunctionReturn(0);
960698a79b9SLisandro Dalcin }
961698a79b9SLisandro Dalcin 
96233a088b6SMatthew G. Knepley /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
963698a79b9SLisandro Dalcin $Elements
964698a79b9SLisandro Dalcin   numEntityBlocks(size_t) numElements(size_t)
965698a79b9SLisandro Dalcin     minElementTag(size_t) maxElementTag(size_t)
966698a79b9SLisandro Dalcin   entityDim(int) entityTag(int) elementType(int; see below) numElementsBlock(size_t)
967698a79b9SLisandro Dalcin     elementTag(size_t) nodeTag(size_t) ...
968698a79b9SLisandro Dalcin     ...
969698a79b9SLisandro Dalcin   ...
970698a79b9SLisandro Dalcin $EndElements
971698a79b9SLisandro Dalcin */
9720598e1a2SLisandro Dalcin static PetscErrorCode GmshReadElements_v41(GmshFile *gmsh, GmshMesh *mesh)
973698a79b9SLisandro Dalcin {
9740598e1a2SLisandro Dalcin   int            info[3], eid, dim, cellType;
9750598e1a2SLisandro Dalcin   PetscInt       sizes[4], *ibuf = NULL, numEntityBlocks, numElements, numBlockElements, numVerts, numNodes, numTags, block, elem, c, p;
976698a79b9SLisandro Dalcin   GmshEntity     *entity = NULL;
977698a79b9SLisandro Dalcin   GmshElement    *elements;
9780598e1a2SLisandro Dalcin   PetscInt       *nodeMap = gmsh->nodeMap;
979698a79b9SLisandro Dalcin 
980698a79b9SLisandro Dalcin   PetscFunctionBegin;
981*5f80ce2aSJacob Faibussowitsch   CHKERRQ(GmshReadSize(gmsh, sizes, 4));
982698a79b9SLisandro Dalcin   numEntityBlocks = sizes[0]; numElements = sizes[1];
983*5f80ce2aSJacob Faibussowitsch   CHKERRQ(GmshElementsCreate(numElements, &elements));
9840598e1a2SLisandro Dalcin   mesh->numElems = numElements;
9850598e1a2SLisandro Dalcin   mesh->elements = elements;
986698a79b9SLisandro Dalcin   for (c = 0, block = 0; block < numEntityBlocks; ++block) {
987*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshReadInt(gmsh, info, 3));
988698a79b9SLisandro Dalcin     dim = info[0]; eid = info[1]; cellType = info[2];
989*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshEntitiesGet(mesh->entities, dim, eid, &entity));
990*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshCellTypeCheck(cellType));
9910598e1a2SLisandro Dalcin     numVerts = GmshCellMap[cellType].numVerts;
9920598e1a2SLisandro Dalcin     numNodes = GmshCellMap[cellType].numNodes;
99381a1af93SMatthew G. Knepley     numTags  = PetscMin(4, entity->numTags);
99481a1af93SMatthew G. Knepley     if (entity->numTags > 4) PetscInfo(NULL, "Entity %d has more then %d physical tags, assigning only the first to elements", eid, 4);
995*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshReadSize(gmsh, &numBlockElements, 1));
996*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshBufferGet(gmsh, (1+numNodes)*numBlockElements, sizeof(PetscInt), &ibuf));
997*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshReadSize(gmsh, ibuf, (1+numNodes)*numBlockElements));
998698a79b9SLisandro Dalcin     for (elem = 0; elem < numBlockElements; ++elem, ++c) {
999698a79b9SLisandro Dalcin       GmshElement *element = elements + c;
10000598e1a2SLisandro Dalcin       const PetscInt *id = ibuf + elem*(1+numNodes), *nodes = id + 1;
1001698a79b9SLisandro Dalcin       element->id  = id[0];
1002698a79b9SLisandro Dalcin       element->dim = dim;
1003698a79b9SLisandro Dalcin       element->cellType = cellType;
10040598e1a2SLisandro Dalcin       element->numVerts = numVerts;
1005698a79b9SLisandro Dalcin       element->numNodes = numNodes;
1006698a79b9SLisandro Dalcin       element->numTags  = numTags;
1007*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSegBufferGet(mesh->segbuf, (size_t)element->numNodes, &element->nodes));
10080598e1a2SLisandro Dalcin       for (p = 0; p < element->numNodes; p++) element->nodes[p] = nodeMap[nodes[p]];
10090598e1a2SLisandro Dalcin       for (p = 0; p < element->numTags;  p++) element->tags[p]  = entity->tags[p];
1010698a79b9SLisandro Dalcin     }
1011698a79b9SLisandro Dalcin   }
1012698a79b9SLisandro Dalcin   PetscFunctionReturn(0);
1013698a79b9SLisandro Dalcin }
1014698a79b9SLisandro Dalcin 
10150598e1a2SLisandro Dalcin /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
1016698a79b9SLisandro Dalcin $Periodic
1017698a79b9SLisandro Dalcin   numPeriodicLinks(size_t)
10189dddd249SSatish Balay   entityDim(int) entityTag(int) entityTagPrimary(int)
1019698a79b9SLisandro Dalcin   numAffine(size_t) value(double) ...
1020698a79b9SLisandro Dalcin   numCorrespondingNodes(size_t)
10219dddd249SSatish Balay     nodeTag(size_t) nodeTagPrimary(size_t)
1022698a79b9SLisandro Dalcin     ...
1023698a79b9SLisandro Dalcin   ...
1024698a79b9SLisandro Dalcin $EndPeriodic
1025698a79b9SLisandro Dalcin */
10260598e1a2SLisandro Dalcin static PetscErrorCode GmshReadPeriodic_v41(GmshFile *gmsh, PetscInt periodicMap[])
1027698a79b9SLisandro Dalcin {
1028698a79b9SLisandro Dalcin   int            info[3];
1029698a79b9SLisandro Dalcin   double         dbuf[16];
10300598e1a2SLisandro Dalcin   PetscInt       numPeriodicLinks, numAffine, numCorrespondingNodes, *nodeTags = NULL, link, node;
10310598e1a2SLisandro Dalcin   PetscInt       *nodeMap = gmsh->nodeMap;
1032698a79b9SLisandro Dalcin 
1033698a79b9SLisandro Dalcin   PetscFunctionBegin;
1034*5f80ce2aSJacob Faibussowitsch   CHKERRQ(GmshReadSize(gmsh, &numPeriodicLinks, 1));
1035698a79b9SLisandro Dalcin   for (link = 0; link < numPeriodicLinks; ++link) {
1036*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshReadInt(gmsh, info, 3));
1037*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshReadSize(gmsh, &numAffine, 1));
1038*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshReadDouble(gmsh, dbuf, numAffine));
1039*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshReadSize(gmsh, &numCorrespondingNodes, 1));
1040*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshBufferGet(gmsh, numCorrespondingNodes, sizeof(PetscInt), &nodeTags));
1041*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshReadSize(gmsh, nodeTags, numCorrespondingNodes*2));
1042698a79b9SLisandro Dalcin     for (node = 0; node < numCorrespondingNodes; ++node) {
10439dddd249SSatish Balay       PetscInt correspondingNode = nodeMap[nodeTags[node*2+0]];
10449dddd249SSatish Balay       PetscInt primaryNode = nodeMap[nodeTags[node*2+1]];
10459dddd249SSatish Balay       periodicMap[correspondingNode] = primaryNode;
1046698a79b9SLisandro Dalcin     }
1047698a79b9SLisandro Dalcin   }
1048698a79b9SLisandro Dalcin   PetscFunctionReturn(0);
1049698a79b9SLisandro Dalcin }
1050698a79b9SLisandro Dalcin 
10510598e1a2SLisandro Dalcin /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
1052d6689ca9SLisandro Dalcin $MeshFormat // same as MSH version 2
1053d6689ca9SLisandro Dalcin   version(ASCII double; currently 4.1)
1054d6689ca9SLisandro Dalcin   file-type(ASCII int; 0 for ASCII mode, 1 for binary mode)
1055d6689ca9SLisandro Dalcin   data-size(ASCII int; sizeof(size_t))
1056d6689ca9SLisandro Dalcin   < int with value one; only in binary mode, to detect endianness >
1057d6689ca9SLisandro Dalcin $EndMeshFormat
1058d6689ca9SLisandro Dalcin */
10590598e1a2SLisandro Dalcin static PetscErrorCode GmshReadMeshFormat(GmshFile *gmsh)
1060698a79b9SLisandro Dalcin {
1061698a79b9SLisandro Dalcin   char           line[PETSC_MAX_PATH_LEN];
1062698a79b9SLisandro Dalcin   int            snum, fileType, fileFormat, dataSize, checkEndian;
1063698a79b9SLisandro Dalcin   float          version;
1064698a79b9SLisandro Dalcin 
1065698a79b9SLisandro Dalcin   PetscFunctionBegin;
1066*5f80ce2aSJacob Faibussowitsch   CHKERRQ(GmshReadString(gmsh, line, 3));
1067698a79b9SLisandro Dalcin   snum = sscanf(line, "%f %d %d", &version, &fileType, &dataSize);
10682c71b3e2SJacob Faibussowitsch   PetscCheckFalse(snum != 3,PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to parse Gmsh file header: %s", line);
10692c71b3e2SJacob Faibussowitsch   PetscCheckFalse(version < 2.2,PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at least 2.2", (double)version);
10702c71b3e2SJacob Faibussowitsch   PetscCheckFalse((int)version == 3,PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f not supported", (double)version);
10712c71b3e2SJacob Faibussowitsch   PetscCheckFalse(version > 4.1,PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at most 4.1", (double)version);
10722c71b3e2SJacob Faibussowitsch   PetscCheckFalse(gmsh->binary && !fileType,PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Viewer is binary but Gmsh file is ASCII");
10732c71b3e2SJacob Faibussowitsch   PetscCheckFalse(!gmsh->binary && fileType,PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Viewer is ASCII but Gmsh file is binary");
1074af7a0b9fSSatish Balay   fileFormat = (int)roundf(version*10);
10752c71b3e2SJacob Faibussowitsch   PetscCheckFalse(fileFormat <= 40 && dataSize != sizeof(double),PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Data size %d is not valid for a Gmsh file", dataSize);
10762c71b3e2SJacob Faibussowitsch   PetscCheckFalse(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);
1077698a79b9SLisandro Dalcin   gmsh->fileFormat = fileFormat;
1078698a79b9SLisandro Dalcin   gmsh->dataSize = dataSize;
1079698a79b9SLisandro Dalcin   gmsh->byteSwap = PETSC_FALSE;
1080698a79b9SLisandro Dalcin   if (gmsh->binary) {
1081*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshReadInt(gmsh, &checkEndian, 1));
1082698a79b9SLisandro Dalcin     if (checkEndian != 1) {
1083*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscByteSwap(&checkEndian, PETSC_ENUM, 1));
10842c71b3e2SJacob Faibussowitsch       PetscCheckFalse(checkEndian != 1,PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to detect endianness in Gmsh file header: %s", line);
1085698a79b9SLisandro Dalcin       gmsh->byteSwap = PETSC_TRUE;
1086698a79b9SLisandro Dalcin     }
1087698a79b9SLisandro Dalcin   }
1088698a79b9SLisandro Dalcin   PetscFunctionReturn(0);
1089698a79b9SLisandro Dalcin }
1090698a79b9SLisandro Dalcin 
10911f643af3SLisandro Dalcin /*
10921f643af3SLisandro Dalcin PhysicalNames
10931f643af3SLisandro Dalcin   numPhysicalNames(ASCII int)
10941f643af3SLisandro Dalcin   dimension(ASCII int) physicalTag(ASCII int) "name"(127 characters max)
10951f643af3SLisandro Dalcin   ...
10961f643af3SLisandro Dalcin $EndPhysicalNames
10971f643af3SLisandro Dalcin */
1098a45dabc8SMatthew G. Knepley static PetscErrorCode GmshReadPhysicalNames(GmshFile *gmsh, GmshMesh *mesh)
1099698a79b9SLisandro Dalcin {
11001f643af3SLisandro Dalcin   char           line[PETSC_MAX_PATH_LEN], name[128+2], *p, *q;
1101a45dabc8SMatthew G. Knepley   int            snum, region, dim, tag;
1102698a79b9SLisandro Dalcin 
1103698a79b9SLisandro Dalcin   PetscFunctionBegin;
1104*5f80ce2aSJacob Faibussowitsch   CHKERRQ(GmshReadString(gmsh, line, 1));
1105a45dabc8SMatthew G. Knepley   snum = sscanf(line, "%d", &region);
1106a45dabc8SMatthew G. Knepley   mesh->numRegions = region;
11072c71b3e2SJacob Faibussowitsch   PetscCheckFalse(snum != 1,PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
1108*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc2(mesh->numRegions, &mesh->regionTags, mesh->numRegions, &mesh->regionNames));
1109a45dabc8SMatthew G. Knepley   for (region = 0; region < mesh->numRegions; ++region) {
1110*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshReadString(gmsh, line, 2));
11111f643af3SLisandro Dalcin     snum = sscanf(line, "%d %d", &dim, &tag);
11122c71b3e2SJacob Faibussowitsch     PetscCheckFalse(snum != 2,PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
1113*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshReadString(gmsh, line, -(PetscInt)sizeof(line)));
1114*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscStrchr(line, '"', &p));
11152c71b3e2SJacob Faibussowitsch     PetscCheckFalse(!p,PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
1116*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscStrrchr(line, '"', &q));
11172c71b3e2SJacob Faibussowitsch     PetscCheckFalse(q == p,PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
1118*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscStrncpy(name, p+1, (size_t)(q-p-1)));
1119a45dabc8SMatthew G. Knepley     mesh->regionTags[region] = tag;
1120*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscStrallocpy(name, &mesh->regionNames[region]));
1121698a79b9SLisandro Dalcin   }
1122de78e4feSLisandro Dalcin   PetscFunctionReturn(0);
1123de78e4feSLisandro Dalcin }
1124de78e4feSLisandro Dalcin 
11250598e1a2SLisandro Dalcin static PetscErrorCode GmshReadEntities(GmshFile *gmsh, GmshMesh *mesh)
112696ca5757SLisandro Dalcin {
11270598e1a2SLisandro Dalcin   PetscFunctionBegin;
11280598e1a2SLisandro Dalcin   switch (gmsh->fileFormat) {
1129*5f80ce2aSJacob Faibussowitsch   case 41: CHKERRQ(GmshReadEntities_v41(gmsh, mesh)); break;
1130*5f80ce2aSJacob Faibussowitsch   default: CHKERRQ(GmshReadEntities_v40(gmsh, mesh)); break;
113196ca5757SLisandro Dalcin   }
11320598e1a2SLisandro Dalcin   PetscFunctionReturn(0);
11330598e1a2SLisandro Dalcin }
11340598e1a2SLisandro Dalcin 
11350598e1a2SLisandro Dalcin static PetscErrorCode GmshReadNodes(GmshFile *gmsh, GmshMesh *mesh)
11360598e1a2SLisandro Dalcin {
11370598e1a2SLisandro Dalcin   PetscFunctionBegin;
11380598e1a2SLisandro Dalcin   switch (gmsh->fileFormat) {
1139*5f80ce2aSJacob Faibussowitsch   case 41: CHKERRQ(GmshReadNodes_v41(gmsh, mesh)); break;
1140*5f80ce2aSJacob Faibussowitsch   case 40: CHKERRQ(GmshReadNodes_v40(gmsh, mesh)); break;
1141*5f80ce2aSJacob Faibussowitsch   default: CHKERRQ(GmshReadNodes_v22(gmsh, mesh)); break;
11420598e1a2SLisandro Dalcin   }
11430598e1a2SLisandro Dalcin 
11440598e1a2SLisandro Dalcin   { /* Gmsh v2.2/v4.0 does not provide min/max node tags */
11450598e1a2SLisandro Dalcin     if (mesh->numNodes > 0 && gmsh->nodeEnd >= gmsh->nodeStart) {
11460598e1a2SLisandro Dalcin       PetscInt  tagMin = PETSC_MAX_INT, tagMax = PETSC_MIN_INT, n;
11470598e1a2SLisandro Dalcin       GmshNodes *nodes = mesh->nodelist;
11480598e1a2SLisandro Dalcin       for (n = 0; n < mesh->numNodes; ++n) {
11490598e1a2SLisandro Dalcin         const PetscInt tag = nodes->id[n];
11500598e1a2SLisandro Dalcin         tagMin = PetscMin(tag, tagMin);
11510598e1a2SLisandro Dalcin         tagMax = PetscMax(tag, tagMax);
11520598e1a2SLisandro Dalcin       }
11530598e1a2SLisandro Dalcin       gmsh->nodeStart = tagMin;
11540598e1a2SLisandro Dalcin       gmsh->nodeEnd   = tagMax+1;
11550598e1a2SLisandro Dalcin     }
11560598e1a2SLisandro Dalcin   }
11570598e1a2SLisandro Dalcin 
11580598e1a2SLisandro Dalcin   { /* Support for sparse node tags */
11590598e1a2SLisandro Dalcin     PetscInt  n, t;
11600598e1a2SLisandro Dalcin     GmshNodes *nodes = mesh->nodelist;
1161*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(gmsh->nodeEnd - gmsh->nodeStart, &gmsh->nbuf));
11620598e1a2SLisandro Dalcin     for (t = 0; t < gmsh->nodeEnd - gmsh->nodeStart; ++t) gmsh->nbuf[t] = PETSC_MIN_INT;
11630598e1a2SLisandro Dalcin     gmsh->nodeMap = gmsh->nbuf - gmsh->nodeStart;
11640598e1a2SLisandro Dalcin     for (n = 0; n < mesh->numNodes; ++n) {
11650598e1a2SLisandro Dalcin       const PetscInt tag = nodes->id[n];
11662c71b3e2SJacob Faibussowitsch       PetscCheckFalse(gmsh->nodeMap[tag] >= 0,PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Repeated node tag %D", tag);
11670598e1a2SLisandro Dalcin       gmsh->nodeMap[tag] = n;
11680598e1a2SLisandro Dalcin     }
11690598e1a2SLisandro Dalcin   }
11700598e1a2SLisandro Dalcin   PetscFunctionReturn(0);
11710598e1a2SLisandro Dalcin }
11720598e1a2SLisandro Dalcin 
11730598e1a2SLisandro Dalcin static PetscErrorCode GmshReadElements(GmshFile *gmsh, GmshMesh *mesh)
11740598e1a2SLisandro Dalcin {
11750598e1a2SLisandro Dalcin   PetscFunctionBegin;
11760598e1a2SLisandro Dalcin   switch (gmsh->fileFormat) {
1177*5f80ce2aSJacob Faibussowitsch   case 41: CHKERRQ(GmshReadElements_v41(gmsh, mesh)); break;
1178*5f80ce2aSJacob Faibussowitsch   case 40: CHKERRQ(GmshReadElements_v40(gmsh, mesh)); break;
1179*5f80ce2aSJacob Faibussowitsch   default: CHKERRQ(GmshReadElements_v22(gmsh, mesh)); break;
11800598e1a2SLisandro Dalcin   }
11810598e1a2SLisandro Dalcin 
11820598e1a2SLisandro Dalcin   { /* Reorder elements by codimension and polytope type */
11830598e1a2SLisandro Dalcin     PetscInt    ne = mesh->numElems;
11840598e1a2SLisandro Dalcin     GmshElement *elements = mesh->elements;
1185066ea43fSLisandro Dalcin     PetscInt    keymap[GMSH_NUM_POLYTOPES], nk = 0;
1186066ea43fSLisandro Dalcin     PetscInt    offset[GMSH_NUM_POLYTOPES+1], e, k;
11870598e1a2SLisandro Dalcin 
1188066ea43fSLisandro Dalcin     for (k = 0; k < GMSH_NUM_POLYTOPES; ++k) keymap[k] = PETSC_MIN_INT;
1189*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMemzero(offset,sizeof(offset)));
11900598e1a2SLisandro Dalcin 
1191066ea43fSLisandro Dalcin     keymap[GMSH_TET] = nk++;
1192066ea43fSLisandro Dalcin     keymap[GMSH_HEX] = nk++;
1193066ea43fSLisandro Dalcin     keymap[GMSH_PRI] = nk++;
1194066ea43fSLisandro Dalcin     keymap[GMSH_PYR] = nk++;
1195066ea43fSLisandro Dalcin     keymap[GMSH_TRI] = nk++;
1196066ea43fSLisandro Dalcin     keymap[GMSH_QUA] = nk++;
1197066ea43fSLisandro Dalcin     keymap[GMSH_SEG] = nk++;
1198066ea43fSLisandro Dalcin     keymap[GMSH_VTX] = nk++;
11990598e1a2SLisandro Dalcin 
1200*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshElementsCreate(mesh->numElems, &mesh->elements));
12010598e1a2SLisandro Dalcin #define key(eid) keymap[GmshCellMap[elements[(eid)].cellType].polytope]
12020598e1a2SLisandro Dalcin     for (e = 0; e < ne; ++e) offset[1+key(e)]++;
12030598e1a2SLisandro Dalcin     for (k = 1; k < nk; ++k) offset[k] += offset[k-1];
12040598e1a2SLisandro Dalcin     for (e = 0; e < ne; ++e) mesh->elements[offset[key(e)]++] = elements[e];
12050598e1a2SLisandro Dalcin #undef key
1206*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshElementsDestroy(&elements));
1207066ea43fSLisandro Dalcin   }
12080598e1a2SLisandro Dalcin 
1209066ea43fSLisandro Dalcin   { /* Mesh dimension and order */
1210066ea43fSLisandro Dalcin     GmshElement *elem = mesh->numElems ? mesh->elements : NULL;
1211066ea43fSLisandro Dalcin     mesh->dim   = elem ? GmshCellMap[elem->cellType].dim   : 0;
1212066ea43fSLisandro Dalcin     mesh->order = elem ? GmshCellMap[elem->cellType].order : 0;
12130598e1a2SLisandro Dalcin   }
12140598e1a2SLisandro Dalcin 
12150598e1a2SLisandro Dalcin   {
12160598e1a2SLisandro Dalcin     PetscBT  vtx;
12170598e1a2SLisandro Dalcin     PetscInt dim = mesh->dim, e, n, v;
12180598e1a2SLisandro Dalcin 
1219*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscBTCreate(mesh->numNodes, &vtx));
12200598e1a2SLisandro Dalcin 
12210598e1a2SLisandro Dalcin     /* Compute number of cells and set of vertices */
12220598e1a2SLisandro Dalcin     mesh->numCells = 0;
12230598e1a2SLisandro Dalcin     for (e = 0; e < mesh->numElems; ++e) {
12240598e1a2SLisandro Dalcin       GmshElement *elem = mesh->elements + e;
12250598e1a2SLisandro Dalcin       if (elem->dim == dim && dim > 0) mesh->numCells++;
12260598e1a2SLisandro Dalcin       for (v = 0; v < elem->numVerts; v++) {
1227*5f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscBTSet(vtx, elem->nodes[v]));
12280598e1a2SLisandro Dalcin       }
12290598e1a2SLisandro Dalcin     }
12300598e1a2SLisandro Dalcin 
12310598e1a2SLisandro Dalcin     /* Compute numbering for vertices */
12320598e1a2SLisandro Dalcin     mesh->numVerts = 0;
1233*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(mesh->numNodes, &mesh->vertexMap));
12340598e1a2SLisandro Dalcin     for (n = 0; n < mesh->numNodes; ++n)
12350598e1a2SLisandro Dalcin       mesh->vertexMap[n] = PetscBTLookup(vtx, n) ? mesh->numVerts++ : PETSC_MIN_INT;
12360598e1a2SLisandro Dalcin 
1237*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscBTDestroy(&vtx));
12380598e1a2SLisandro Dalcin   }
12390598e1a2SLisandro Dalcin   PetscFunctionReturn(0);
12400598e1a2SLisandro Dalcin }
12410598e1a2SLisandro Dalcin 
12420598e1a2SLisandro Dalcin static PetscErrorCode GmshReadPeriodic(GmshFile *gmsh, GmshMesh *mesh)
12430598e1a2SLisandro Dalcin {
12440598e1a2SLisandro Dalcin   PetscInt       n;
12450598e1a2SLisandro Dalcin 
12460598e1a2SLisandro Dalcin   PetscFunctionBegin;
1247*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(mesh->numNodes, &mesh->periodMap));
12480598e1a2SLisandro Dalcin   for (n = 0; n < mesh->numNodes; ++n) mesh->periodMap[n] = n;
12490598e1a2SLisandro Dalcin   switch (gmsh->fileFormat) {
1250*5f80ce2aSJacob Faibussowitsch   case 41: CHKERRQ(GmshReadPeriodic_v41(gmsh, mesh->periodMap)); break;
1251*5f80ce2aSJacob Faibussowitsch   default: CHKERRQ(GmshReadPeriodic_v40(gmsh, mesh->periodMap)); break;
12520598e1a2SLisandro Dalcin   }
12530598e1a2SLisandro Dalcin 
12549dddd249SSatish Balay   /* Find canonical primary nodes */
12550598e1a2SLisandro Dalcin   for (n = 0; n < mesh->numNodes; ++n)
12560598e1a2SLisandro Dalcin     while (mesh->periodMap[n] != mesh->periodMap[mesh->periodMap[n]])
12570598e1a2SLisandro Dalcin       mesh->periodMap[n] = mesh->periodMap[mesh->periodMap[n]];
12580598e1a2SLisandro Dalcin 
12599dddd249SSatish Balay   /* Renumber vertices (filter out correspondings) */
12600598e1a2SLisandro Dalcin   mesh->numVerts = 0;
12610598e1a2SLisandro Dalcin   for (n = 0; n < mesh->numNodes; ++n)
12620598e1a2SLisandro Dalcin     if (mesh->vertexMap[n] >= 0)   /* is vertex */
12639dddd249SSatish Balay       if (mesh->periodMap[n] == n) /* is primary */
12640598e1a2SLisandro Dalcin         mesh->vertexMap[n] = mesh->numVerts++;
12650598e1a2SLisandro Dalcin   for (n = 0; n < mesh->numNodes; ++n)
12660598e1a2SLisandro Dalcin     if (mesh->vertexMap[n] >= 0)   /* is vertex */
12679dddd249SSatish Balay       if (mesh->periodMap[n] != n) /* is corresponding  */
12680598e1a2SLisandro Dalcin         mesh->vertexMap[n] = mesh->vertexMap[mesh->periodMap[n]];
12690598e1a2SLisandro Dalcin   PetscFunctionReturn(0);
12700598e1a2SLisandro Dalcin }
12710598e1a2SLisandro Dalcin 
1272066ea43fSLisandro Dalcin #define DM_POLYTOPE_VERTEX  DM_POLYTOPE_POINT
1273066ea43fSLisandro Dalcin #define DM_POLYTOPE_PYRAMID DM_POLYTOPE_UNKNOWN
1274066ea43fSLisandro Dalcin static const DMPolytopeType DMPolytopeMap[] = {
1275066ea43fSLisandro Dalcin   /* GMSH_VTX */ DM_POLYTOPE_VERTEX,
1276066ea43fSLisandro Dalcin   /* GMSH_SEG */ DM_POLYTOPE_SEGMENT,
1277066ea43fSLisandro Dalcin   /* GMSH_TRI */ DM_POLYTOPE_TRIANGLE,
1278066ea43fSLisandro Dalcin   /* GMSH_QUA */ DM_POLYTOPE_QUADRILATERAL,
1279066ea43fSLisandro Dalcin   /* GMSH_TET */ DM_POLYTOPE_TETRAHEDRON,
1280066ea43fSLisandro Dalcin   /* GMSH_HEX */ DM_POLYTOPE_HEXAHEDRON,
1281066ea43fSLisandro Dalcin   /* GMSH_PRI */ DM_POLYTOPE_TRI_PRISM,
1282066ea43fSLisandro Dalcin   /* GMSH_PYR */ DM_POLYTOPE_PYRAMID,
1283066ea43fSLisandro Dalcin   DM_POLYTOPE_UNKNOWN
1284066ea43fSLisandro Dalcin };
12850598e1a2SLisandro Dalcin 
12869fbee547SJacob Faibussowitsch static inline DMPolytopeType DMPolytopeTypeFromGmsh(PetscInt cellType)
12870598e1a2SLisandro Dalcin {
1288066ea43fSLisandro Dalcin   return DMPolytopeMap[GmshCellMap[cellType].polytope];
1289066ea43fSLisandro Dalcin }
1290066ea43fSLisandro Dalcin 
1291066ea43fSLisandro Dalcin static PetscErrorCode GmshCreateFE(MPI_Comm comm, const char prefix[], PetscBool isSimplex, PetscBool continuity, PetscDTNodeType nodeType, PetscInt dim, PetscInt Nc, PetscInt k, PetscFE *fem)
1292066ea43fSLisandro Dalcin {
1293066ea43fSLisandro Dalcin   DM              K;
1294066ea43fSLisandro Dalcin   PetscSpace      P;
1295066ea43fSLisandro Dalcin   PetscDualSpace  Q;
1296066ea43fSLisandro Dalcin   PetscQuadrature q, fq;
1297066ea43fSLisandro Dalcin   PetscBool       isTensor = isSimplex ? PETSC_FALSE : PETSC_TRUE;
1298066ea43fSLisandro Dalcin   PetscBool       endpoint = PETSC_TRUE;
1299066ea43fSLisandro Dalcin   char            name[32];
1300066ea43fSLisandro Dalcin 
1301066ea43fSLisandro Dalcin   PetscFunctionBegin;
1302066ea43fSLisandro Dalcin   /* Create space */
1303*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSpaceCreate(comm, &P));
1304*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSpaceSetType(P, PETSCSPACEPOLYNOMIAL));
1305*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSpacePolynomialSetTensor(P, isTensor));
1306*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSpaceSetNumComponents(P, Nc));
1307*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSpaceSetNumVariables(P, dim));
1308*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSpaceSetDegree(P, k, PETSC_DETERMINE));
1309066ea43fSLisandro Dalcin   if (prefix) {
1310*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectSetOptionsPrefix((PetscObject) P, prefix));
1311*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSpaceSetFromOptions(P));
1312*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectSetOptionsPrefix((PetscObject) P, NULL));
1313*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSpaceGetDegree(P, &k, NULL));
1314066ea43fSLisandro Dalcin   }
1315*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSpaceSetUp(P));
1316066ea43fSLisandro Dalcin   /* Create dual space */
1317*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDualSpaceCreate(comm, &Q));
1318*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDualSpaceSetType(Q, PETSCDUALSPACELAGRANGE));
1319*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDualSpaceLagrangeSetTensor(Q, isTensor));
1320*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDualSpaceLagrangeSetContinuity(Q, continuity));
1321*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDualSpaceLagrangeSetNodeType(Q, nodeType, endpoint, 0));
1322*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDualSpaceSetNumComponents(Q, Nc));
1323*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDualSpaceSetOrder(Q, k));
1324*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexCreateReferenceCell(PETSC_COMM_SELF, DMPolytopeTypeSimpleShape(dim, isSimplex), &K));
1325*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDualSpaceSetDM(Q, K));
1326*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMDestroy(&K));
1327066ea43fSLisandro Dalcin   if (prefix) {
1328*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectSetOptionsPrefix((PetscObject) Q, prefix));
1329*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscDualSpaceSetFromOptions(Q));
1330*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectSetOptionsPrefix((PetscObject) Q, NULL));
1331066ea43fSLisandro Dalcin   }
1332*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDualSpaceSetUp(Q));
1333066ea43fSLisandro Dalcin   /* Create quadrature */
1334066ea43fSLisandro Dalcin   if (isSimplex) {
1335*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscDTStroudConicalQuadrature(dim,   1, k+1, -1, +1, &q));
1336*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscDTStroudConicalQuadrature(dim-1, 1, k+1, -1, +1, &fq));
1337066ea43fSLisandro Dalcin   } else {
1338*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscDTGaussTensorQuadrature(dim,   1, k+1, -1, +1, &q));
1339*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscDTGaussTensorQuadrature(dim-1, 1, k+1, -1, +1, &fq));
1340066ea43fSLisandro Dalcin   }
1341066ea43fSLisandro Dalcin   /* Create finite element */
1342*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFECreate(comm, fem));
1343*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFESetType(*fem, PETSCFEBASIC));
1344*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFESetNumComponents(*fem, Nc));
1345*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFESetBasisSpace(*fem, P));
1346*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFESetDualSpace(*fem, Q));
1347*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFESetQuadrature(*fem, q));
1348*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFESetFaceQuadrature(*fem, fq));
1349066ea43fSLisandro Dalcin   if (prefix) {
1350*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectSetOptionsPrefix((PetscObject) *fem, prefix));
1351*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFESetFromOptions(*fem));
1352*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectSetOptionsPrefix((PetscObject) *fem, NULL));
1353066ea43fSLisandro Dalcin   }
1354*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFESetUp(*fem));
1355066ea43fSLisandro Dalcin   /* Cleanup */
1356*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSpaceDestroy(&P));
1357*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscDualSpaceDestroy(&Q));
1358*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscQuadratureDestroy(&q));
1359*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscQuadratureDestroy(&fq));
1360066ea43fSLisandro Dalcin   /* Set finite element name */
1361*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSNPrintf(name, sizeof(name), "%s%D", isSimplex? "P" : "Q", k));
1362*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFESetName(*fem, name));
1363066ea43fSLisandro Dalcin   PetscFunctionReturn(0);
136496ca5757SLisandro Dalcin }
136596ca5757SLisandro Dalcin 
1366d6689ca9SLisandro Dalcin /*@C
1367d6689ca9SLisandro Dalcin   DMPlexCreateGmshFromFile - Create a DMPlex mesh from a Gmsh file
1368d6689ca9SLisandro Dalcin 
1369d6689ca9SLisandro Dalcin + comm        - The MPI communicator
1370d6689ca9SLisandro Dalcin . filename    - Name of the Gmsh file
1371d6689ca9SLisandro Dalcin - interpolate - Create faces and edges in the mesh
1372d6689ca9SLisandro Dalcin 
1373d6689ca9SLisandro Dalcin   Output Parameter:
1374d6689ca9SLisandro Dalcin . dm  - The DM object representing the mesh
1375d6689ca9SLisandro Dalcin 
1376d6689ca9SLisandro Dalcin   Level: beginner
1377d6689ca9SLisandro Dalcin 
1378d6689ca9SLisandro Dalcin .seealso: DMPlexCreateFromFile(), DMPlexCreateGmsh(), DMPlexCreate()
1379d6689ca9SLisandro Dalcin @*/
1380d6689ca9SLisandro Dalcin PetscErrorCode DMPlexCreateGmshFromFile(MPI_Comm comm, const char filename[], PetscBool interpolate, DM *dm)
1381d6689ca9SLisandro Dalcin {
1382d6689ca9SLisandro Dalcin   PetscViewer     viewer;
1383d6689ca9SLisandro Dalcin   PetscMPIInt     rank;
1384d6689ca9SLisandro Dalcin   int             fileType;
1385d6689ca9SLisandro Dalcin   PetscViewerType vtype;
1386d6689ca9SLisandro Dalcin 
1387d6689ca9SLisandro Dalcin   PetscFunctionBegin;
1388*5f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Comm_rank(comm, &rank));
1389d6689ca9SLisandro Dalcin 
1390d6689ca9SLisandro Dalcin   /* Determine Gmsh file type (ASCII or binary) from file header */
1391dd400576SPatrick Sanan   if (rank == 0) {
13920598e1a2SLisandro Dalcin     GmshFile    gmsh[1];
1393d6689ca9SLisandro Dalcin     char        line[PETSC_MAX_PATH_LEN];
1394d6689ca9SLisandro Dalcin     int         snum;
1395d6689ca9SLisandro Dalcin     float       version;
1396d6689ca9SLisandro Dalcin 
1397*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscArrayzero(gmsh,1));
1398*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerCreate(PETSC_COMM_SELF, &gmsh->viewer));
1399*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerSetType(gmsh->viewer, PETSCVIEWERASCII));
1400*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerFileSetMode(gmsh->viewer, FILE_MODE_READ));
1401*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerFileSetName(gmsh->viewer, filename));
1402d6689ca9SLisandro Dalcin     /* Read only the first two lines of the Gmsh file */
1403*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshReadSection(gmsh, line));
1404*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshExpect(gmsh, "$MeshFormat", line));
1405*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshReadString(gmsh, line, 2));
1406d6689ca9SLisandro Dalcin     snum = sscanf(line, "%f %d", &version, &fileType);
14072c71b3e2SJacob Faibussowitsch     PetscCheckFalse(snum != 2,PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to parse Gmsh file header: %s", line);
14082c71b3e2SJacob Faibussowitsch     PetscCheckFalse(version < 2.2,PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at least 2.2", (double)version);
14092c71b3e2SJacob Faibussowitsch     PetscCheckFalse((int)version == 3,PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f not supported", (double)version);
14102c71b3e2SJacob Faibussowitsch     PetscCheckFalse(version > 4.1,PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at most 4.1", (double)version);
1411*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerDestroy(&gmsh->viewer));
1412d6689ca9SLisandro Dalcin   }
1413*5f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Bcast(&fileType, 1, MPI_INT, 0, comm));
1414d6689ca9SLisandro Dalcin   vtype = (fileType == 0) ? PETSCVIEWERASCII : PETSCVIEWERBINARY;
1415d6689ca9SLisandro Dalcin 
1416d6689ca9SLisandro Dalcin   /* Create appropriate viewer and build plex */
1417*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscViewerCreate(comm, &viewer));
1418*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscViewerSetType(viewer, vtype));
1419*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscViewerFileSetMode(viewer, FILE_MODE_READ));
1420*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscViewerFileSetName(viewer, filename));
1421*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexCreateGmsh(comm, viewer, interpolate, dm));
1422*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscViewerDestroy(&viewer));
1423d6689ca9SLisandro Dalcin   PetscFunctionReturn(0);
1424d6689ca9SLisandro Dalcin }
1425d6689ca9SLisandro Dalcin 
1426331830f3SMatthew G. Knepley /*@
14277d282ae0SMichael Lange   DMPlexCreateGmsh - Create a DMPlex mesh from a Gmsh file viewer
1428331830f3SMatthew G. Knepley 
1429d083f849SBarry Smith   Collective
1430331830f3SMatthew G. Knepley 
1431331830f3SMatthew G. Knepley   Input Parameters:
1432331830f3SMatthew G. Knepley + comm  - The MPI communicator
1433331830f3SMatthew G. Knepley . viewer - The Viewer associated with a Gmsh file
1434331830f3SMatthew G. Knepley - interpolate - Create faces and edges in the mesh
1435331830f3SMatthew G. Knepley 
1436331830f3SMatthew G. Knepley   Output Parameter:
1437331830f3SMatthew G. Knepley . dm  - The DM object representing the mesh
1438331830f3SMatthew G. Knepley 
1439698a79b9SLisandro Dalcin   Note: http://gmsh.info/doc/texinfo/gmsh.html#MSH-file-format
1440331830f3SMatthew G. Knepley 
1441331830f3SMatthew G. Knepley   Level: beginner
1442331830f3SMatthew G. Knepley 
1443331830f3SMatthew G. Knepley .seealso: DMPLEX, DMCreate()
1444331830f3SMatthew G. Knepley @*/
1445331830f3SMatthew G. Knepley PetscErrorCode DMPlexCreateGmsh(MPI_Comm comm, PetscViewer viewer, PetscBool interpolate, DM *dm)
1446331830f3SMatthew G. Knepley {
14470598e1a2SLisandro Dalcin   GmshMesh      *mesh = NULL;
144811c56cb0SLisandro Dalcin   PetscViewer    parentviewer = NULL;
14490598e1a2SLisandro Dalcin   PetscBT        periodicVerts = NULL;
14500598e1a2SLisandro Dalcin   PetscBT        periodicCells = NULL;
1451066ea43fSLisandro Dalcin   DM             cdm;
1452331830f3SMatthew G. Knepley   PetscSection   coordSection;
1453331830f3SMatthew G. Knepley   Vec            coordinates;
1454a45dabc8SMatthew G. Knepley   DMLabel        cellSets = NULL, faceSets = NULL, vertSets = NULL, marker = NULL, *regionSets;
1455066ea43fSLisandro Dalcin   PetscInt       dim = 0, coordDim = -1, order = 0;
14560598e1a2SLisandro Dalcin   PetscInt       numNodes = 0, numElems = 0, numVerts = 0, numCells = 0;
1457066ea43fSLisandro Dalcin   PetscInt       cell, cone[8], e, n, v, d;
145881a1af93SMatthew G. Knepley   PetscBool      binary, usemarker = PETSC_FALSE, useregions = PETSC_FALSE, markvertices = PETSC_FALSE;
14590598e1a2SLisandro Dalcin   PetscBool      hybrid = interpolate, periodic = PETSC_TRUE;
1460066ea43fSLisandro Dalcin   PetscBool      highOrder = PETSC_TRUE, highOrderSet, project = PETSC_FALSE;
1461066ea43fSLisandro Dalcin   PetscBool      isSimplex = PETSC_FALSE, isHybrid = PETSC_FALSE, hasTetra = PETSC_FALSE;
14620598e1a2SLisandro Dalcin   PetscMPIInt    rank;
1463331830f3SMatthew G. Knepley   PetscErrorCode ierr;
1464331830f3SMatthew G. Knepley 
1465331830f3SMatthew G. Knepley   PetscFunctionBegin;
1466*5f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Comm_rank(comm, &rank));
1467ef12879bSLisandro Dalcin   ierr = PetscObjectOptionsBegin((PetscObject)viewer);CHKERRQ(ierr);
1468*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsHead(PetscOptionsObject,"DMPlex Gmsh options"));
1469*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsBool("-dm_plex_gmsh_hybrid", "Generate hybrid cell bounds", "DMPlexCreateGmsh", hybrid, &hybrid, NULL));
1470*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsBool("-dm_plex_gmsh_periodic","Read Gmsh periodic section", "DMPlexCreateGmsh", periodic, &periodic, NULL));
1471*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsBool("-dm_plex_gmsh_highorder","Generate high-order coordinates", "DMPlexCreateGmsh", highOrder, &highOrder, &highOrderSet));
1472*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsBool("-dm_plex_gmsh_project", "Project high-order coordinates to a different space", "DMPlexCreateGmsh", project, &project, NULL));
1473*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsBool("-dm_plex_gmsh_use_marker", "Generate marker label", "DMPlexCreateGmsh", usemarker, &usemarker, NULL));
1474*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsBool("-dm_plex_gmsh_use_regions", "Generate labels with region names", "DMPlexCreateGmsh", useregions, &useregions, NULL));
1475*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsBool("-dm_plex_gmsh_mark_vertices", "Add vertices to generated labels", "DMPlexCreateGmsh", markvertices, &markvertices, NULL));
1476*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsBoundedInt("-dm_plex_gmsh_spacedim", "Embedding space dimension", "DMPlexCreateGmsh", coordDim, &coordDim, NULL, PETSC_DECIDE));
1477*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsTail());
1478ef12879bSLisandro Dalcin   ierr = PetscOptionsEnd();CHKERRQ(ierr);
14790598e1a2SLisandro Dalcin 
1480*5f80ce2aSJacob Faibussowitsch   CHKERRQ(GmshCellInfoSetUp());
148111c56cb0SLisandro Dalcin 
1482*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMCreate(comm, dm));
1483*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetType(*dm, DMPLEX));
1484*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscLogEventBegin(DMPLEX_CreateGmsh,*dm,NULL,NULL,NULL));
148511c56cb0SLisandro Dalcin 
1486*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &binary));
148711c56cb0SLisandro Dalcin 
148811c56cb0SLisandro Dalcin   /* Binary viewers read on all ranks, get subviewer to read only in rank 0 */
14893b46f529SLisandro Dalcin   if (binary) {
149011c56cb0SLisandro Dalcin     parentviewer = viewer;
1491*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerGetSubViewer(parentviewer, PETSC_COMM_SELF, &viewer));
149211c56cb0SLisandro Dalcin   }
149311c56cb0SLisandro Dalcin 
1494dd400576SPatrick Sanan   if (rank == 0) {
14950598e1a2SLisandro Dalcin     GmshFile  gmsh[1];
1496698a79b9SLisandro Dalcin     char      line[PETSC_MAX_PATH_LEN];
1497698a79b9SLisandro Dalcin     PetscBool match;
1498331830f3SMatthew G. Knepley 
1499*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscArrayzero(gmsh,1));
1500698a79b9SLisandro Dalcin     gmsh->viewer = viewer;
1501698a79b9SLisandro Dalcin     gmsh->binary = binary;
1502698a79b9SLisandro Dalcin 
1503*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshMeshCreate(&mesh));
15040598e1a2SLisandro Dalcin 
1505698a79b9SLisandro Dalcin     /* Read mesh format */
1506*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshReadSection(gmsh, line));
1507*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshExpect(gmsh, "$MeshFormat", line));
1508*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshReadMeshFormat(gmsh));
1509*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshReadEndSection(gmsh, "$EndMeshFormat", line));
151011c56cb0SLisandro Dalcin 
1511dc0ede3bSMatthew G. Knepley     /* OPTIONAL Read physical names */
1512*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshReadSection(gmsh, line));
1513*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshMatch(gmsh, "$PhysicalNames", line, &match));
1514dc0ede3bSMatthew G. Knepley     if (match) {
1515*5f80ce2aSJacob Faibussowitsch       CHKERRQ(GmshExpect(gmsh, "$PhysicalNames", line));
1516*5f80ce2aSJacob Faibussowitsch       CHKERRQ(GmshReadPhysicalNames(gmsh, mesh));
1517*5f80ce2aSJacob Faibussowitsch       CHKERRQ(GmshReadEndSection(gmsh, "$EndPhysicalNames", line));
1518698a79b9SLisandro Dalcin       /* Initial read for entity section */
1519*5f80ce2aSJacob Faibussowitsch       CHKERRQ(GmshReadSection(gmsh, line));
1520dc0ede3bSMatthew G. Knepley     }
152111c56cb0SLisandro Dalcin 
1522de78e4feSLisandro Dalcin     /* Read entities */
1523698a79b9SLisandro Dalcin     if (gmsh->fileFormat >= 40) {
1524*5f80ce2aSJacob Faibussowitsch       CHKERRQ(GmshExpect(gmsh, "$Entities", line));
1525*5f80ce2aSJacob Faibussowitsch       CHKERRQ(GmshReadEntities(gmsh, mesh));
1526*5f80ce2aSJacob Faibussowitsch       CHKERRQ(GmshReadEndSection(gmsh, "$EndEntities", line));
1527698a79b9SLisandro Dalcin       /* Initial read for nodes section */
1528*5f80ce2aSJacob Faibussowitsch       CHKERRQ(GmshReadSection(gmsh, line));
1529de78e4feSLisandro Dalcin     }
1530de78e4feSLisandro Dalcin 
1531698a79b9SLisandro Dalcin     /* Read nodes */
1532*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshExpect(gmsh, "$Nodes", line));
1533*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshReadNodes(gmsh, mesh));
1534*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshReadEndSection(gmsh, "$EndNodes", line));
153511c56cb0SLisandro Dalcin 
1536698a79b9SLisandro Dalcin     /* Read elements */
1537*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshReadSection(gmsh, line));
1538*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshExpect(gmsh, "$Elements", line));
1539*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshReadElements(gmsh, mesh));
1540*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshReadEndSection(gmsh, "$EndElements", line));
1541de78e4feSLisandro Dalcin 
15420598e1a2SLisandro Dalcin     /* Read periodic section (OPTIONAL) */
1543698a79b9SLisandro Dalcin     if (periodic) {
1544*5f80ce2aSJacob Faibussowitsch       CHKERRQ(GmshReadSection(gmsh, line));
1545*5f80ce2aSJacob Faibussowitsch       CHKERRQ(GmshMatch(gmsh, "$Periodic", line, &periodic));
1546ef12879bSLisandro Dalcin     }
1547ef12879bSLisandro Dalcin     if (periodic) {
1548*5f80ce2aSJacob Faibussowitsch       CHKERRQ(GmshExpect(gmsh, "$Periodic", line));
1549*5f80ce2aSJacob Faibussowitsch       CHKERRQ(GmshReadPeriodic(gmsh, mesh));
1550*5f80ce2aSJacob Faibussowitsch       CHKERRQ(GmshReadEndSection(gmsh, "$EndPeriodic", line));
1551698a79b9SLisandro Dalcin     }
1552698a79b9SLisandro Dalcin 
1553*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(gmsh->wbuf));
1554*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(gmsh->sbuf));
1555*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(gmsh->nbuf));
15560598e1a2SLisandro Dalcin 
15570598e1a2SLisandro Dalcin     dim       = mesh->dim;
1558066ea43fSLisandro Dalcin     order     = mesh->order;
15590598e1a2SLisandro Dalcin     numNodes  = mesh->numNodes;
15600598e1a2SLisandro Dalcin     numElems  = mesh->numElems;
15610598e1a2SLisandro Dalcin     numVerts  = mesh->numVerts;
15620598e1a2SLisandro Dalcin     numCells  = mesh->numCells;
1563066ea43fSLisandro Dalcin 
1564066ea43fSLisandro Dalcin     {
1565066ea43fSLisandro Dalcin       GmshElement *elemA = mesh->numCells > 0 ? mesh->elements : NULL;
1566066ea43fSLisandro Dalcin       GmshElement *elemB = elemA ? elemA + mesh->numCells - 1  : NULL;
1567066ea43fSLisandro Dalcin       int ptA = elemA ? GmshCellMap[elemA->cellType].polytope : -1;
1568066ea43fSLisandro Dalcin       int ptB = elemB ? GmshCellMap[elemB->cellType].polytope : -1;
1569066ea43fSLisandro Dalcin       isSimplex = (ptA == GMSH_QUA || ptA == GMSH_HEX) ? PETSC_FALSE : PETSC_TRUE;
1570066ea43fSLisandro Dalcin       isHybrid  = (ptA == ptB) ? PETSC_FALSE : PETSC_TRUE;
1571066ea43fSLisandro Dalcin       hasTetra  = (ptA == GMSH_TET) ? PETSC_TRUE : PETSC_FALSE;
1572066ea43fSLisandro Dalcin     }
1573698a79b9SLisandro Dalcin   }
1574698a79b9SLisandro Dalcin 
1575698a79b9SLisandro Dalcin   if (parentviewer) {
1576*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscViewerRestoreSubViewer(parentviewer, PETSC_COMM_SELF, &viewer));
1577698a79b9SLisandro Dalcin   }
1578698a79b9SLisandro Dalcin 
1579066ea43fSLisandro Dalcin   {
1580066ea43fSLisandro Dalcin     int buf[6];
1581698a79b9SLisandro Dalcin 
1582066ea43fSLisandro Dalcin     buf[0] = (int)dim;
1583066ea43fSLisandro Dalcin     buf[1] = (int)order;
1584066ea43fSLisandro Dalcin     buf[2] = periodic;
1585066ea43fSLisandro Dalcin     buf[3] = isSimplex;
1586066ea43fSLisandro Dalcin     buf[4] = isHybrid;
1587066ea43fSLisandro Dalcin     buf[5] = hasTetra;
1588066ea43fSLisandro Dalcin 
1589*5f80ce2aSJacob Faibussowitsch     CHKERRMPI(MPI_Bcast(buf, 6, MPI_INT, 0, comm));
1590066ea43fSLisandro Dalcin 
1591066ea43fSLisandro Dalcin     dim       = buf[0];
1592066ea43fSLisandro Dalcin     order     = buf[1];
1593066ea43fSLisandro Dalcin     periodic  = buf[2] ? PETSC_TRUE : PETSC_FALSE;
1594066ea43fSLisandro Dalcin     isSimplex = buf[3] ? PETSC_TRUE : PETSC_FALSE;
1595066ea43fSLisandro Dalcin     isHybrid  = buf[4] ? PETSC_TRUE : PETSC_FALSE;
1596066ea43fSLisandro Dalcin     hasTetra  = buf[5] ? PETSC_TRUE : PETSC_FALSE;
1597dea2a3c7SStefano Zampini   }
1598dea2a3c7SStefano Zampini 
1599066ea43fSLisandro Dalcin   if (!highOrderSet) highOrder = (order > 1) ? PETSC_TRUE : PETSC_FALSE;
16002c71b3e2SJacob Faibussowitsch   PetscCheckFalse(highOrder && isHybrid,comm, PETSC_ERR_SUP, "No support for discretization on hybrid meshes yet");
1601066ea43fSLisandro Dalcin 
16020598e1a2SLisandro Dalcin   /* We do not want this label automatically computed, instead we fill it here */
1603*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMCreateLabel(*dm, "celltype"));
160411c56cb0SLisandro Dalcin 
1605a4bb7517SMichael Lange   /* Allocate the cell-vertex mesh */
1606*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexSetChart(*dm, 0, numCells+numVerts));
16070598e1a2SLisandro Dalcin   for (cell = 0; cell < numCells; ++cell) {
16080598e1a2SLisandro Dalcin     GmshElement *elem = mesh->elements + cell;
16090598e1a2SLisandro Dalcin     DMPolytopeType ctype = DMPolytopeTypeFromGmsh(elem->cellType);
16100598e1a2SLisandro Dalcin     if (hybrid && hasTetra && ctype == DM_POLYTOPE_TRI_PRISM) ctype = DM_POLYTOPE_TRI_PRISM_TENSOR;
1611*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexSetConeSize(*dm, cell, elem->numVerts));
1612*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexSetCellType(*dm, cell, ctype));
1613db397164SMichael Lange   }
16140598e1a2SLisandro Dalcin   for (v = numCells; v < numCells+numVerts; ++v) {
1615*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexSetCellType(*dm, v, DM_POLYTOPE_POINT));
161696ca5757SLisandro Dalcin   }
1617*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetUp(*dm));
161896ca5757SLisandro Dalcin 
1619a4bb7517SMichael Lange   /* Add cell-vertex connections */
16200598e1a2SLisandro Dalcin   for (cell = 0; cell < numCells; ++cell) {
16210598e1a2SLisandro Dalcin     GmshElement *elem = mesh->elements + cell;
16220598e1a2SLisandro Dalcin     for (v = 0; v < elem->numVerts; ++v) {
16230598e1a2SLisandro Dalcin       const PetscInt nn = elem->nodes[v];
16240598e1a2SLisandro Dalcin       const PetscInt vv = mesh->vertexMap[nn];
16250598e1a2SLisandro Dalcin       cone[v] = numCells + vv;
1626db397164SMichael Lange     }
1627*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexReorderCell(*dm, cell, cone));
1628*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexSetCone(*dm, cell, cone));
1629a4bb7517SMichael Lange   }
163096ca5757SLisandro Dalcin 
1631*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetDimension(*dm, dim));
1632*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexSymmetrize(*dm));
1633*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexStratify(*dm));
1634331830f3SMatthew G. Knepley   if (interpolate) {
16355fd9971aSMatthew G. Knepley     DM idm;
1636331830f3SMatthew G. Knepley 
1637*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexInterpolate(*dm, &idm));
1638*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMDestroy(dm));
1639331830f3SMatthew G. Knepley     *dm  = idm;
1640331830f3SMatthew G. Knepley   }
1641917266a4SLisandro Dalcin 
164281a1af93SMatthew G. Knepley   /* Create the label "marker" over the whole boundary */
16432c71b3e2SJacob Faibussowitsch   PetscCheckFalse(usemarker && !interpolate && dim > 1,comm,PETSC_ERR_SUP,"Cannot create marker label without interpolation");
1644dd400576SPatrick Sanan   if (rank == 0 && usemarker) {
1645d3f73514SStefano Zampini     PetscInt f, fStart, fEnd;
1646d3f73514SStefano Zampini 
1647*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMCreateLabel(*dm, "marker"));
1648*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetHeightStratum(*dm, 1, &fStart, &fEnd));
1649d3f73514SStefano Zampini     for (f = fStart; f < fEnd; ++f) {
1650d3f73514SStefano Zampini       PetscInt suppSize;
1651d3f73514SStefano Zampini 
1652*5f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetSupportSize(*dm, f, &suppSize));
1653d3f73514SStefano Zampini       if (suppSize == 1) {
1654d3f73514SStefano Zampini         PetscInt *cone = NULL, coneSize, p;
1655d3f73514SStefano Zampini 
1656*5f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetTransitiveClosure(*dm, f, PETSC_TRUE, &coneSize, &cone));
1657d3f73514SStefano Zampini         for (p = 0; p < coneSize; p += 2) {
1658*5f80ce2aSJacob Faibussowitsch           CHKERRQ(DMSetLabelValue_Fast(*dm, &marker, "marker", cone[p], 1));
1659d3f73514SStefano Zampini         }
1660*5f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexRestoreTransitiveClosure(*dm, f, PETSC_TRUE, &coneSize, &cone));
1661d3f73514SStefano Zampini       }
1662d3f73514SStefano Zampini     }
1663d3f73514SStefano Zampini   }
166416ad7e67SMichael Lange 
1665dd400576SPatrick Sanan   if (rank == 0) {
1666a45dabc8SMatthew G. Knepley     const PetscInt Nr = useregions ? mesh->numRegions : 0;
166711c56cb0SLisandro Dalcin     PetscInt       vStart, vEnd;
1668d1a54cefSMatthew G. Knepley 
1669*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscCalloc1(Nr, &regionSets));
1670*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetDepthStratum(*dm, 0, &vStart, &vEnd));
16710598e1a2SLisandro Dalcin     for (cell = 0, e = 0; e < numElems; ++e) {
16720598e1a2SLisandro Dalcin       GmshElement *elem = mesh->elements + e;
16736e1dd89aSLawrence Mitchell 
16746e1dd89aSLawrence Mitchell       /* Create cell sets */
16750598e1a2SLisandro Dalcin       if (elem->dim == dim && dim > 0) {
16760598e1a2SLisandro Dalcin         if (elem->numTags > 0) {
1677a45dabc8SMatthew G. Knepley           const PetscInt tag = elem->tags[0];
1678a45dabc8SMatthew G. Knepley           PetscInt       r;
1679a45dabc8SMatthew G. Knepley 
1680*5f80ce2aSJacob Faibussowitsch           if (!Nr) CHKERRQ(DMSetLabelValue_Fast(*dm, &cellSets, "Cell Sets", cell, tag));
1681a45dabc8SMatthew G. Knepley           for (r = 0; r < Nr; ++r) {
1682*5f80ce2aSJacob Faibussowitsch             if (mesh->regionTags[r] == tag) CHKERRQ(DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], cell, tag));
1683a45dabc8SMatthew G. Knepley           }
16846e1dd89aSLawrence Mitchell         }
1685917266a4SLisandro Dalcin         cell++;
16866e1dd89aSLawrence Mitchell       }
16870c070f12SSander Arens 
16880598e1a2SLisandro Dalcin       /* Create face sets */
16890598e1a2SLisandro Dalcin       if (interpolate && elem->dim == dim-1) {
16900598e1a2SLisandro Dalcin         PetscInt        joinSize;
16910598e1a2SLisandro Dalcin         const PetscInt *join = NULL;
1692a45dabc8SMatthew G. Knepley         const PetscInt  tag = elem->tags[0];
1693a45dabc8SMatthew G. Knepley         PetscInt        r;
1694a45dabc8SMatthew G. Knepley 
16950598e1a2SLisandro Dalcin         /* Find the relevant facet with vertex joins */
16960598e1a2SLisandro Dalcin         for (v = 0; v < elem->numVerts; ++v) {
16970598e1a2SLisandro Dalcin           const PetscInt nn = elem->nodes[v];
16980598e1a2SLisandro Dalcin           const PetscInt vv = mesh->vertexMap[nn];
16990598e1a2SLisandro Dalcin           cone[v] = vStart + vv;
17000598e1a2SLisandro Dalcin         }
1701*5f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetFullJoin(*dm, elem->numVerts, cone, &joinSize, &join));
17022c71b3e2SJacob Faibussowitsch         PetscCheckFalse(joinSize != 1,PETSC_COMM_SELF, PETSC_ERR_SUP, "Could not determine Plex facet for Gmsh element %D (Plex cell %D)", elem->id, e);
1703*5f80ce2aSJacob Faibussowitsch         if (!Nr) CHKERRQ(DMSetLabelValue_Fast(*dm, &faceSets, "Face Sets", join[0], tag));
1704a45dabc8SMatthew G. Knepley         for (r = 0; r < Nr; ++r) {
1705*5f80ce2aSJacob Faibussowitsch           if (mesh->regionTags[r] == tag) CHKERRQ(DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], join[0], tag));
1706a45dabc8SMatthew G. Knepley         }
1707*5f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexRestoreJoin(*dm, elem->numVerts, cone, &joinSize, &join));
17080598e1a2SLisandro Dalcin       }
17090598e1a2SLisandro Dalcin 
17100c070f12SSander Arens       /* Create vertex sets */
17110598e1a2SLisandro Dalcin       if (elem->dim == 0) {
17120598e1a2SLisandro Dalcin         if (elem->numTags > 0) {
17130598e1a2SLisandro Dalcin           const PetscInt nn = elem->nodes[0];
17140598e1a2SLisandro Dalcin           const PetscInt vv = mesh->vertexMap[nn];
1715a45dabc8SMatthew G. Knepley           const PetscInt tag = elem->tags[0];
1716a45dabc8SMatthew G. Knepley           PetscInt       r;
1717a45dabc8SMatthew G. Knepley 
1718*5f80ce2aSJacob Faibussowitsch           if (!Nr) CHKERRQ(DMSetLabelValue_Fast(*dm, &vertSets, "Vertex Sets", vStart + vv, tag));
171981a1af93SMatthew G. Knepley           for (r = 0; r < Nr; ++r) {
1720*5f80ce2aSJacob Faibussowitsch             if (mesh->regionTags[r] == tag) CHKERRQ(DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], vStart + vv, tag));
172181a1af93SMatthew G. Knepley           }
172281a1af93SMatthew G. Knepley         }
172381a1af93SMatthew G. Knepley       }
172481a1af93SMatthew G. Knepley     }
172581a1af93SMatthew G. Knepley     if (markvertices) {
172681a1af93SMatthew G. Knepley       for (v = 0; v < numNodes; ++v) {
172781a1af93SMatthew G. Knepley         const PetscInt vv  = mesh->vertexMap[v];
172881a1af93SMatthew G. Knepley         const PetscInt tag = mesh->nodelist->tag[v];
172981a1af93SMatthew G. Knepley         PetscInt       r;
173081a1af93SMatthew G. Knepley 
173181a1af93SMatthew G. Knepley         if (tag != -1) {
1732*5f80ce2aSJacob Faibussowitsch           if (!Nr) CHKERRQ(DMSetLabelValue_Fast(*dm, &vertSets, "Vertex Sets", vStart + vv, tag));
1733a45dabc8SMatthew G. Knepley           for (r = 0; r < Nr; ++r) {
1734*5f80ce2aSJacob Faibussowitsch             if (mesh->regionTags[r] == tag) CHKERRQ(DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], vStart + vv, tag));
17350598e1a2SLisandro Dalcin           }
17360598e1a2SLisandro Dalcin         }
17370598e1a2SLisandro Dalcin       }
17380598e1a2SLisandro Dalcin     }
1739*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(regionSets));
1740a45dabc8SMatthew G. Knepley   }
17410598e1a2SLisandro Dalcin 
17427dd454faSLisandro Dalcin   { /* Create Cell/Face/Vertex Sets labels at all processes */
17437dd454faSLisandro Dalcin     enum {n = 4};
17447dd454faSLisandro Dalcin     PetscBool flag[n];
17457dd454faSLisandro Dalcin 
17467dd454faSLisandro Dalcin     flag[0] = cellSets ? PETSC_TRUE : PETSC_FALSE;
17477dd454faSLisandro Dalcin     flag[1] = faceSets ? PETSC_TRUE : PETSC_FALSE;
17487dd454faSLisandro Dalcin     flag[2] = vertSets ? PETSC_TRUE : PETSC_FALSE;
17497dd454faSLisandro Dalcin     flag[3] = marker   ? PETSC_TRUE : PETSC_FALSE;
1750*5f80ce2aSJacob Faibussowitsch     CHKERRMPI(MPI_Bcast(flag, n, MPIU_BOOL, 0, comm));
1751*5f80ce2aSJacob Faibussowitsch     if (flag[0]) CHKERRQ(DMCreateLabel(*dm, "Cell Sets"));
1752*5f80ce2aSJacob Faibussowitsch     if (flag[1]) CHKERRQ(DMCreateLabel(*dm, "Face Sets"));
1753*5f80ce2aSJacob Faibussowitsch     if (flag[2]) CHKERRQ(DMCreateLabel(*dm, "Vertex Sets"));
1754*5f80ce2aSJacob Faibussowitsch     if (flag[3]) CHKERRQ(DMCreateLabel(*dm, "marker"));
17557dd454faSLisandro Dalcin   }
17567dd454faSLisandro Dalcin 
17570598e1a2SLisandro Dalcin   if (periodic) {
1758*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscBTCreate(numVerts, &periodicVerts));
17590598e1a2SLisandro Dalcin     for (n = 0; n < numNodes; ++n) {
17600598e1a2SLisandro Dalcin       if (mesh->vertexMap[n] >= 0) {
17610598e1a2SLisandro Dalcin         if (PetscUnlikely(mesh->periodMap[n] != n)) {
17620598e1a2SLisandro Dalcin           PetscInt m = mesh->periodMap[n];
1763*5f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscBTSet(periodicVerts, mesh->vertexMap[n]));
1764*5f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscBTSet(periodicVerts, mesh->vertexMap[m]));
17650598e1a2SLisandro Dalcin         }
17660598e1a2SLisandro Dalcin       }
17670598e1a2SLisandro Dalcin     }
1768*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscBTCreate(numCells, &periodicCells));
17690598e1a2SLisandro Dalcin     for (cell = 0; cell < numCells; ++cell) {
17700598e1a2SLisandro Dalcin       GmshElement *elem = mesh->elements + cell;
17710598e1a2SLisandro Dalcin       for (v = 0; v < elem->numVerts; ++v) {
17720598e1a2SLisandro Dalcin         PetscInt nn = elem->nodes[v];
17730598e1a2SLisandro Dalcin         PetscInt vv = mesh->vertexMap[nn];
17740598e1a2SLisandro Dalcin         if (PetscUnlikely(PetscBTLookup(periodicVerts, vv))) {
1775*5f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscBTSet(periodicCells, cell)); break;
17760c070f12SSander Arens         }
17770c070f12SSander Arens       }
17780c070f12SSander Arens     }
177916ad7e67SMichael Lange   }
178016ad7e67SMichael Lange 
1781066ea43fSLisandro Dalcin   /* Setup coordinate DM */
17820598e1a2SLisandro Dalcin   if (coordDim < 0) coordDim = dim;
1783*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetCoordinateDim(*dm, coordDim));
1784*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetCoordinateDM(*dm, &cdm));
1785066ea43fSLisandro Dalcin   if (highOrder) {
1786066ea43fSLisandro Dalcin     PetscFE         fe;
1787066ea43fSLisandro Dalcin     PetscBool       continuity = periodic ? PETSC_FALSE : PETSC_TRUE;
1788066ea43fSLisandro Dalcin     PetscDTNodeType nodeType   = PETSCDTNODES_EQUISPACED;
1789066ea43fSLisandro Dalcin 
1790066ea43fSLisandro Dalcin     if (isSimplex) continuity = PETSC_FALSE; /* XXX FIXME Requires DMPlexSetClosurePermutationLexicographic() */
1791066ea43fSLisandro Dalcin 
1792*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshCreateFE(comm, NULL, isSimplex, continuity, nodeType, dim, coordDim, order, &fe));
1793*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFEViewFromOptions(fe, NULL, "-dm_plex_gmsh_fe_view"));
1794*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMSetField(cdm, 0, NULL, (PetscObject) fe));
1795*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFEDestroy(&fe));
1796*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMCreateDS(cdm));
1797066ea43fSLisandro Dalcin   }
1798066ea43fSLisandro Dalcin 
1799066ea43fSLisandro Dalcin   /* Create coordinates */
1800066ea43fSLisandro Dalcin   if (highOrder) {
1801066ea43fSLisandro Dalcin 
1802066ea43fSLisandro Dalcin     PetscInt     maxDof = GmshNumNodes_HEX(order)*coordDim;
1803066ea43fSLisandro Dalcin     double       *coords = mesh ? mesh->nodelist->xyz : NULL;
1804066ea43fSLisandro Dalcin     PetscSection section;
1805066ea43fSLisandro Dalcin     PetscScalar  *cellCoords;
1806066ea43fSLisandro Dalcin 
1807*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMSetLocalSection(cdm, NULL));
1808*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetLocalSection(cdm, &coordSection));
1809*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionClone(coordSection, &section));
1810*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexSetClosurePermutationTensor(cdm, 0, section)); /* XXX Implement DMPlexSetClosurePermutationLexicographic() */
1811066ea43fSLisandro Dalcin 
1812*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMCreateLocalVector(cdm, &coordinates));
1813*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(maxDof, &cellCoords));
1814066ea43fSLisandro Dalcin     for (cell = 0; cell < numCells; ++cell) {
1815066ea43fSLisandro Dalcin       GmshElement *elem = mesh->elements + cell;
1816066ea43fSLisandro Dalcin       const int *lexorder = GmshCellMap[elem->cellType].lexorder();
1817b9bf55e5SMatthew G. Knepley       int s = 0;
1818066ea43fSLisandro Dalcin       for (n = 0; n < elem->numNodes; ++n) {
1819b9bf55e5SMatthew G. Knepley         while (lexorder[n+s] < 0) ++s;
1820b9bf55e5SMatthew G. Knepley         const PetscInt node = elem->nodes[lexorder[n+s]];
1821b9bf55e5SMatthew G. Knepley         for (d = 0; d < coordDim; ++d) cellCoords[(n+s)*coordDim+d] = (PetscReal) coords[node*3+d];
1822b9bf55e5SMatthew G. Knepley       }
1823b9bf55e5SMatthew G. Knepley       if (s) {
1824b9bf55e5SMatthew G. Knepley         /* For the coordinate mapping we weight vertices by -1/4 and edges by 1/2, which we get from Q_2 interpolation */
1825b9bf55e5SMatthew G. Knepley         PetscReal quaCenterWeights[9]  = {-0.25, 0.5, -0.25, 0.5, 0.0, 0.5, -0.25, 0.5, -0.25};
1826b9bf55e5SMatthew G. Knepley         /* For the coordinate mapping we weight vertices by -1/4 and edges by 1/2, which we get from Q_2 interpolation */
1827b9bf55e5SMatthew G. Knepley         PetscReal hexBottomWeights[27] = {-0.25, 0.5,  -0.25, 0.5,  0.0, 0.5,  -0.25, 0.5,  -0.25,
1828b9bf55e5SMatthew G. Knepley                                            0.0,  0.0,   0.0,  0.0,  0.0, 0.0,   0.0,  0.0,   0.0,
1829b9bf55e5SMatthew G. Knepley                                            0.0,  0.0,   0.0,  0.0,  0.0, 0.0,   0.0,  0.0,   0.0};
1830b9bf55e5SMatthew G. Knepley         PetscReal hexFrontWeights[27]  = {-0.25, 0.5,  -0.25, 0.0,  0.0, 0.0,   0.0,  0.0,   0.0,
1831b9bf55e5SMatthew G. Knepley                                            0.5,  0.0,   0.5,  0.0,  0.0, 0.0,   0.0,  0.0,   0.0,
1832b9bf55e5SMatthew G. Knepley                                           -0.25, 0.5,  -0.25, 0.0,  0.0, 0.0,   0.0,  0.0,   0.0};
1833b9bf55e5SMatthew G. Knepley         PetscReal hexLeftWeights[27]   = {-0.25, 0.0,   0.0,  0.5,  0.0, 0.0,  -0.25, 0.0,   0.0,
1834b9bf55e5SMatthew G. Knepley                                            0.5,  0.0,   0.0,  0.0,  0.0, 0.0,   0.5,  0.0,   0.0,
1835b9bf55e5SMatthew G. Knepley                                           -0.25, 0.0,   0.0,  0.5,  0.0, 0.0,  -0.25, 0.0,   0.0};
1836b9bf55e5SMatthew G. Knepley         PetscReal hexRightWeights[27]  = { 0.0,  0.0,  -0.25, 0.0,  0.0, 0.5,   0.0,  0.0,  -0.25,
1837b9bf55e5SMatthew G. Knepley                                            0.0,  0.0,   0.5,  0.0,  0.0, 0.0,   0.0,  0.0,   0.5,
1838b9bf55e5SMatthew G. Knepley                                            0.0,  0.0,  -0.25, 0.0,  0.0, 0.5,   0.0,  0.0,  -0.25};
1839b9bf55e5SMatthew G. Knepley         PetscReal hexBackWeights[27]   = { 0.0,  0.0,   0.0,  0.0,  0.0, 0.0,  -0.25, 0.5,  -0.25,
1840b9bf55e5SMatthew G. Knepley                                            0.0,  0.0,   0.0,  0.0,  0.0, 0.0,   0.5,  0.0,   0.5,
1841b9bf55e5SMatthew G. Knepley                                            0.0,  0.0,   0.0,  0.0,  0.0, 0.0,  -0.25, 0.5,  -0.25};
1842b9bf55e5SMatthew G. Knepley         PetscReal hexTopWeights[27]    = { 0.0,  0.0,   0.0,  0.0,  0.0, 0.0,   0.0,  0.0,   0.0,
1843b9bf55e5SMatthew G. Knepley                                            0.0,  0.0,   0.0,  0.0,  0.0, 0.0,   0.0,  0.0,   0.0,
1844b9bf55e5SMatthew G. Knepley                                           -0.25, 0.5,  -0.25, 0.5,  0.0, 0.5,  -0.25, 0.5,  -0.25};
1845b9bf55e5SMatthew G. Knepley         PetscReal hexCenterWeights[27] = {-0.25, 0.25, -0.25, 0.25, 0.0, 0.25, -0.25, 0.25, -0.25,
1846b9bf55e5SMatthew G. Knepley                                            0.25, 0.0,   0.25, 0.0,  0.0, 0.0,   0.25, 0.0,   0.25,
1847b9bf55e5SMatthew G. Knepley                                           -0.25, 0.25, -0.25, 0.25, 0.0, 0.25, -0.25, 0.25, -0.25};
1848b9bf55e5SMatthew G. Knepley         PetscReal  *sdWeights2[9]      = {NULL, NULL, NULL, NULL, quaCenterWeights, NULL, NULL, NULL, NULL};
1849b9bf55e5SMatthew G. Knepley         PetscReal  *sdWeights3[27]     = {NULL, NULL, NULL, NULL, hexBottomWeights, NULL, NULL, NULL, NULL,
1850b9bf55e5SMatthew G. Knepley                                           NULL, hexFrontWeights, NULL, hexLeftWeights, hexCenterWeights, hexRightWeights, NULL, hexBackWeights, NULL,
1851b9bf55e5SMatthew G. Knepley                                           NULL, NULL, NULL, NULL, hexTopWeights,    NULL, NULL, NULL, NULL};
1852b9bf55e5SMatthew G. Knepley         PetscReal **sdWeights[4]       = {NULL, NULL, sdWeights2, sdWeights3};
1853b9bf55e5SMatthew G. Knepley 
1854b9bf55e5SMatthew G. Knepley         /* Missing entries in serendipity cell, only works for 8-node quad and 20-node hex */
1855b9bf55e5SMatthew G. Knepley         for (n = 0; n < elem->numNodes+s; ++n) {
1856b9bf55e5SMatthew G. Knepley           if (lexorder[n] >= 0) continue;
1857b9bf55e5SMatthew G. Knepley           for (d = 0; d < coordDim; ++d) cellCoords[n*coordDim+d] = 0.0;
1858b9bf55e5SMatthew G. Knepley           for (int bn = 0; bn < elem->numNodes+s; ++bn) {
1859b9bf55e5SMatthew G. Knepley             if (lexorder[bn] < 0) continue;
1860b9bf55e5SMatthew G. Knepley             const PetscReal *weights = sdWeights[coordDim][n];
1861b9bf55e5SMatthew G. Knepley             const PetscInt   bnode   = elem->nodes[lexorder[bn]];
1862b9bf55e5SMatthew G. Knepley             for (d = 0; d < coordDim; ++d) cellCoords[n*coordDim+d] += weights[bn] * (PetscReal) coords[bnode*3+d];
1863b9bf55e5SMatthew G. Knepley           }
1864b9bf55e5SMatthew G. Knepley         }
1865066ea43fSLisandro Dalcin       }
1866*5f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexVecSetClosure(cdm, section, coordinates, cell, cellCoords, INSERT_VALUES));
1867066ea43fSLisandro Dalcin     }
1868*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionDestroy(&section));
1869*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(cellCoords));
1870066ea43fSLisandro Dalcin 
1871066ea43fSLisandro Dalcin   } else {
1872066ea43fSLisandro Dalcin 
1873066ea43fSLisandro Dalcin     PetscInt    *nodeMap;
1874066ea43fSLisandro Dalcin     double      *coords = mesh ? mesh->nodelist->xyz : NULL;
1875066ea43fSLisandro Dalcin     PetscScalar *pointCoords;
1876066ea43fSLisandro Dalcin 
1877*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetLocalSection(cdm, &coordSection));
1878*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionSetNumFields(coordSection, 1));
1879*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionSetFieldComponents(coordSection, 0, coordDim));
18800598e1a2SLisandro Dalcin     if (periodic) { /* we need to localize coordinates on cells */
1881*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionSetChart(coordSection, 0, numCells+numVerts));
1882f45c9589SStefano Zampini     } else {
1883*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionSetChart(coordSection, numCells, numCells+numVerts));
1884f45c9589SStefano Zampini     }
18850598e1a2SLisandro Dalcin     if (periodic) {
18860598e1a2SLisandro Dalcin       for (cell = 0; cell < numCells; ++cell) {
18870598e1a2SLisandro Dalcin         if (PetscUnlikely(PetscBTLookup(periodicCells, cell))) {
18880598e1a2SLisandro Dalcin           GmshElement *elem = mesh->elements + cell;
18890598e1a2SLisandro Dalcin           PetscInt dof = elem->numVerts * coordDim;
1890*5f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionSetDof(coordSection, cell, dof));
1891*5f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionSetFieldDof(coordSection, cell, 0, dof));
1892f45c9589SStefano Zampini         }
1893f45c9589SStefano Zampini       }
1894f45c9589SStefano Zampini     }
18950598e1a2SLisandro Dalcin     for (v = numCells; v < numCells+numVerts; ++v) {
1896*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionSetDof(coordSection, v, coordDim));
1897*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionSetFieldDof(coordSection, v, 0, coordDim));
18980598e1a2SLisandro Dalcin     }
1899*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionSetUp(coordSection));
1900066ea43fSLisandro Dalcin 
1901*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMCreateLocalVector(cdm, &coordinates));
1902*5f80ce2aSJacob Faibussowitsch     CHKERRQ(VecGetArray(coordinates, &pointCoords));
19030598e1a2SLisandro Dalcin     if (periodic) {
19040598e1a2SLisandro Dalcin       for (cell = 0; cell < numCells; ++cell) {
19050598e1a2SLisandro Dalcin         if (PetscUnlikely(PetscBTLookup(periodicCells, cell))) {
19060598e1a2SLisandro Dalcin           GmshElement *elem = mesh->elements + cell;
19070598e1a2SLisandro Dalcin           PetscInt off, node;
19080598e1a2SLisandro Dalcin           for (v = 0; v < elem->numVerts; ++v)
19090598e1a2SLisandro Dalcin             cone[v] = elem->nodes[v];
1910*5f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexReorderCell(cdm, cell, cone));
1911*5f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSectionGetOffset(coordSection, cell, &off));
19120598e1a2SLisandro Dalcin           for (v = 0; v < elem->numVerts; ++v)
19130598e1a2SLisandro Dalcin             for (node = cone[v], d = 0; d < coordDim; ++d)
1914066ea43fSLisandro Dalcin               pointCoords[off++] = (PetscReal) coords[node*3+d];
1915331830f3SMatthew G. Knepley         }
1916331830f3SMatthew G. Knepley       }
1917331830f3SMatthew G. Knepley     }
1918*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(numVerts, &nodeMap));
19190598e1a2SLisandro Dalcin     for (n = 0; n < numNodes; n++)
19200598e1a2SLisandro Dalcin       if (mesh->vertexMap[n] >= 0)
1921066ea43fSLisandro Dalcin         nodeMap[mesh->vertexMap[n]] = n;
19220598e1a2SLisandro Dalcin     for (v = 0; v < numVerts; ++v) {
1923066ea43fSLisandro Dalcin       PetscInt off, node = nodeMap[v];
1924*5f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetOffset(coordSection, numCells + v, &off));
19250598e1a2SLisandro Dalcin       for (d = 0; d < coordDim; ++d)
1926066ea43fSLisandro Dalcin         pointCoords[off+d] = (PetscReal) coords[node*3+d];
19270598e1a2SLisandro Dalcin     }
1928*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(nodeMap));
1929*5f80ce2aSJacob Faibussowitsch     CHKERRQ(VecRestoreArray(coordinates, &pointCoords));
1930066ea43fSLisandro Dalcin 
1931066ea43fSLisandro Dalcin   }
1932066ea43fSLisandro Dalcin 
1933*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectSetName((PetscObject) coordinates, "coordinates"));
1934*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSetBlockSize(coordinates, coordDim));
1935*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetCoordinatesLocal(*dm, coordinates));
1936*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&coordinates));
1937*5f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetPeriodicity(*dm, periodic, NULL, NULL, NULL));
193811c56cb0SLisandro Dalcin 
1939*5f80ce2aSJacob Faibussowitsch   CHKERRQ(GmshMeshDestroy(&mesh));
1940*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscBTDestroy(&periodicVerts));
1941*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscBTDestroy(&periodicCells));
194211c56cb0SLisandro Dalcin 
1943066ea43fSLisandro Dalcin   if (highOrder && project)  {
1944066ea43fSLisandro Dalcin     PetscFE         fe;
1945066ea43fSLisandro Dalcin     const char      prefix[]   = "dm_plex_gmsh_project_";
1946066ea43fSLisandro Dalcin     PetscBool       continuity = periodic ? PETSC_FALSE : PETSC_TRUE;
1947066ea43fSLisandro Dalcin     PetscDTNodeType nodeType   = PETSCDTNODES_GAUSSJACOBI;
1948066ea43fSLisandro Dalcin 
1949066ea43fSLisandro Dalcin     if (isSimplex) continuity = PETSC_FALSE; /* XXX FIXME Requires DMPlexSetClosurePermutationLexicographic() */
1950066ea43fSLisandro Dalcin 
1951*5f80ce2aSJacob Faibussowitsch     CHKERRQ(GmshCreateFE(comm, prefix, isSimplex, continuity, nodeType, dim, coordDim, order, &fe));
1952*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFEViewFromOptions(fe, NULL, "-dm_plex_gmsh_project_fe_view"));
1953*5f80ce2aSJacob Faibussowitsch     CHKERRQ(DMProjectCoordinates(*dm, fe));
1954*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFEDestroy(&fe));
1955066ea43fSLisandro Dalcin   }
1956066ea43fSLisandro Dalcin 
1957*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscLogEventEnd(DMPLEX_CreateGmsh,*dm,NULL,NULL,NULL));
1958331830f3SMatthew G. Knepley   PetscFunctionReturn(0);
1959331830f3SMatthew G. Knepley }
1960