xref: /petsc/src/dm/impls/plex/plexgmsh.c (revision b9bf55e54e629a92c5d1645aa648429faa277013)
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 
16*b9bf55e5SMatthew G. Knepley static int *GmshLexOrder_QUA_2_Serendipity(void)
17*b9bf55e5SMatthew G. Knepley {
18*b9bf55e5SMatthew G. Knepley   static int Gmsh_LexOrder_QUA_2_Serendipity[9] = {-1};
19*b9bf55e5SMatthew G. Knepley   int *lex = Gmsh_LexOrder_QUA_2_Serendipity;
20*b9bf55e5SMatthew G. Knepley   if (lex[0] == -1) {
21*b9bf55e5SMatthew G. Knepley     /* Vertices */
22*b9bf55e5SMatthew G. Knepley     lex[0] = 0; lex[2] = 1; lex[8] = 2; lex[6] = 3;
23*b9bf55e5SMatthew G. Knepley     /* Edges */
24*b9bf55e5SMatthew G. Knepley     lex[1] = 4; lex[5] = 5; lex[7] = 6; lex[3] = 7;
25*b9bf55e5SMatthew G. Knepley     /* Cell */
26*b9bf55e5SMatthew G. Knepley     lex[4] = -8;
27*b9bf55e5SMatthew G. Knepley   }
28*b9bf55e5SMatthew G. Knepley   return lex;
29*b9bf55e5SMatthew G. Knepley }
30*b9bf55e5SMatthew G. Knepley 
31*b9bf55e5SMatthew G. Knepley static int *GmshLexOrder_HEX_2_Serendipity(void)
32*b9bf55e5SMatthew G. Knepley {
33*b9bf55e5SMatthew G. Knepley   static int Gmsh_LexOrder_HEX_2_Serendipity[27] = {-1};
34*b9bf55e5SMatthew G. Knepley   int *lex = Gmsh_LexOrder_HEX_2_Serendipity;
35*b9bf55e5SMatthew G. Knepley   if (lex[0] == -1) {
36*b9bf55e5SMatthew G. Knepley     /* Vertices */
37*b9bf55e5SMatthew G. Knepley     lex[ 0] =   0; lex[ 2] =   1; lex[ 8] =   2; lex[ 6] =   3;
38*b9bf55e5SMatthew G. Knepley     lex[18] =   4; lex[20] =   5; lex[26] =   6; lex[24] =   7;
39*b9bf55e5SMatthew G. Knepley     /* Edges */
40*b9bf55e5SMatthew G. Knepley     lex[ 1] =   8; lex[ 3] =   9; lex[ 9] =  10; lex[ 5] =  11;
41*b9bf55e5SMatthew G. Knepley     lex[11] =  12; lex[ 7] =  13; lex[17] =  14; lex[15] =  15;
42*b9bf55e5SMatthew G. Knepley     lex[19] =  16; lex[21] =  17; lex[23] =  18; lex[25] =  19;
43*b9bf55e5SMatthew G. Knepley     /* Faces */
44*b9bf55e5SMatthew G. Knepley     lex[ 4] = -20; lex[10] = -21; lex[12] = -22; lex[14] = -23;
45*b9bf55e5SMatthew G. Knepley     lex[16] = -24; lex[22] = -25;
46*b9bf55e5SMatthew G. Knepley     /* Cell */
47*b9bf55e5SMatthew G. Knepley     lex[13] = -26;
48*b9bf55e5SMatthew G. Knepley   }
49*b9bf55e5SMatthew G. Knepley   return lex;
50*b9bf55e5SMatthew G. Knepley }
51*b9bf55e5SMatthew 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),
128*b9bf55e5SMatthew 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),
151*b9bf55e5SMatthew 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]))) \
2160598e1a2SLisandro Dalcin       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid Gmsh element type %d", _ct_); \
2170598e1a2SLisandro Dalcin     if (GmshCellMap[_ct_].cellType != _ct_) \
2180598e1a2SLisandro Dalcin       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported Gmsh element type %d", _ct_); \
219066ea43fSLisandro Dalcin     if (GmshCellMap[_ct_].polytope == -1) \
2200598e1a2SLisandro Dalcin       SETERRQ1(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   PetscErrorCode ierr;
24311c56cb0SLisandro Dalcin 
24411c56cb0SLisandro Dalcin   PetscFunctionBegin;
245698a79b9SLisandro Dalcin   if (gmsh->wlen < size) {
246698a79b9SLisandro Dalcin     ierr = PetscFree(gmsh->wbuf);CHKERRQ(ierr);
247698a79b9SLisandro Dalcin     ierr = PetscMalloc(size, &gmsh->wbuf);CHKERRQ(ierr);
248698a79b9SLisandro Dalcin     gmsh->wlen = size;
249de78e4feSLisandro Dalcin   }
250698a79b9SLisandro Dalcin   *(void**)buf = size ? gmsh->wbuf : NULL;
251de78e4feSLisandro Dalcin   PetscFunctionReturn(0);
252de78e4feSLisandro Dalcin }
253de78e4feSLisandro Dalcin 
254698a79b9SLisandro Dalcin static PetscErrorCode GmshBufferSizeGet(GmshFile *gmsh, size_t count, void *buf)
255698a79b9SLisandro Dalcin {
256698a79b9SLisandro Dalcin   size_t         dataSize = (size_t)gmsh->dataSize;
257698a79b9SLisandro Dalcin   size_t         size = count * dataSize;
258698a79b9SLisandro Dalcin   PetscErrorCode ierr;
259698a79b9SLisandro Dalcin 
260698a79b9SLisandro Dalcin   PetscFunctionBegin;
261698a79b9SLisandro Dalcin   if (gmsh->slen < size) {
262698a79b9SLisandro Dalcin     ierr = PetscFree(gmsh->sbuf);CHKERRQ(ierr);
263698a79b9SLisandro Dalcin     ierr = PetscMalloc(size, &gmsh->sbuf);CHKERRQ(ierr);
264698a79b9SLisandro Dalcin     gmsh->slen = size;
265698a79b9SLisandro Dalcin   }
266698a79b9SLisandro Dalcin   *(void**)buf = size ? gmsh->sbuf : NULL;
267698a79b9SLisandro Dalcin   PetscFunctionReturn(0);
268698a79b9SLisandro Dalcin }
269698a79b9SLisandro Dalcin 
270698a79b9SLisandro Dalcin static PetscErrorCode GmshRead(GmshFile *gmsh, void *buf, PetscInt count, PetscDataType dtype)
271de78e4feSLisandro Dalcin {
272de78e4feSLisandro Dalcin   PetscErrorCode ierr;
273de78e4feSLisandro Dalcin   PetscFunctionBegin;
274698a79b9SLisandro Dalcin   ierr = PetscViewerRead(gmsh->viewer, buf, count, NULL, dtype);CHKERRQ(ierr);
275698a79b9SLisandro Dalcin   if (gmsh->byteSwap) {ierr = PetscByteSwap(buf, dtype, count);CHKERRQ(ierr);}
276698a79b9SLisandro Dalcin   PetscFunctionReturn(0);
277698a79b9SLisandro Dalcin }
278698a79b9SLisandro Dalcin 
279698a79b9SLisandro Dalcin static PetscErrorCode GmshReadString(GmshFile *gmsh, char *buf, PetscInt count)
280698a79b9SLisandro Dalcin {
281698a79b9SLisandro Dalcin   PetscErrorCode ierr;
282698a79b9SLisandro Dalcin   PetscFunctionBegin;
283698a79b9SLisandro Dalcin   ierr = PetscViewerRead(gmsh->viewer, buf, count, NULL, PETSC_STRING);CHKERRQ(ierr);
284698a79b9SLisandro Dalcin   PetscFunctionReturn(0);
285698a79b9SLisandro Dalcin }
286698a79b9SLisandro Dalcin 
287d6689ca9SLisandro Dalcin static PetscErrorCode GmshMatch(PETSC_UNUSED GmshFile *gmsh, const char Section[], char line[PETSC_MAX_PATH_LEN], PetscBool *match)
288d6689ca9SLisandro Dalcin {
289d6689ca9SLisandro Dalcin   PetscErrorCode ierr;
290d6689ca9SLisandro Dalcin   PetscFunctionBegin;
291d6689ca9SLisandro Dalcin   ierr = PetscStrcmp(line, Section, match);CHKERRQ(ierr);
292d6689ca9SLisandro Dalcin   PetscFunctionReturn(0);
293d6689ca9SLisandro Dalcin }
294d6689ca9SLisandro Dalcin 
295d6689ca9SLisandro Dalcin static PetscErrorCode GmshExpect(GmshFile *gmsh, const char Section[], char line[PETSC_MAX_PATH_LEN])
296d6689ca9SLisandro Dalcin {
297d6689ca9SLisandro Dalcin   PetscBool      match;
298d6689ca9SLisandro Dalcin   PetscErrorCode ierr;
299d6689ca9SLisandro Dalcin 
300d6689ca9SLisandro Dalcin   PetscFunctionBegin;
301d6689ca9SLisandro Dalcin   ierr = GmshMatch(gmsh, Section, line, &match);CHKERRQ(ierr);
3020598e1a2SLisandro Dalcin   if (!match) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file, expecting %s",Section);
303d6689ca9SLisandro Dalcin   PetscFunctionReturn(0);
304d6689ca9SLisandro Dalcin }
305d6689ca9SLisandro Dalcin 
306d6689ca9SLisandro Dalcin static PetscErrorCode GmshReadSection(GmshFile *gmsh, char line[PETSC_MAX_PATH_LEN])
307d6689ca9SLisandro Dalcin {
308d6689ca9SLisandro Dalcin   PetscBool      match;
309d6689ca9SLisandro Dalcin   PetscErrorCode ierr;
310d6689ca9SLisandro Dalcin 
311d6689ca9SLisandro Dalcin   PetscFunctionBegin;
312d6689ca9SLisandro Dalcin   while (PETSC_TRUE) {
313d6689ca9SLisandro Dalcin     ierr = GmshReadString(gmsh, line, 1);CHKERRQ(ierr);
314d6689ca9SLisandro Dalcin     ierr = GmshMatch(gmsh, "$Comments", line, &match);CHKERRQ(ierr);
315d6689ca9SLisandro Dalcin     if (!match) break;
316d6689ca9SLisandro Dalcin     while (PETSC_TRUE) {
317d6689ca9SLisandro Dalcin       ierr = GmshReadString(gmsh, line, 1);CHKERRQ(ierr);
318d6689ca9SLisandro Dalcin       ierr = GmshMatch(gmsh, "$EndComments", line, &match);CHKERRQ(ierr);
319d6689ca9SLisandro Dalcin       if (match) break;
320d6689ca9SLisandro Dalcin     }
321d6689ca9SLisandro Dalcin   }
322d6689ca9SLisandro Dalcin   PetscFunctionReturn(0);
323d6689ca9SLisandro Dalcin }
324d6689ca9SLisandro Dalcin 
325d6689ca9SLisandro Dalcin static PetscErrorCode GmshReadEndSection(GmshFile *gmsh, const char EndSection[], char line[PETSC_MAX_PATH_LEN])
326d6689ca9SLisandro Dalcin {
327d6689ca9SLisandro Dalcin   PetscErrorCode ierr;
328d6689ca9SLisandro Dalcin   PetscFunctionBegin;
329d6689ca9SLisandro Dalcin   ierr = GmshReadString(gmsh, line, 1);CHKERRQ(ierr);
330d6689ca9SLisandro Dalcin   ierr = GmshExpect(gmsh, EndSection, line);CHKERRQ(ierr);
331d6689ca9SLisandro Dalcin   PetscFunctionReturn(0);
332d6689ca9SLisandro Dalcin }
333d6689ca9SLisandro Dalcin 
334698a79b9SLisandro Dalcin static PetscErrorCode GmshReadSize(GmshFile *gmsh, PetscInt *buf, PetscInt count)
335698a79b9SLisandro Dalcin {
336698a79b9SLisandro Dalcin   PetscInt       i;
337698a79b9SLisandro Dalcin   size_t         dataSize = (size_t)gmsh->dataSize;
338698a79b9SLisandro Dalcin   PetscErrorCode ierr;
339698a79b9SLisandro Dalcin 
340698a79b9SLisandro Dalcin   PetscFunctionBegin;
341698a79b9SLisandro Dalcin   if (dataSize == sizeof(PetscInt)) {
342698a79b9SLisandro Dalcin     ierr = GmshRead(gmsh, buf, count, PETSC_INT);CHKERRQ(ierr);
343698a79b9SLisandro Dalcin   } else  if (dataSize == sizeof(int)) {
344698a79b9SLisandro Dalcin     int *ibuf = NULL;
34589d5b078SSatish Balay     ierr = GmshBufferSizeGet(gmsh, count, &ibuf);CHKERRQ(ierr);
346698a79b9SLisandro Dalcin     ierr = GmshRead(gmsh, ibuf, count, PETSC_ENUM);CHKERRQ(ierr);
347698a79b9SLisandro Dalcin     for (i = 0; i < count; ++i) buf[i] = (PetscInt)ibuf[i];
348698a79b9SLisandro Dalcin   } else  if (dataSize == sizeof(long)) {
349698a79b9SLisandro Dalcin     long *ibuf = NULL;
35089d5b078SSatish Balay     ierr = GmshBufferSizeGet(gmsh, count, &ibuf);CHKERRQ(ierr);
351698a79b9SLisandro Dalcin     ierr = GmshRead(gmsh, ibuf, count, PETSC_LONG);CHKERRQ(ierr);
352698a79b9SLisandro Dalcin     for (i = 0; i < count; ++i) buf[i] = (PetscInt)ibuf[i];
353698a79b9SLisandro Dalcin   } else if (dataSize == sizeof(PetscInt64)) {
354698a79b9SLisandro Dalcin     PetscInt64 *ibuf = NULL;
35589d5b078SSatish Balay     ierr = GmshBufferSizeGet(gmsh, count, &ibuf);CHKERRQ(ierr);
356698a79b9SLisandro Dalcin     ierr = GmshRead(gmsh, ibuf, count, PETSC_INT64);CHKERRQ(ierr);
357698a79b9SLisandro Dalcin     for (i = 0; i < count; ++i) buf[i] = (PetscInt)ibuf[i];
358698a79b9SLisandro Dalcin   }
359698a79b9SLisandro Dalcin   PetscFunctionReturn(0);
360698a79b9SLisandro Dalcin }
361698a79b9SLisandro Dalcin 
362698a79b9SLisandro Dalcin static PetscErrorCode GmshReadInt(GmshFile *gmsh, int *buf, PetscInt count)
363698a79b9SLisandro Dalcin {
364698a79b9SLisandro Dalcin   PetscErrorCode ierr;
365698a79b9SLisandro Dalcin   PetscFunctionBegin;
366698a79b9SLisandro Dalcin   ierr = GmshRead(gmsh, buf, count, PETSC_ENUM);CHKERRQ(ierr);
367698a79b9SLisandro Dalcin   PetscFunctionReturn(0);
368698a79b9SLisandro Dalcin }
369698a79b9SLisandro Dalcin 
370698a79b9SLisandro Dalcin static PetscErrorCode GmshReadDouble(GmshFile *gmsh, double *buf, PetscInt count)
371698a79b9SLisandro Dalcin {
372698a79b9SLisandro Dalcin   PetscErrorCode ierr;
373698a79b9SLisandro Dalcin   PetscFunctionBegin;
374698a79b9SLisandro Dalcin   ierr = GmshRead(gmsh, buf, count, PETSC_DOUBLE);CHKERRQ(ierr);
375de78e4feSLisandro Dalcin   PetscFunctionReturn(0);
376de78e4feSLisandro Dalcin }
377de78e4feSLisandro Dalcin 
378de78e4feSLisandro Dalcin typedef struct {
3790598e1a2SLisandro Dalcin   PetscInt id;       /* Entity ID */
3800598e1a2SLisandro Dalcin   PetscInt dim;      /* Dimension */
381de78e4feSLisandro Dalcin   double   bbox[6];  /* Bounding box */
382de78e4feSLisandro Dalcin   PetscInt numTags;  /* Size of tag array */
383de78e4feSLisandro Dalcin   int      tags[4];  /* Tag array */
384de78e4feSLisandro Dalcin } GmshEntity;
385de78e4feSLisandro Dalcin 
386de78e4feSLisandro Dalcin typedef struct {
387730356f6SLisandro Dalcin   GmshEntity *entity[4];
388730356f6SLisandro Dalcin   PetscHMapI  entityMap[4];
389730356f6SLisandro Dalcin } GmshEntities;
390730356f6SLisandro Dalcin 
391698a79b9SLisandro Dalcin static PetscErrorCode GmshEntitiesCreate(PetscInt count[4], GmshEntities **entities)
392730356f6SLisandro Dalcin {
393730356f6SLisandro Dalcin   PetscInt       dim;
394730356f6SLisandro Dalcin   PetscErrorCode ierr;
395730356f6SLisandro Dalcin 
396730356f6SLisandro Dalcin   PetscFunctionBegin;
397730356f6SLisandro Dalcin   ierr = PetscNew(entities);CHKERRQ(ierr);
398730356f6SLisandro Dalcin   for (dim = 0; dim < 4; ++dim) {
399730356f6SLisandro Dalcin     ierr = PetscCalloc1(count[dim], &(*entities)->entity[dim]);CHKERRQ(ierr);
400730356f6SLisandro Dalcin     ierr = PetscHMapICreate(&(*entities)->entityMap[dim]);CHKERRQ(ierr);
401730356f6SLisandro Dalcin   }
402730356f6SLisandro Dalcin   PetscFunctionReturn(0);
403730356f6SLisandro Dalcin }
404730356f6SLisandro Dalcin 
4050598e1a2SLisandro Dalcin static PetscErrorCode GmshEntitiesDestroy(GmshEntities **entities)
4060598e1a2SLisandro Dalcin {
4070598e1a2SLisandro Dalcin   PetscInt       dim;
4080598e1a2SLisandro Dalcin   PetscErrorCode ierr;
4090598e1a2SLisandro Dalcin 
4100598e1a2SLisandro Dalcin   PetscFunctionBegin;
4110598e1a2SLisandro Dalcin   if (!*entities) PetscFunctionReturn(0);
4120598e1a2SLisandro Dalcin   for (dim = 0; dim < 4; ++dim) {
4130598e1a2SLisandro Dalcin     ierr = PetscFree((*entities)->entity[dim]);CHKERRQ(ierr);
4140598e1a2SLisandro Dalcin     ierr = PetscHMapIDestroy(&(*entities)->entityMap[dim]);CHKERRQ(ierr);
4150598e1a2SLisandro Dalcin   }
4160598e1a2SLisandro Dalcin   ierr = PetscFree((*entities));CHKERRQ(ierr);
4170598e1a2SLisandro Dalcin   PetscFunctionReturn(0);
4180598e1a2SLisandro Dalcin }
4190598e1a2SLisandro Dalcin 
420730356f6SLisandro Dalcin static PetscErrorCode GmshEntitiesAdd(GmshEntities *entities, PetscInt index, PetscInt dim, PetscInt eid, GmshEntity** entity)
421730356f6SLisandro Dalcin {
422730356f6SLisandro Dalcin   PetscErrorCode ierr;
4230598e1a2SLisandro Dalcin 
424730356f6SLisandro Dalcin   PetscFunctionBegin;
425730356f6SLisandro Dalcin   ierr = PetscHMapISet(entities->entityMap[dim], eid, index);CHKERRQ(ierr);
426730356f6SLisandro Dalcin   entities->entity[dim][index].dim = dim;
427730356f6SLisandro Dalcin   entities->entity[dim][index].id  = eid;
428730356f6SLisandro Dalcin   if (entity) *entity = &entities->entity[dim][index];
429730356f6SLisandro Dalcin   PetscFunctionReturn(0);
430730356f6SLisandro Dalcin }
431730356f6SLisandro Dalcin 
432730356f6SLisandro Dalcin static PetscErrorCode GmshEntitiesGet(GmshEntities *entities, PetscInt dim, PetscInt eid, GmshEntity** entity)
433730356f6SLisandro Dalcin {
434730356f6SLisandro Dalcin   PetscInt       index;
435730356f6SLisandro Dalcin   PetscErrorCode ierr;
436730356f6SLisandro Dalcin 
437730356f6SLisandro Dalcin   PetscFunctionBegin;
438730356f6SLisandro Dalcin   ierr = PetscHMapIGet(entities->entityMap[dim], eid, &index);CHKERRQ(ierr);
439730356f6SLisandro Dalcin   *entity = &entities->entity[dim][index];
440730356f6SLisandro Dalcin   PetscFunctionReturn(0);
441730356f6SLisandro Dalcin }
442730356f6SLisandro Dalcin 
4430598e1a2SLisandro Dalcin typedef struct {
4440598e1a2SLisandro Dalcin   PetscInt *id;   /* Node IDs */
4450598e1a2SLisandro Dalcin   double   *xyz;  /* Coordinates */
4460598e1a2SLisandro Dalcin } GmshNodes;
4470598e1a2SLisandro Dalcin 
4480598e1a2SLisandro Dalcin static PetscErrorCode GmshNodesCreate(PetscInt count, GmshNodes **nodes)
449730356f6SLisandro Dalcin {
450730356f6SLisandro Dalcin   PetscErrorCode ierr;
451730356f6SLisandro Dalcin 
452730356f6SLisandro Dalcin   PetscFunctionBegin;
4530598e1a2SLisandro Dalcin   ierr = PetscNew(nodes);CHKERRQ(ierr);
4540598e1a2SLisandro Dalcin   ierr = PetscMalloc1(count*1, &(*nodes)->id);CHKERRQ(ierr);
4550598e1a2SLisandro Dalcin   ierr = PetscMalloc1(count*3, &(*nodes)->xyz);CHKERRQ(ierr);
4560598e1a2SLisandro Dalcin   PetscFunctionReturn(0);
457730356f6SLisandro Dalcin }
4580598e1a2SLisandro Dalcin 
4590598e1a2SLisandro Dalcin static PetscErrorCode GmshNodesDestroy(GmshNodes **nodes)
4600598e1a2SLisandro Dalcin {
4610598e1a2SLisandro Dalcin   PetscErrorCode ierr;
4620598e1a2SLisandro Dalcin   PetscFunctionBegin;
4630598e1a2SLisandro Dalcin   if (!*nodes) PetscFunctionReturn(0);
4640598e1a2SLisandro Dalcin   ierr = PetscFree((*nodes)->id);CHKERRQ(ierr);
4650598e1a2SLisandro Dalcin   ierr = PetscFree((*nodes)->xyz);CHKERRQ(ierr);
4660598e1a2SLisandro Dalcin   ierr = PetscFree((*nodes));CHKERRQ(ierr);
467730356f6SLisandro Dalcin   PetscFunctionReturn(0);
468730356f6SLisandro Dalcin }
469730356f6SLisandro Dalcin 
470730356f6SLisandro Dalcin typedef struct {
4710598e1a2SLisandro Dalcin   PetscInt id;       /* Element ID */
4720598e1a2SLisandro Dalcin   PetscInt dim;      /* Dimension */
473de78e4feSLisandro Dalcin   PetscInt cellType; /* Cell type */
4740598e1a2SLisandro Dalcin   PetscInt numVerts; /* Size of vertex array */
475de78e4feSLisandro Dalcin   PetscInt numNodes; /* Size of node array */
4760598e1a2SLisandro Dalcin   PetscInt *nodes;   /* Vertex/Node array */
477de78e4feSLisandro Dalcin   PetscInt numTags;  /* Size of tag array */
478de78e4feSLisandro Dalcin   int      tags[4];  /* Tag array */
479de78e4feSLisandro Dalcin } GmshElement;
480de78e4feSLisandro Dalcin 
4810598e1a2SLisandro Dalcin static PetscErrorCode GmshElementsCreate(PetscInt count, GmshElement **elements)
4820598e1a2SLisandro Dalcin {
4830598e1a2SLisandro Dalcin   PetscErrorCode ierr;
4840598e1a2SLisandro Dalcin 
4850598e1a2SLisandro Dalcin   PetscFunctionBegin;
4860598e1a2SLisandro Dalcin   ierr = PetscCalloc1(count, elements);CHKERRQ(ierr);
4870598e1a2SLisandro Dalcin   PetscFunctionReturn(0);
4880598e1a2SLisandro Dalcin }
4890598e1a2SLisandro Dalcin 
4900598e1a2SLisandro Dalcin static PetscErrorCode GmshElementsDestroy(GmshElement **elements)
4910598e1a2SLisandro Dalcin {
4920598e1a2SLisandro Dalcin   PetscErrorCode ierr;
4930598e1a2SLisandro Dalcin 
4940598e1a2SLisandro Dalcin   PetscFunctionBegin;
4950598e1a2SLisandro Dalcin   if (!*elements) PetscFunctionReturn(0);
4960598e1a2SLisandro Dalcin   ierr = PetscFree(*elements);CHKERRQ(ierr);
4970598e1a2SLisandro Dalcin   PetscFunctionReturn(0);
4980598e1a2SLisandro Dalcin }
4990598e1a2SLisandro Dalcin 
5000598e1a2SLisandro Dalcin typedef struct {
5010598e1a2SLisandro Dalcin   PetscInt       dim;
502066ea43fSLisandro Dalcin   PetscInt       order;
5030598e1a2SLisandro Dalcin   GmshEntities  *entities;
5040598e1a2SLisandro Dalcin   PetscInt       numNodes;
5050598e1a2SLisandro Dalcin   GmshNodes     *nodelist;
5060598e1a2SLisandro Dalcin   PetscInt       numElems;
5070598e1a2SLisandro Dalcin   GmshElement   *elements;
5080598e1a2SLisandro Dalcin   PetscInt       numVerts;
5090598e1a2SLisandro Dalcin   PetscInt       numCells;
5100598e1a2SLisandro Dalcin   PetscInt      *periodMap;
5110598e1a2SLisandro Dalcin   PetscInt      *vertexMap;
5120598e1a2SLisandro Dalcin   PetscSegBuffer segbuf;
513a45dabc8SMatthew G. Knepley   PetscInt       numRegions;
514a45dabc8SMatthew G. Knepley   PetscInt      *regionTags;
515a45dabc8SMatthew G. Knepley   char         **regionNames;
5160598e1a2SLisandro Dalcin } GmshMesh;
5170598e1a2SLisandro Dalcin 
5180598e1a2SLisandro Dalcin static PetscErrorCode GmshMeshCreate(GmshMesh **mesh)
5190598e1a2SLisandro Dalcin {
5200598e1a2SLisandro Dalcin   PetscErrorCode ierr;
5210598e1a2SLisandro Dalcin 
5220598e1a2SLisandro Dalcin   PetscFunctionBegin;
5230598e1a2SLisandro Dalcin   ierr = PetscNew(mesh);CHKERRQ(ierr);
5240598e1a2SLisandro Dalcin   ierr = PetscSegBufferCreate(sizeof(PetscInt), 0, &(*mesh)->segbuf);CHKERRQ(ierr);
5250598e1a2SLisandro Dalcin   PetscFunctionReturn(0);
5260598e1a2SLisandro Dalcin }
5270598e1a2SLisandro Dalcin 
5280598e1a2SLisandro Dalcin static PetscErrorCode GmshMeshDestroy(GmshMesh **mesh)
5290598e1a2SLisandro Dalcin {
530a45dabc8SMatthew G. Knepley   PetscInt       r;
5310598e1a2SLisandro Dalcin   PetscErrorCode ierr;
5320598e1a2SLisandro Dalcin 
5330598e1a2SLisandro Dalcin   PetscFunctionBegin;
5340598e1a2SLisandro Dalcin   if (!*mesh) PetscFunctionReturn(0);
5350598e1a2SLisandro Dalcin   ierr = GmshEntitiesDestroy(&(*mesh)->entities);CHKERRQ(ierr);
5360598e1a2SLisandro Dalcin   ierr = GmshNodesDestroy(&(*mesh)->nodelist);CHKERRQ(ierr);
5370598e1a2SLisandro Dalcin   ierr = GmshElementsDestroy(&(*mesh)->elements);CHKERRQ(ierr);
5380598e1a2SLisandro Dalcin   ierr = PetscFree((*mesh)->periodMap);CHKERRQ(ierr);
5390598e1a2SLisandro Dalcin   ierr = PetscFree((*mesh)->vertexMap);CHKERRQ(ierr);
5400598e1a2SLisandro Dalcin   ierr = PetscSegBufferDestroy(&(*mesh)->segbuf);CHKERRQ(ierr);
541a45dabc8SMatthew G. Knepley   for (r = 0; r < (*mesh)->numRegions; ++r) {ierr = PetscFree((*mesh)->regionNames[r]);CHKERRQ(ierr);}
542a45dabc8SMatthew G. Knepley   ierr = PetscFree2((*mesh)->regionTags, (*mesh)->regionNames);CHKERRQ(ierr);
5430598e1a2SLisandro Dalcin   ierr = PetscFree((*mesh));CHKERRQ(ierr);
5440598e1a2SLisandro Dalcin   PetscFunctionReturn(0);
5450598e1a2SLisandro Dalcin }
5460598e1a2SLisandro Dalcin 
5470598e1a2SLisandro Dalcin static PetscErrorCode GmshReadNodes_v22(GmshFile *gmsh, GmshMesh *mesh)
548de78e4feSLisandro Dalcin {
549698a79b9SLisandro Dalcin   PetscViewer    viewer = gmsh->viewer;
550698a79b9SLisandro Dalcin   PetscBool      byteSwap = gmsh->byteSwap;
551de78e4feSLisandro Dalcin   char           line[PETSC_MAX_PATH_LEN];
5520598e1a2SLisandro Dalcin   int            n, num, nid, snum;
5530598e1a2SLisandro Dalcin   GmshNodes      *nodes;
554de78e4feSLisandro Dalcin   PetscErrorCode ierr;
555de78e4feSLisandro Dalcin 
556de78e4feSLisandro Dalcin   PetscFunctionBegin;
557de78e4feSLisandro Dalcin   ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);
558698a79b9SLisandro Dalcin   snum = sscanf(line, "%d", &num);
5590598e1a2SLisandro Dalcin   if (snum != 1) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
5600598e1a2SLisandro Dalcin   ierr = GmshNodesCreate(num, &nodes);CHKERRQ(ierr);
5610598e1a2SLisandro Dalcin   mesh->numNodes = num;
5620598e1a2SLisandro Dalcin   mesh->nodelist = nodes;
5630598e1a2SLisandro Dalcin   for (n = 0; n < num; ++n) {
5640598e1a2SLisandro Dalcin     double *xyz = nodes->xyz + n*3;
56511c56cb0SLisandro Dalcin     ierr = PetscViewerRead(viewer, &nid, 1, NULL, PETSC_ENUM);CHKERRQ(ierr);
56611c56cb0SLisandro Dalcin     ierr = PetscViewerRead(viewer, xyz, 3, NULL, PETSC_DOUBLE);CHKERRQ(ierr);
5670598e1a2SLisandro Dalcin     if (byteSwap) {ierr = PetscByteSwap(&nid, PETSC_ENUM, 1);CHKERRQ(ierr);}
56811c56cb0SLisandro Dalcin     if (byteSwap) {ierr = PetscByteSwap(xyz, PETSC_DOUBLE, 3);CHKERRQ(ierr);}
5690598e1a2SLisandro Dalcin     nodes->id[n] = nid;
57011c56cb0SLisandro Dalcin   }
57111c56cb0SLisandro Dalcin   PetscFunctionReturn(0);
57211c56cb0SLisandro Dalcin }
57311c56cb0SLisandro Dalcin 
574de78e4feSLisandro Dalcin /* Gmsh elements can be of any dimension/co-dimension, so we need to traverse the
575de78e4feSLisandro Dalcin    file contents multiple times to figure out the true number of cells and facets
576de78e4feSLisandro Dalcin    in the given mesh. To make this more efficient we read the file contents only
577de78e4feSLisandro Dalcin    once and store them in memory, while determining the true number of cells. */
5780598e1a2SLisandro Dalcin static PetscErrorCode GmshReadElements_v22(GmshFile* gmsh, GmshMesh *mesh)
57911c56cb0SLisandro Dalcin {
580698a79b9SLisandro Dalcin   PetscViewer    viewer = gmsh->viewer;
581698a79b9SLisandro Dalcin   PetscBool      binary = gmsh->binary;
582698a79b9SLisandro Dalcin   PetscBool      byteSwap = gmsh->byteSwap;
583de78e4feSLisandro Dalcin   char           line[PETSC_MAX_PATH_LEN];
5840598e1a2SLisandro Dalcin   int            i, c, p, num, ibuf[1+4+1000], snum;
5850598e1a2SLisandro Dalcin   int            cellType, numElem, numVerts, numNodes, numTags;
586df032b82SMatthew G. Knepley   GmshElement   *elements;
5870598e1a2SLisandro Dalcin   PetscInt      *nodeMap = gmsh->nodeMap;
588df032b82SMatthew G. Knepley   PetscErrorCode ierr;
589df032b82SMatthew G. Knepley 
590df032b82SMatthew G. Knepley   PetscFunctionBegin;
591feb237baSPierre Jolivet   ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);
592698a79b9SLisandro Dalcin   snum = sscanf(line, "%d", &num);
5930598e1a2SLisandro Dalcin   if (snum != 1) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
5940598e1a2SLisandro Dalcin   ierr = GmshElementsCreate(num, &elements);CHKERRQ(ierr);
5950598e1a2SLisandro Dalcin   mesh->numElems = num;
5960598e1a2SLisandro Dalcin   mesh->elements = elements;
597698a79b9SLisandro Dalcin   for (c = 0; c < num;) {
59811c56cb0SLisandro Dalcin     ierr = PetscViewerRead(viewer, ibuf, 3, NULL, PETSC_ENUM);CHKERRQ(ierr);
59911c56cb0SLisandro Dalcin     if (byteSwap) {ierr = PetscByteSwap(ibuf, PETSC_ENUM, 3);CHKERRQ(ierr);}
6000598e1a2SLisandro Dalcin 
6010598e1a2SLisandro Dalcin     cellType = binary ? ibuf[0] : ibuf[1];
6020598e1a2SLisandro Dalcin     numElem  = binary ? ibuf[1] : 1;
603df032b82SMatthew G. Knepley     numTags  = ibuf[2];
6040598e1a2SLisandro Dalcin 
6050598e1a2SLisandro Dalcin     ierr = GmshCellTypeCheck(cellType);CHKERRQ(ierr);
6060598e1a2SLisandro Dalcin     numVerts = GmshCellMap[cellType].numVerts;
6070598e1a2SLisandro Dalcin     numNodes = GmshCellMap[cellType].numNodes;
6080598e1a2SLisandro Dalcin 
609df032b82SMatthew G. Knepley     for (i = 0; i < numElem; ++i, ++c) {
6100598e1a2SLisandro Dalcin       GmshElement *element = elements + c;
6110598e1a2SLisandro Dalcin       const int off = binary ? 0 : 1, nint = 1 + numTags + numNodes - off;
6120598e1a2SLisandro Dalcin       const int *id = ibuf, *nodes = ibuf + 1 + numTags, *tags = ibuf + 1;
6130598e1a2SLisandro Dalcin       ierr = PetscViewerRead(viewer, ibuf+off, nint, NULL, PETSC_ENUM);CHKERRQ(ierr);
6140598e1a2SLisandro Dalcin       if (byteSwap) {ierr = PetscByteSwap(ibuf+off, PETSC_ENUM, nint);CHKERRQ(ierr);}
6150598e1a2SLisandro Dalcin       element->id  = id[0];
6160598e1a2SLisandro Dalcin       element->dim = GmshCellMap[cellType].dim;
6170598e1a2SLisandro Dalcin       element->cellType = cellType;
6180598e1a2SLisandro Dalcin       element->numVerts = numVerts;
6190598e1a2SLisandro Dalcin       element->numNodes = numNodes;
6200598e1a2SLisandro Dalcin       element->numTags  = PetscMin(numTags, 4);
6210598e1a2SLisandro Dalcin       ierr = PetscSegBufferGet(mesh->segbuf, (size_t)element->numNodes, &element->nodes);CHKERRQ(ierr);
6220598e1a2SLisandro Dalcin       for (p = 0; p < element->numNodes; p++) element->nodes[p] = nodeMap[nodes[p]];
6230598e1a2SLisandro Dalcin       for (p = 0; p < element->numTags;  p++) element->tags[p]  = tags[p];
624df032b82SMatthew G. Knepley     }
625df032b82SMatthew G. Knepley   }
626df032b82SMatthew G. Knepley   PetscFunctionReturn(0);
627df032b82SMatthew G. Knepley }
6287d282ae0SMichael Lange 
629de78e4feSLisandro Dalcin /*
630de78e4feSLisandro Dalcin $Entities
631de78e4feSLisandro Dalcin   numPoints(unsigned long) numCurves(unsigned long)
632de78e4feSLisandro Dalcin     numSurfaces(unsigned long) numVolumes(unsigned long)
633de78e4feSLisandro Dalcin   // points
634de78e4feSLisandro Dalcin   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
635de78e4feSLisandro Dalcin     boxMaxX(double) boxMaxY(double) boxMaxZ(double)
636de78e4feSLisandro Dalcin     numPhysicals(unsigned long) phyisicalTag[...](int)
637de78e4feSLisandro Dalcin   ...
638de78e4feSLisandro Dalcin   // curves
639de78e4feSLisandro Dalcin   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
640de78e4feSLisandro Dalcin      boxMaxX(double) boxMaxY(double) boxMaxZ(double)
641de78e4feSLisandro Dalcin      numPhysicals(unsigned long) physicalTag[...](int)
642de78e4feSLisandro Dalcin      numBREPVert(unsigned long) tagBREPVert[...](int)
643de78e4feSLisandro Dalcin   ...
644de78e4feSLisandro Dalcin   // surfaces
645de78e4feSLisandro Dalcin   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
646de78e4feSLisandro Dalcin     boxMaxX(double) boxMaxY(double) boxMaxZ(double)
647de78e4feSLisandro Dalcin     numPhysicals(unsigned long) physicalTag[...](int)
648de78e4feSLisandro Dalcin     numBREPCurve(unsigned long) tagBREPCurve[...](int)
649de78e4feSLisandro Dalcin   ...
650de78e4feSLisandro Dalcin   // volumes
651de78e4feSLisandro Dalcin   tag(int) boxMinX(double) boxMinY(double) boxMinZ(double)
652de78e4feSLisandro Dalcin     boxMaxX(double) boxMaxY(double) boxMaxZ(double)
653de78e4feSLisandro Dalcin     numPhysicals(unsigned long) physicalTag[...](int)
654de78e4feSLisandro Dalcin     numBREPSurfaces(unsigned long) tagBREPSurfaces[...](int)
655de78e4feSLisandro Dalcin   ...
656de78e4feSLisandro Dalcin $EndEntities
657de78e4feSLisandro Dalcin */
6580598e1a2SLisandro Dalcin static PetscErrorCode GmshReadEntities_v40(GmshFile *gmsh, GmshMesh *mesh)
659de78e4feSLisandro Dalcin {
660698a79b9SLisandro Dalcin   PetscViewer    viewer = gmsh->viewer;
661698a79b9SLisandro Dalcin   PetscBool      byteSwap = gmsh->byteSwap;
662698a79b9SLisandro Dalcin   long           index, num, lbuf[4];
663730356f6SLisandro Dalcin   int            dim, eid, numTags, *ibuf, t;
664698a79b9SLisandro Dalcin   PetscInt       count[4], i;
665a5ba3d71SLisandro Dalcin   GmshEntity     *entity = NULL;
666de78e4feSLisandro Dalcin   PetscErrorCode ierr;
667de78e4feSLisandro Dalcin 
668de78e4feSLisandro Dalcin   PetscFunctionBegin;
669698a79b9SLisandro Dalcin   ierr = PetscViewerRead(viewer, lbuf, 4, NULL, PETSC_LONG);CHKERRQ(ierr);
670698a79b9SLisandro Dalcin   if (byteSwap) {ierr = PetscByteSwap(lbuf, PETSC_LONG, 4);CHKERRQ(ierr);}
671698a79b9SLisandro Dalcin   for (i = 0; i < 4; ++i) count[i] = lbuf[i];
6720598e1a2SLisandro Dalcin   ierr = GmshEntitiesCreate(count, &mesh->entities);CHKERRQ(ierr);
673de78e4feSLisandro Dalcin   for (dim = 0; dim < 4; ++dim) {
674730356f6SLisandro Dalcin     for (index = 0; index < count[dim]; ++index) {
675730356f6SLisandro Dalcin       ierr = PetscViewerRead(viewer, &eid, 1, NULL, PETSC_ENUM);CHKERRQ(ierr);
676730356f6SLisandro Dalcin       if (byteSwap) {ierr = PetscByteSwap(&eid, PETSC_ENUM, 1);CHKERRQ(ierr);}
6770598e1a2SLisandro Dalcin       ierr = GmshEntitiesAdd(mesh->entities, (PetscInt)index, dim, eid, &entity);CHKERRQ(ierr);
678de78e4feSLisandro Dalcin       ierr = PetscViewerRead(viewer, entity->bbox, 6, NULL, PETSC_DOUBLE);CHKERRQ(ierr);
679de78e4feSLisandro Dalcin       if (byteSwap) {ierr = PetscByteSwap(entity->bbox, PETSC_DOUBLE, 6);CHKERRQ(ierr);}
680de78e4feSLisandro Dalcin       ierr = PetscViewerRead(viewer, &num, 1, NULL, PETSC_LONG);CHKERRQ(ierr);
681de78e4feSLisandro Dalcin       if (byteSwap) {ierr = PetscByteSwap(&num, PETSC_LONG, 1);CHKERRQ(ierr);}
682698a79b9SLisandro Dalcin       ierr = GmshBufferGet(gmsh, num, sizeof(int), &ibuf);CHKERRQ(ierr);
683de78e4feSLisandro Dalcin       ierr = PetscViewerRead(viewer, ibuf, num, NULL, PETSC_ENUM);CHKERRQ(ierr);
684730356f6SLisandro Dalcin       if (byteSwap) {ierr = PetscByteSwap(ibuf, PETSC_ENUM, num);CHKERRQ(ierr);}
685de78e4feSLisandro Dalcin       entity->numTags = numTags = (int) PetscMin(num, 4);
686de78e4feSLisandro Dalcin       for (t = 0; t < numTags; ++t) entity->tags[t] = ibuf[t];
687de78e4feSLisandro Dalcin       if (dim == 0) continue;
688de78e4feSLisandro Dalcin       ierr = PetscViewerRead(viewer, &num, 1, NULL, PETSC_LONG);CHKERRQ(ierr);
689de78e4feSLisandro Dalcin       if (byteSwap) {ierr = PetscByteSwap(&num, PETSC_LONG, 1);CHKERRQ(ierr);}
690698a79b9SLisandro Dalcin       ierr = GmshBufferGet(gmsh, num, sizeof(int), &ibuf);CHKERRQ(ierr);
691de78e4feSLisandro Dalcin       ierr = PetscViewerRead(viewer, ibuf, num, NULL, PETSC_ENUM);CHKERRQ(ierr);
692730356f6SLisandro Dalcin       if (byteSwap) {ierr = PetscByteSwap(ibuf, PETSC_ENUM, num);CHKERRQ(ierr);}
693de78e4feSLisandro Dalcin     }
694de78e4feSLisandro Dalcin   }
695de78e4feSLisandro Dalcin   PetscFunctionReturn(0);
696de78e4feSLisandro Dalcin }
697de78e4feSLisandro Dalcin 
698de78e4feSLisandro Dalcin /*
699de78e4feSLisandro Dalcin $Nodes
700de78e4feSLisandro Dalcin   numEntityBlocks(unsigned long) numNodes(unsigned long)
701de78e4feSLisandro Dalcin   tagEntity(int) dimEntity(int) typeNode(int) numNodes(unsigned long)
702de78e4feSLisandro Dalcin     tag(int) x(double) y(double) z(double)
703de78e4feSLisandro Dalcin     ...
704de78e4feSLisandro Dalcin   ...
705de78e4feSLisandro Dalcin $EndNodes
706de78e4feSLisandro Dalcin */
7070598e1a2SLisandro Dalcin static PetscErrorCode GmshReadNodes_v40(GmshFile *gmsh, GmshMesh *mesh)
708de78e4feSLisandro Dalcin {
709698a79b9SLisandro Dalcin   PetscViewer    viewer = gmsh->viewer;
710698a79b9SLisandro Dalcin   PetscBool      byteSwap = gmsh->byteSwap;
7110598e1a2SLisandro Dalcin   long           block, node, n, numEntityBlocks, numTotalNodes, numNodes;
712de78e4feSLisandro Dalcin   int            info[3], nid;
7130598e1a2SLisandro Dalcin   GmshNodes      *nodes;
714de78e4feSLisandro Dalcin   PetscErrorCode ierr;
715de78e4feSLisandro Dalcin 
716de78e4feSLisandro Dalcin   PetscFunctionBegin;
717de78e4feSLisandro Dalcin   ierr = PetscViewerRead(viewer, &numEntityBlocks, 1, NULL, PETSC_LONG);CHKERRQ(ierr);
718de78e4feSLisandro Dalcin   if (byteSwap) {ierr = PetscByteSwap(&numEntityBlocks, PETSC_LONG, 1);CHKERRQ(ierr);}
719de78e4feSLisandro Dalcin   ierr = PetscViewerRead(viewer, &numTotalNodes, 1, NULL, PETSC_LONG);CHKERRQ(ierr);
720de78e4feSLisandro Dalcin   if (byteSwap) {ierr = PetscByteSwap(&numTotalNodes, PETSC_LONG, 1);CHKERRQ(ierr);}
7210598e1a2SLisandro Dalcin   ierr = GmshNodesCreate(numTotalNodes, &nodes);CHKERRQ(ierr);
7220598e1a2SLisandro Dalcin   mesh->numNodes = numTotalNodes;
7230598e1a2SLisandro Dalcin   mesh->nodelist = nodes;
7240598e1a2SLisandro Dalcin   for (n = 0, block = 0; block < numEntityBlocks; ++block) {
725de78e4feSLisandro Dalcin     ierr = PetscViewerRead(viewer, info, 3, NULL, PETSC_ENUM);CHKERRQ(ierr);
726de78e4feSLisandro Dalcin     ierr = PetscViewerRead(viewer, &numNodes, 1, NULL, PETSC_LONG);CHKERRQ(ierr);
727de78e4feSLisandro Dalcin     if (byteSwap) {ierr = PetscByteSwap(&numNodes, PETSC_LONG, 1);CHKERRQ(ierr);}
728698a79b9SLisandro Dalcin     if (gmsh->binary) {
729277f51e8SBarry Smith       size_t nbytes = sizeof(int) + 3*sizeof(double);
730277f51e8SBarry Smith       char   *cbuf = NULL; /* dummy value to prevent warning from compiler about possible unitilized value */
731698a79b9SLisandro Dalcin       ierr = GmshBufferGet(gmsh, numNodes, nbytes, &cbuf);CHKERRQ(ierr);
732de78e4feSLisandro Dalcin       ierr = PetscViewerRead(viewer, cbuf, numNodes*nbytes, NULL, PETSC_CHAR);CHKERRQ(ierr);
7330598e1a2SLisandro Dalcin       for (node = 0; node < numNodes; ++node, ++n) {
734de78e4feSLisandro Dalcin         char   *cnid = cbuf + node*nbytes, *cxyz = cnid + sizeof(int);
7350598e1a2SLisandro Dalcin         double *xyz = nodes->xyz + n*3;
73630815ce0SLisandro Dalcin         if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(cnid, PETSC_ENUM, 1);CHKERRQ(ierr);}
73730815ce0SLisandro Dalcin         if (!PetscBinaryBigEndian()) {ierr = PetscByteSwap(cxyz, PETSC_DOUBLE, 3);CHKERRQ(ierr);}
738de78e4feSLisandro Dalcin         ierr = PetscMemcpy(&nid, cnid, sizeof(int));CHKERRQ(ierr);
739de78e4feSLisandro Dalcin         ierr = PetscMemcpy(xyz, cxyz, 3*sizeof(double));CHKERRQ(ierr);
740de78e4feSLisandro Dalcin         if (byteSwap) {ierr = PetscByteSwap(&nid, PETSC_ENUM, 1);CHKERRQ(ierr);}
741de78e4feSLisandro Dalcin         if (byteSwap) {ierr = PetscByteSwap(xyz, PETSC_DOUBLE, 3);CHKERRQ(ierr);}
7420598e1a2SLisandro Dalcin         nodes->id[n] = nid;
743de78e4feSLisandro Dalcin       }
744de78e4feSLisandro Dalcin     } else {
7450598e1a2SLisandro Dalcin       for (node = 0; node < numNodes; ++node, ++n) {
7460598e1a2SLisandro Dalcin         double *xyz = nodes->xyz + n*3;
747de78e4feSLisandro Dalcin         ierr = PetscViewerRead(viewer, &nid, 1, NULL, PETSC_ENUM);CHKERRQ(ierr);
748de78e4feSLisandro Dalcin         ierr = PetscViewerRead(viewer, xyz, 3, NULL, PETSC_DOUBLE);CHKERRQ(ierr);
7490598e1a2SLisandro Dalcin         if (byteSwap) {ierr = PetscByteSwap(&nid, PETSC_ENUM, 1);CHKERRQ(ierr);}
750de78e4feSLisandro Dalcin         if (byteSwap) {ierr = PetscByteSwap(xyz, PETSC_DOUBLE, 3);CHKERRQ(ierr);}
7510598e1a2SLisandro Dalcin         nodes->id[n] = nid;
752de78e4feSLisandro Dalcin       }
753de78e4feSLisandro Dalcin     }
754de78e4feSLisandro Dalcin   }
755de78e4feSLisandro Dalcin   PetscFunctionReturn(0);
756de78e4feSLisandro Dalcin }
757de78e4feSLisandro Dalcin 
758de78e4feSLisandro Dalcin /*
759de78e4feSLisandro Dalcin $Elements
760de78e4feSLisandro Dalcin   numEntityBlocks(unsigned long) numElements(unsigned long)
761de78e4feSLisandro Dalcin   tagEntity(int) dimEntity(int) typeEle(int) numElements(unsigned long)
762de78e4feSLisandro Dalcin     tag(int) numVert[...](int)
763de78e4feSLisandro Dalcin     ...
764de78e4feSLisandro Dalcin   ...
765de78e4feSLisandro Dalcin $EndElements
766de78e4feSLisandro Dalcin */
7670598e1a2SLisandro Dalcin static PetscErrorCode GmshReadElements_v40(GmshFile *gmsh, GmshMesh *mesh)
768de78e4feSLisandro Dalcin {
769698a79b9SLisandro Dalcin   PetscViewer    viewer = gmsh->viewer;
770698a79b9SLisandro Dalcin   PetscBool      byteSwap = gmsh->byteSwap;
771de78e4feSLisandro Dalcin   long           c, block, numEntityBlocks, numTotalElements, elem, numElements;
772de78e4feSLisandro Dalcin   int            p, info[3], *ibuf = NULL;
7730598e1a2SLisandro Dalcin   int            eid, dim, cellType, numVerts, numNodes, numTags;
774a5ba3d71SLisandro Dalcin   GmshEntity     *entity = NULL;
775de78e4feSLisandro Dalcin   GmshElement    *elements;
7760598e1a2SLisandro Dalcin   PetscInt       *nodeMap = gmsh->nodeMap;
777de78e4feSLisandro Dalcin   PetscErrorCode ierr;
778de78e4feSLisandro Dalcin 
779de78e4feSLisandro Dalcin   PetscFunctionBegin;
780de78e4feSLisandro Dalcin   ierr = PetscViewerRead(viewer, &numEntityBlocks, 1, NULL, PETSC_LONG);CHKERRQ(ierr);
781de78e4feSLisandro Dalcin   if (byteSwap) {ierr = PetscByteSwap(&numEntityBlocks, PETSC_LONG, 1);CHKERRQ(ierr);}
782de78e4feSLisandro Dalcin   ierr = PetscViewerRead(viewer, &numTotalElements, 1, NULL, PETSC_LONG);CHKERRQ(ierr);
783de78e4feSLisandro Dalcin   if (byteSwap) {ierr = PetscByteSwap(&numTotalElements, PETSC_LONG, 1);CHKERRQ(ierr);}
7840598e1a2SLisandro Dalcin   ierr = GmshElementsCreate(numTotalElements, &elements);CHKERRQ(ierr);
7850598e1a2SLisandro Dalcin   mesh->numElems = numTotalElements;
7860598e1a2SLisandro Dalcin   mesh->elements = elements;
787de78e4feSLisandro Dalcin   for (c = 0, block = 0; block < numEntityBlocks; ++block) {
788de78e4feSLisandro Dalcin     ierr = PetscViewerRead(viewer, info, 3, NULL, PETSC_ENUM);CHKERRQ(ierr);
789de78e4feSLisandro Dalcin     if (byteSwap) {ierr = PetscByteSwap(info, PETSC_ENUM, 3);CHKERRQ(ierr);}
790de78e4feSLisandro Dalcin     eid = info[0]; dim = info[1]; cellType = info[2];
7910598e1a2SLisandro Dalcin     ierr = GmshEntitiesGet(mesh->entities, dim, eid, &entity);CHKERRQ(ierr);
7920598e1a2SLisandro Dalcin     ierr = GmshCellTypeCheck(cellType);CHKERRQ(ierr);
7930598e1a2SLisandro Dalcin     numVerts = GmshCellMap[cellType].numVerts;
7940598e1a2SLisandro Dalcin     numNodes = GmshCellMap[cellType].numNodes;
795730356f6SLisandro Dalcin     numTags  = entity->numTags;
796de78e4feSLisandro Dalcin     ierr = PetscViewerRead(viewer, &numElements, 1, NULL, PETSC_LONG);CHKERRQ(ierr);
797de78e4feSLisandro Dalcin     if (byteSwap) {ierr = PetscByteSwap(&numElements, PETSC_LONG, 1);CHKERRQ(ierr);}
798698a79b9SLisandro Dalcin     ierr = GmshBufferGet(gmsh, (1+numNodes)*numElements, sizeof(int), &ibuf);CHKERRQ(ierr);
799de78e4feSLisandro Dalcin     ierr = PetscViewerRead(viewer, ibuf, (1+numNodes)*numElements, NULL, PETSC_ENUM);CHKERRQ(ierr);
800de78e4feSLisandro Dalcin     if (byteSwap) {ierr = PetscByteSwap(ibuf, PETSC_ENUM, (1+numNodes)*numElements);CHKERRQ(ierr);}
801de78e4feSLisandro Dalcin     for (elem = 0; elem < numElements; ++elem, ++c) {
802de78e4feSLisandro Dalcin       GmshElement *element = elements + c;
8030598e1a2SLisandro Dalcin       const int *id = ibuf + elem*(1+numNodes), *nodes = id + 1;
8040598e1a2SLisandro Dalcin       element->id  = id[0];
805de78e4feSLisandro Dalcin       element->dim = dim;
806de78e4feSLisandro Dalcin       element->cellType = cellType;
8070598e1a2SLisandro Dalcin       element->numVerts = numVerts;
808de78e4feSLisandro Dalcin       element->numNodes = numNodes;
809de78e4feSLisandro Dalcin       element->numTags  = numTags;
8100598e1a2SLisandro Dalcin       ierr = PetscSegBufferGet(mesh->segbuf, (size_t)element->numNodes, &element->nodes);CHKERRQ(ierr);
8110598e1a2SLisandro Dalcin       for (p = 0; p < element->numNodes; p++) element->nodes[p] = nodeMap[nodes[p]];
8120598e1a2SLisandro Dalcin       for (p = 0; p < element->numTags;  p++) element->tags[p]  = entity->tags[p];
813de78e4feSLisandro Dalcin     }
814de78e4feSLisandro Dalcin   }
815698a79b9SLisandro Dalcin   PetscFunctionReturn(0);
816698a79b9SLisandro Dalcin }
817698a79b9SLisandro Dalcin 
8180598e1a2SLisandro Dalcin static PetscErrorCode GmshReadPeriodic_v40(GmshFile *gmsh, PetscInt periodicMap[])
819698a79b9SLisandro Dalcin {
820698a79b9SLisandro Dalcin   PetscViewer    viewer = gmsh->viewer;
821698a79b9SLisandro Dalcin   int            fileFormat = gmsh->fileFormat;
822698a79b9SLisandro Dalcin   PetscBool      binary = gmsh->binary;
823698a79b9SLisandro Dalcin   PetscBool      byteSwap = gmsh->byteSwap;
824698a79b9SLisandro Dalcin   int            numPeriodic, snum, i;
825698a79b9SLisandro Dalcin   char           line[PETSC_MAX_PATH_LEN];
8260598e1a2SLisandro Dalcin   PetscInt       *nodeMap = gmsh->nodeMap;
827698a79b9SLisandro Dalcin   PetscErrorCode ierr;
828698a79b9SLisandro Dalcin 
829698a79b9SLisandro Dalcin   PetscFunctionBegin;
830698a79b9SLisandro Dalcin   if (fileFormat == 22 || !binary) {
831698a79b9SLisandro Dalcin     ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);
832698a79b9SLisandro Dalcin     snum = sscanf(line, "%d", &numPeriodic);
8330598e1a2SLisandro Dalcin     if (snum != 1) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
834698a79b9SLisandro Dalcin   } else {
835698a79b9SLisandro Dalcin     ierr = PetscViewerRead(viewer, &numPeriodic, 1, NULL, PETSC_ENUM);CHKERRQ(ierr);
836698a79b9SLisandro Dalcin     if (byteSwap) {ierr = PetscByteSwap(&numPeriodic, PETSC_ENUM, 1);CHKERRQ(ierr);}
837698a79b9SLisandro Dalcin   }
838698a79b9SLisandro Dalcin   for (i = 0; i < numPeriodic; i++) {
8399dddd249SSatish Balay     int    ibuf[3], correspondingDim = -1, correspondingTag = -1, primaryTag = -1, correspondingNode, primaryNode;
840698a79b9SLisandro Dalcin     long   j, nNodes;
841698a79b9SLisandro Dalcin     double affine[16];
842698a79b9SLisandro Dalcin 
843698a79b9SLisandro Dalcin     if (fileFormat == 22 || !binary) {
844698a79b9SLisandro Dalcin       ierr = PetscViewerRead(viewer, line, 3, NULL, PETSC_STRING);CHKERRQ(ierr);
8459dddd249SSatish Balay       snum = sscanf(line, "%d %d %d", &correspondingDim, &correspondingTag, &primaryTag);
8460598e1a2SLisandro Dalcin       if (snum != 3) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
847698a79b9SLisandro Dalcin     } else {
848698a79b9SLisandro Dalcin       ierr = PetscViewerRead(viewer, ibuf, 3, NULL, PETSC_ENUM);CHKERRQ(ierr);
849698a79b9SLisandro Dalcin       if (byteSwap) {ierr = PetscByteSwap(ibuf, PETSC_ENUM, 3);CHKERRQ(ierr);}
8509dddd249SSatish Balay       correspondingDim = ibuf[0]; correspondingTag = ibuf[1]; primaryTag = ibuf[2];
851698a79b9SLisandro Dalcin     }
8529dddd249SSatish Balay     (void)correspondingDim; (void)correspondingTag; (void)primaryTag; /* unused */
853698a79b9SLisandro Dalcin 
854698a79b9SLisandro Dalcin     if (fileFormat == 22 || !binary) {
855698a79b9SLisandro Dalcin       ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);
856698a79b9SLisandro Dalcin       snum = sscanf(line, "%ld", &nNodes);
8574c500f23SPierre Jolivet       if (snum != 1) { /* discard transformation and try again */
858698a79b9SLisandro Dalcin         ierr = PetscViewerRead(viewer, line, -PETSC_MAX_PATH_LEN, NULL, PETSC_STRING);CHKERRQ(ierr);
859698a79b9SLisandro Dalcin         ierr = PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING);CHKERRQ(ierr);
860698a79b9SLisandro Dalcin         snum = sscanf(line, "%ld", &nNodes);
8610598e1a2SLisandro Dalcin         if (snum != 1) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
862698a79b9SLisandro Dalcin       }
863698a79b9SLisandro Dalcin     } else {
864698a79b9SLisandro Dalcin       ierr = PetscViewerRead(viewer, &nNodes, 1, NULL, PETSC_LONG);CHKERRQ(ierr);
865698a79b9SLisandro Dalcin       if (byteSwap) {ierr = PetscByteSwap(&nNodes, PETSC_LONG, 1);CHKERRQ(ierr);}
8664c500f23SPierre Jolivet       if (nNodes == -1) { /* discard transformation and try again */
867698a79b9SLisandro Dalcin         ierr = PetscViewerRead(viewer, affine, 16, NULL, PETSC_DOUBLE);CHKERRQ(ierr);
868698a79b9SLisandro Dalcin         ierr = PetscViewerRead(viewer, &nNodes, 1, NULL, PETSC_LONG);CHKERRQ(ierr);
869698a79b9SLisandro Dalcin         if (byteSwap) {ierr = PetscByteSwap(&nNodes, PETSC_LONG, 1);CHKERRQ(ierr);}
870698a79b9SLisandro Dalcin       }
871698a79b9SLisandro Dalcin     }
872698a79b9SLisandro Dalcin 
873698a79b9SLisandro Dalcin     for (j = 0; j < nNodes; j++) {
874698a79b9SLisandro Dalcin       if (fileFormat == 22 || !binary) {
875698a79b9SLisandro Dalcin         ierr = PetscViewerRead(viewer, line, 2, NULL, PETSC_STRING);CHKERRQ(ierr);
8769dddd249SSatish Balay         snum = sscanf(line, "%d %d", &correspondingNode, &primaryNode);
8770598e1a2SLisandro Dalcin         if (snum != 2) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
878698a79b9SLisandro Dalcin       } else {
879698a79b9SLisandro Dalcin         ierr = PetscViewerRead(viewer, ibuf, 2, NULL, PETSC_ENUM);CHKERRQ(ierr);
880698a79b9SLisandro Dalcin         if (byteSwap) {ierr = PetscByteSwap(ibuf, PETSC_ENUM, 2);CHKERRQ(ierr);}
8819dddd249SSatish Balay         correspondingNode = ibuf[0]; primaryNode = ibuf[1];
882698a79b9SLisandro Dalcin       }
8839dddd249SSatish Balay       correspondingNode  = (int) nodeMap[correspondingNode];
8849dddd249SSatish Balay       primaryNode = (int) nodeMap[primaryNode];
8859dddd249SSatish Balay       periodicMap[correspondingNode] = primaryNode;
886698a79b9SLisandro Dalcin     }
887698a79b9SLisandro Dalcin   }
888698a79b9SLisandro Dalcin   PetscFunctionReturn(0);
889698a79b9SLisandro Dalcin }
890698a79b9SLisandro Dalcin 
8910598e1a2SLisandro Dalcin /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
892698a79b9SLisandro Dalcin $Entities
893698a79b9SLisandro Dalcin   numPoints(size_t) numCurves(size_t)
894698a79b9SLisandro Dalcin     numSurfaces(size_t) numVolumes(size_t)
895698a79b9SLisandro Dalcin   pointTag(int) X(double) Y(double) Z(double)
896698a79b9SLisandro Dalcin     numPhysicalTags(size_t) physicalTag(int) ...
897698a79b9SLisandro Dalcin   ...
898698a79b9SLisandro Dalcin   curveTag(int) minX(double) minY(double) minZ(double)
899698a79b9SLisandro Dalcin     maxX(double) maxY(double) maxZ(double)
900698a79b9SLisandro Dalcin     numPhysicalTags(size_t) physicalTag(int) ...
901698a79b9SLisandro Dalcin     numBoundingPoints(size_t) pointTag(int) ...
902698a79b9SLisandro Dalcin   ...
903698a79b9SLisandro Dalcin   surfaceTag(int) minX(double) minY(double) minZ(double)
904698a79b9SLisandro Dalcin     maxX(double) maxY(double) maxZ(double)
905698a79b9SLisandro Dalcin     numPhysicalTags(size_t) physicalTag(int) ...
906698a79b9SLisandro Dalcin     numBoundingCurves(size_t) curveTag(int) ...
907698a79b9SLisandro Dalcin   ...
908698a79b9SLisandro Dalcin   volumeTag(int) minX(double) minY(double) minZ(double)
909698a79b9SLisandro Dalcin     maxX(double) maxY(double) maxZ(double)
910698a79b9SLisandro Dalcin     numPhysicalTags(size_t) physicalTag(int) ...
911698a79b9SLisandro Dalcin     numBoundngSurfaces(size_t) surfaceTag(int) ...
912698a79b9SLisandro Dalcin   ...
913698a79b9SLisandro Dalcin $EndEntities
914698a79b9SLisandro Dalcin */
9150598e1a2SLisandro Dalcin static PetscErrorCode GmshReadEntities_v41(GmshFile *gmsh, GmshMesh *mesh)
916698a79b9SLisandro Dalcin {
917698a79b9SLisandro Dalcin   PetscInt       count[4], index, numTags, i;
918698a79b9SLisandro Dalcin   int            dim, eid, *tags = NULL;
919698a79b9SLisandro Dalcin   GmshEntity     *entity = NULL;
920698a79b9SLisandro Dalcin   PetscErrorCode ierr;
921698a79b9SLisandro Dalcin 
922698a79b9SLisandro Dalcin   PetscFunctionBegin;
923698a79b9SLisandro Dalcin   ierr = GmshReadSize(gmsh, count, 4);CHKERRQ(ierr);
9240598e1a2SLisandro Dalcin   ierr = GmshEntitiesCreate(count, &mesh->entities);CHKERRQ(ierr);
925698a79b9SLisandro Dalcin   for (dim = 0; dim < 4; ++dim) {
926698a79b9SLisandro Dalcin     for (index = 0; index < count[dim]; ++index) {
927698a79b9SLisandro Dalcin       ierr = GmshReadInt(gmsh, &eid, 1);CHKERRQ(ierr);
9280598e1a2SLisandro Dalcin       ierr = GmshEntitiesAdd(mesh->entities, (PetscInt)index, dim, eid, &entity);CHKERRQ(ierr);
929698a79b9SLisandro Dalcin       ierr = GmshReadDouble(gmsh, entity->bbox, (dim == 0) ? 3 : 6);CHKERRQ(ierr);
930698a79b9SLisandro Dalcin       ierr = GmshReadSize(gmsh, &numTags, 1);CHKERRQ(ierr);
931698a79b9SLisandro Dalcin       ierr = GmshBufferGet(gmsh, numTags, sizeof(int), &tags);CHKERRQ(ierr);
932698a79b9SLisandro Dalcin       ierr = GmshReadInt(gmsh, tags, numTags);CHKERRQ(ierr);
933698a79b9SLisandro Dalcin       entity->numTags = PetscMin(numTags, 4);
934698a79b9SLisandro Dalcin       for (i = 0; i < entity->numTags; ++i) entity->tags[i] = tags[i];
935698a79b9SLisandro Dalcin       if (dim == 0) continue;
936698a79b9SLisandro Dalcin       ierr = GmshReadSize(gmsh, &numTags, 1);CHKERRQ(ierr);
937698a79b9SLisandro Dalcin       ierr = GmshBufferGet(gmsh, numTags, sizeof(int), &tags);CHKERRQ(ierr);
938698a79b9SLisandro Dalcin       ierr = GmshReadInt(gmsh, tags, numTags);CHKERRQ(ierr);
939698a79b9SLisandro Dalcin     }
940698a79b9SLisandro Dalcin   }
941698a79b9SLisandro Dalcin   PetscFunctionReturn(0);
942698a79b9SLisandro Dalcin }
943698a79b9SLisandro Dalcin 
94433a088b6SMatthew G. Knepley /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
945698a79b9SLisandro Dalcin $Nodes
946698a79b9SLisandro Dalcin   numEntityBlocks(size_t) numNodes(size_t)
947698a79b9SLisandro Dalcin     minNodeTag(size_t) maxNodeTag(size_t)
948698a79b9SLisandro Dalcin   entityDim(int) entityTag(int) parametric(int; 0 or 1) numNodesBlock(size_t)
949698a79b9SLisandro Dalcin     nodeTag(size_t)
950698a79b9SLisandro Dalcin     ...
951698a79b9SLisandro Dalcin     x(double) y(double) z(double)
952698a79b9SLisandro Dalcin        < u(double; if parametric and entityDim = 1 or entityDim = 2) >
953698a79b9SLisandro Dalcin        < v(double; if parametric and entityDim = 2) >
954698a79b9SLisandro Dalcin     ...
955698a79b9SLisandro Dalcin   ...
956698a79b9SLisandro Dalcin $EndNodes
957698a79b9SLisandro Dalcin */
9580598e1a2SLisandro Dalcin static PetscErrorCode GmshReadNodes_v41(GmshFile *gmsh, GmshMesh *mesh)
959698a79b9SLisandro Dalcin {
960698a79b9SLisandro Dalcin   int            info[3];
9610598e1a2SLisandro Dalcin   PetscInt       sizes[4], numEntityBlocks, numNodes, numNodesBlock = 0, block, node;
9620598e1a2SLisandro Dalcin   GmshNodes      *nodes;
963698a79b9SLisandro Dalcin   PetscErrorCode ierr;
964698a79b9SLisandro Dalcin 
965698a79b9SLisandro Dalcin   PetscFunctionBegin;
966698a79b9SLisandro Dalcin   ierr = GmshReadSize(gmsh, sizes, 4);CHKERRQ(ierr);
9670598e1a2SLisandro Dalcin   numEntityBlocks = sizes[0]; numNodes = sizes[1];
9680598e1a2SLisandro Dalcin   ierr = GmshNodesCreate(numNodes, &nodes);CHKERRQ(ierr);
9690598e1a2SLisandro Dalcin   mesh->numNodes = numNodes;
9700598e1a2SLisandro Dalcin   mesh->nodelist = nodes;
971698a79b9SLisandro Dalcin   for (block = 0, node = 0; block < numEntityBlocks; ++block, node += numNodesBlock) {
972698a79b9SLisandro Dalcin     ierr = GmshReadInt(gmsh, info, 3);CHKERRQ(ierr);
973698a79b9SLisandro Dalcin     if (info[2] != 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Parametric coordinates not supported");
9740598e1a2SLisandro Dalcin     ierr = GmshReadSize(gmsh, &numNodesBlock, 1);CHKERRQ(ierr);
9750598e1a2SLisandro Dalcin     ierr = GmshReadSize(gmsh, nodes->id+node, numNodesBlock);CHKERRQ(ierr);
9760598e1a2SLisandro Dalcin     ierr = GmshReadDouble(gmsh, nodes->xyz+node*3, numNodesBlock*3);CHKERRQ(ierr);
977698a79b9SLisandro Dalcin   }
9780598e1a2SLisandro Dalcin   gmsh->nodeStart = sizes[2];
9790598e1a2SLisandro Dalcin   gmsh->nodeEnd   = sizes[3]+1;
980698a79b9SLisandro Dalcin   PetscFunctionReturn(0);
981698a79b9SLisandro Dalcin }
982698a79b9SLisandro Dalcin 
98333a088b6SMatthew G. Knepley /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
984698a79b9SLisandro Dalcin $Elements
985698a79b9SLisandro Dalcin   numEntityBlocks(size_t) numElements(size_t)
986698a79b9SLisandro Dalcin     minElementTag(size_t) maxElementTag(size_t)
987698a79b9SLisandro Dalcin   entityDim(int) entityTag(int) elementType(int; see below) numElementsBlock(size_t)
988698a79b9SLisandro Dalcin     elementTag(size_t) nodeTag(size_t) ...
989698a79b9SLisandro Dalcin     ...
990698a79b9SLisandro Dalcin   ...
991698a79b9SLisandro Dalcin $EndElements
992698a79b9SLisandro Dalcin */
9930598e1a2SLisandro Dalcin static PetscErrorCode GmshReadElements_v41(GmshFile *gmsh, GmshMesh *mesh)
994698a79b9SLisandro Dalcin {
9950598e1a2SLisandro Dalcin   int            info[3], eid, dim, cellType;
9960598e1a2SLisandro Dalcin   PetscInt       sizes[4], *ibuf = NULL, numEntityBlocks, numElements, numBlockElements, numVerts, numNodes, numTags, block, elem, c, p;
997698a79b9SLisandro Dalcin   GmshEntity     *entity = NULL;
998698a79b9SLisandro Dalcin   GmshElement    *elements;
9990598e1a2SLisandro Dalcin   PetscInt       *nodeMap = gmsh->nodeMap;
1000698a79b9SLisandro Dalcin   PetscErrorCode ierr;
1001698a79b9SLisandro Dalcin 
1002698a79b9SLisandro Dalcin   PetscFunctionBegin;
1003698a79b9SLisandro Dalcin   ierr = GmshReadSize(gmsh, sizes, 4);CHKERRQ(ierr);
1004698a79b9SLisandro Dalcin   numEntityBlocks = sizes[0]; numElements = sizes[1];
10050598e1a2SLisandro Dalcin   ierr = GmshElementsCreate(numElements, &elements);CHKERRQ(ierr);
10060598e1a2SLisandro Dalcin   mesh->numElems = numElements;
10070598e1a2SLisandro Dalcin   mesh->elements = elements;
1008698a79b9SLisandro Dalcin   for (c = 0, block = 0; block < numEntityBlocks; ++block) {
1009698a79b9SLisandro Dalcin     ierr = GmshReadInt(gmsh, info, 3);CHKERRQ(ierr);
1010698a79b9SLisandro Dalcin     dim = info[0]; eid = info[1]; cellType = info[2];
10110598e1a2SLisandro Dalcin     ierr = GmshEntitiesGet(mesh->entities, dim, eid, &entity);CHKERRQ(ierr);
10120598e1a2SLisandro Dalcin     ierr = GmshCellTypeCheck(cellType);CHKERRQ(ierr);
10130598e1a2SLisandro Dalcin     numVerts = GmshCellMap[cellType].numVerts;
10140598e1a2SLisandro Dalcin     numNodes = GmshCellMap[cellType].numNodes;
1015698a79b9SLisandro Dalcin     numTags  = entity->numTags;
1016698a79b9SLisandro Dalcin     ierr = GmshReadSize(gmsh, &numBlockElements, 1);CHKERRQ(ierr);
1017698a79b9SLisandro Dalcin     ierr = GmshBufferGet(gmsh, (1+numNodes)*numBlockElements, sizeof(PetscInt), &ibuf);CHKERRQ(ierr);
1018698a79b9SLisandro Dalcin     ierr = GmshReadSize(gmsh, ibuf, (1+numNodes)*numBlockElements);CHKERRQ(ierr);
1019698a79b9SLisandro Dalcin     for (elem = 0; elem < numBlockElements; ++elem, ++c) {
1020698a79b9SLisandro Dalcin       GmshElement *element = elements + c;
10210598e1a2SLisandro Dalcin       const PetscInt *id = ibuf + elem*(1+numNodes), *nodes = id + 1;
1022698a79b9SLisandro Dalcin       element->id  = id[0];
1023698a79b9SLisandro Dalcin       element->dim = dim;
1024698a79b9SLisandro Dalcin       element->cellType = cellType;
10250598e1a2SLisandro Dalcin       element->numVerts = numVerts;
1026698a79b9SLisandro Dalcin       element->numNodes = numNodes;
1027698a79b9SLisandro Dalcin       element->numTags  = numTags;
10280598e1a2SLisandro Dalcin       ierr = PetscSegBufferGet(mesh->segbuf, (size_t)element->numNodes, &element->nodes);CHKERRQ(ierr);
10290598e1a2SLisandro Dalcin       for (p = 0; p < element->numNodes; p++) element->nodes[p] = nodeMap[nodes[p]];
10300598e1a2SLisandro Dalcin       for (p = 0; p < element->numTags;  p++) element->tags[p]  = entity->tags[p];
1031698a79b9SLisandro Dalcin     }
1032698a79b9SLisandro Dalcin   }
1033698a79b9SLisandro Dalcin   PetscFunctionReturn(0);
1034698a79b9SLisandro Dalcin }
1035698a79b9SLisandro Dalcin 
10360598e1a2SLisandro Dalcin /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
1037698a79b9SLisandro Dalcin $Periodic
1038698a79b9SLisandro Dalcin   numPeriodicLinks(size_t)
10399dddd249SSatish Balay   entityDim(int) entityTag(int) entityTagPrimary(int)
1040698a79b9SLisandro Dalcin   numAffine(size_t) value(double) ...
1041698a79b9SLisandro Dalcin   numCorrespondingNodes(size_t)
10429dddd249SSatish Balay     nodeTag(size_t) nodeTagPrimary(size_t)
1043698a79b9SLisandro Dalcin     ...
1044698a79b9SLisandro Dalcin   ...
1045698a79b9SLisandro Dalcin $EndPeriodic
1046698a79b9SLisandro Dalcin */
10470598e1a2SLisandro Dalcin static PetscErrorCode GmshReadPeriodic_v41(GmshFile *gmsh, PetscInt periodicMap[])
1048698a79b9SLisandro Dalcin {
1049698a79b9SLisandro Dalcin   int            info[3];
1050698a79b9SLisandro Dalcin   double         dbuf[16];
10510598e1a2SLisandro Dalcin   PetscInt       numPeriodicLinks, numAffine, numCorrespondingNodes, *nodeTags = NULL, link, node;
10520598e1a2SLisandro Dalcin   PetscInt       *nodeMap = gmsh->nodeMap;
1053698a79b9SLisandro Dalcin   PetscErrorCode ierr;
1054698a79b9SLisandro Dalcin 
1055698a79b9SLisandro Dalcin   PetscFunctionBegin;
1056698a79b9SLisandro Dalcin   ierr = GmshReadSize(gmsh, &numPeriodicLinks, 1);CHKERRQ(ierr);
1057698a79b9SLisandro Dalcin   for (link = 0; link < numPeriodicLinks; ++link) {
1058698a79b9SLisandro Dalcin     ierr = GmshReadInt(gmsh, info, 3);CHKERRQ(ierr);
1059698a79b9SLisandro Dalcin     ierr = GmshReadSize(gmsh, &numAffine, 1);CHKERRQ(ierr);
1060698a79b9SLisandro Dalcin     ierr = GmshReadDouble(gmsh, dbuf, numAffine);CHKERRQ(ierr);
1061698a79b9SLisandro Dalcin     ierr = GmshReadSize(gmsh, &numCorrespondingNodes, 1);CHKERRQ(ierr);
1062698a79b9SLisandro Dalcin     ierr = GmshBufferGet(gmsh, numCorrespondingNodes, sizeof(PetscInt), &nodeTags);CHKERRQ(ierr);
1063698a79b9SLisandro Dalcin     ierr = GmshReadSize(gmsh, nodeTags, numCorrespondingNodes*2);CHKERRQ(ierr);
1064698a79b9SLisandro Dalcin     for (node = 0; node < numCorrespondingNodes; ++node) {
10659dddd249SSatish Balay       PetscInt correspondingNode = nodeMap[nodeTags[node*2+0]];
10669dddd249SSatish Balay       PetscInt primaryNode = nodeMap[nodeTags[node*2+1]];
10679dddd249SSatish Balay       periodicMap[correspondingNode] = primaryNode;
1068698a79b9SLisandro Dalcin     }
1069698a79b9SLisandro Dalcin   }
1070698a79b9SLisandro Dalcin   PetscFunctionReturn(0);
1071698a79b9SLisandro Dalcin }
1072698a79b9SLisandro Dalcin 
10730598e1a2SLisandro Dalcin /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format
1074d6689ca9SLisandro Dalcin $MeshFormat // same as MSH version 2
1075d6689ca9SLisandro Dalcin   version(ASCII double; currently 4.1)
1076d6689ca9SLisandro Dalcin   file-type(ASCII int; 0 for ASCII mode, 1 for binary mode)
1077d6689ca9SLisandro Dalcin   data-size(ASCII int; sizeof(size_t))
1078d6689ca9SLisandro Dalcin   < int with value one; only in binary mode, to detect endianness >
1079d6689ca9SLisandro Dalcin $EndMeshFormat
1080d6689ca9SLisandro Dalcin */
10810598e1a2SLisandro Dalcin static PetscErrorCode GmshReadMeshFormat(GmshFile *gmsh)
1082698a79b9SLisandro Dalcin {
1083698a79b9SLisandro Dalcin   char           line[PETSC_MAX_PATH_LEN];
1084698a79b9SLisandro Dalcin   int            snum, fileType, fileFormat, dataSize, checkEndian;
1085698a79b9SLisandro Dalcin   float          version;
1086698a79b9SLisandro Dalcin   PetscErrorCode ierr;
1087698a79b9SLisandro Dalcin 
1088698a79b9SLisandro Dalcin   PetscFunctionBegin;
1089698a79b9SLisandro Dalcin   ierr = GmshReadString(gmsh, line, 3);CHKERRQ(ierr);
1090698a79b9SLisandro Dalcin   snum = sscanf(line, "%f %d %d", &version, &fileType, &dataSize);
10910598e1a2SLisandro Dalcin   if (snum != 3) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to parse Gmsh file header: %s", line);
10920598e1a2SLisandro Dalcin   if (version < 2.2) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at least 2.2", (double)version);
10930598e1a2SLisandro Dalcin   if ((int)version == 3) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f not supported", (double)version);
10940598e1a2SLisandro Dalcin   if (version > 4.1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at most 4.1", (double)version);
10950598e1a2SLisandro Dalcin   if (gmsh->binary && !fileType) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Viewer is binary but Gmsh file is ASCII");
10960598e1a2SLisandro Dalcin   if (!gmsh->binary && fileType) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Viewer is ASCII but Gmsh file is binary");
1097af7a0b9fSSatish Balay   fileFormat = (int)roundf(version*10);
10980598e1a2SLisandro Dalcin   if (fileFormat <= 40 && dataSize != sizeof(double)) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Data size %d is not valid for a Gmsh file", dataSize);
10990598e1a2SLisandro Dalcin   if (fileFormat >= 41 && dataSize != sizeof(int) && dataSize != sizeof(PetscInt64)) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Data size %d is not valid for a Gmsh file", dataSize);
1100698a79b9SLisandro Dalcin   gmsh->fileFormat = fileFormat;
1101698a79b9SLisandro Dalcin   gmsh->dataSize = dataSize;
1102698a79b9SLisandro Dalcin   gmsh->byteSwap = PETSC_FALSE;
1103698a79b9SLisandro Dalcin   if (gmsh->binary) {
1104698a79b9SLisandro Dalcin     ierr = GmshReadInt(gmsh, &checkEndian, 1);CHKERRQ(ierr);
1105698a79b9SLisandro Dalcin     if (checkEndian != 1) {
1106698a79b9SLisandro Dalcin       ierr = PetscByteSwap(&checkEndian, PETSC_ENUM, 1);CHKERRQ(ierr);
11070598e1a2SLisandro Dalcin       if (checkEndian != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to detect endianness in Gmsh file header: %s", line);
1108698a79b9SLisandro Dalcin       gmsh->byteSwap = PETSC_TRUE;
1109698a79b9SLisandro Dalcin     }
1110698a79b9SLisandro Dalcin   }
1111698a79b9SLisandro Dalcin   PetscFunctionReturn(0);
1112698a79b9SLisandro Dalcin }
1113698a79b9SLisandro Dalcin 
11141f643af3SLisandro Dalcin /*
11151f643af3SLisandro Dalcin PhysicalNames
11161f643af3SLisandro Dalcin   numPhysicalNames(ASCII int)
11171f643af3SLisandro Dalcin   dimension(ASCII int) physicalTag(ASCII int) "name"(127 characters max)
11181f643af3SLisandro Dalcin   ...
11191f643af3SLisandro Dalcin $EndPhysicalNames
11201f643af3SLisandro Dalcin */
1121a45dabc8SMatthew G. Knepley static PetscErrorCode GmshReadPhysicalNames(GmshFile *gmsh, GmshMesh *mesh)
1122698a79b9SLisandro Dalcin {
11231f643af3SLisandro Dalcin   char           line[PETSC_MAX_PATH_LEN], name[128+2], *p, *q;
1124a45dabc8SMatthew G. Knepley   int            snum, region, dim, tag;
1125698a79b9SLisandro Dalcin   PetscErrorCode ierr;
1126698a79b9SLisandro Dalcin 
1127698a79b9SLisandro Dalcin   PetscFunctionBegin;
1128698a79b9SLisandro Dalcin   ierr = GmshReadString(gmsh, line, 1);CHKERRQ(ierr);
1129a45dabc8SMatthew G. Knepley   snum = sscanf(line, "%d", &region);
1130a45dabc8SMatthew G. Knepley   mesh->numRegions = region;
11310598e1a2SLisandro Dalcin   if (snum != 1) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
1132a45dabc8SMatthew G. Knepley   ierr = PetscMalloc2(mesh->numRegions, &mesh->regionTags, mesh->numRegions, &mesh->regionNames);CHKERRQ(ierr);
1133a45dabc8SMatthew G. Knepley   for (region = 0; region < mesh->numRegions; ++region) {
11341f643af3SLisandro Dalcin     ierr = GmshReadString(gmsh, line, 2);CHKERRQ(ierr);
11351f643af3SLisandro Dalcin     snum = sscanf(line, "%d %d", &dim, &tag);
11360598e1a2SLisandro Dalcin     if (snum != 2) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
11371f643af3SLisandro Dalcin     ierr = GmshReadString(gmsh, line, -(PetscInt)sizeof(line));CHKERRQ(ierr);
11381f643af3SLisandro Dalcin     ierr = PetscStrchr(line, '"', &p);CHKERRQ(ierr);
11390598e1a2SLisandro Dalcin     if (!p) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
11401f643af3SLisandro Dalcin     ierr = PetscStrrchr(line, '"', &q);CHKERRQ(ierr);
11410598e1a2SLisandro Dalcin     if (q == p) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file");
11421f643af3SLisandro Dalcin     ierr = PetscStrncpy(name, p+1, (size_t)(q-p-1));CHKERRQ(ierr);
1143a45dabc8SMatthew G. Knepley     mesh->regionTags[region] = tag;
1144a45dabc8SMatthew G. Knepley     ierr = PetscStrallocpy(name, &mesh->regionNames[region]);CHKERRQ(ierr);
1145698a79b9SLisandro Dalcin   }
1146de78e4feSLisandro Dalcin   PetscFunctionReturn(0);
1147de78e4feSLisandro Dalcin }
1148de78e4feSLisandro Dalcin 
11490598e1a2SLisandro Dalcin static PetscErrorCode GmshReadEntities(GmshFile *gmsh, GmshMesh *mesh)
115096ca5757SLisandro Dalcin {
11510598e1a2SLisandro Dalcin   PetscErrorCode ierr;
11520598e1a2SLisandro Dalcin 
11530598e1a2SLisandro Dalcin   PetscFunctionBegin;
11540598e1a2SLisandro Dalcin   switch (gmsh->fileFormat) {
11550598e1a2SLisandro Dalcin   case 41: ierr = GmshReadEntities_v41(gmsh, mesh);CHKERRQ(ierr); break;
11560598e1a2SLisandro Dalcin   default: ierr = GmshReadEntities_v40(gmsh, mesh);CHKERRQ(ierr); break;
115796ca5757SLisandro Dalcin   }
11580598e1a2SLisandro Dalcin   PetscFunctionReturn(0);
11590598e1a2SLisandro Dalcin }
11600598e1a2SLisandro Dalcin 
11610598e1a2SLisandro Dalcin static PetscErrorCode GmshReadNodes(GmshFile *gmsh, GmshMesh *mesh)
11620598e1a2SLisandro Dalcin {
11630598e1a2SLisandro Dalcin   PetscErrorCode ierr;
11640598e1a2SLisandro Dalcin 
11650598e1a2SLisandro Dalcin   PetscFunctionBegin;
11660598e1a2SLisandro Dalcin   switch (gmsh->fileFormat) {
11670598e1a2SLisandro Dalcin   case 41: ierr = GmshReadNodes_v41(gmsh, mesh);CHKERRQ(ierr); break;
11680598e1a2SLisandro Dalcin   case 40: ierr = GmshReadNodes_v40(gmsh, mesh);CHKERRQ(ierr); break;
11690598e1a2SLisandro Dalcin   default: ierr = GmshReadNodes_v22(gmsh, mesh);CHKERRQ(ierr); break;
11700598e1a2SLisandro Dalcin   }
11710598e1a2SLisandro Dalcin 
11720598e1a2SLisandro Dalcin   { /* Gmsh v2.2/v4.0 does not provide min/max node tags */
11730598e1a2SLisandro Dalcin     if (mesh->numNodes > 0 && gmsh->nodeEnd >= gmsh->nodeStart) {
11740598e1a2SLisandro Dalcin       PetscInt  tagMin = PETSC_MAX_INT, tagMax = PETSC_MIN_INT, n;
11750598e1a2SLisandro Dalcin       GmshNodes *nodes = mesh->nodelist;
11760598e1a2SLisandro Dalcin       for (n = 0; n < mesh->numNodes; ++n) {
11770598e1a2SLisandro Dalcin         const PetscInt tag = nodes->id[n];
11780598e1a2SLisandro Dalcin         tagMin = PetscMin(tag, tagMin);
11790598e1a2SLisandro Dalcin         tagMax = PetscMax(tag, tagMax);
11800598e1a2SLisandro Dalcin       }
11810598e1a2SLisandro Dalcin       gmsh->nodeStart = tagMin;
11820598e1a2SLisandro Dalcin       gmsh->nodeEnd   = tagMax+1;
11830598e1a2SLisandro Dalcin     }
11840598e1a2SLisandro Dalcin   }
11850598e1a2SLisandro Dalcin 
11860598e1a2SLisandro Dalcin   { /* Support for sparse node tags */
11870598e1a2SLisandro Dalcin     PetscInt  n, t;
11880598e1a2SLisandro Dalcin     GmshNodes *nodes = mesh->nodelist;
11890598e1a2SLisandro Dalcin     ierr = PetscMalloc1(gmsh->nodeEnd - gmsh->nodeStart, &gmsh->nbuf);CHKERRQ(ierr);
11900598e1a2SLisandro Dalcin     for (t = 0; t < gmsh->nodeEnd - gmsh->nodeStart; ++t) gmsh->nbuf[t] = PETSC_MIN_INT;
11910598e1a2SLisandro Dalcin     gmsh->nodeMap = gmsh->nbuf - gmsh->nodeStart;
11920598e1a2SLisandro Dalcin     for (n = 0; n < mesh->numNodes; ++n) {
11930598e1a2SLisandro Dalcin       const PetscInt tag = nodes->id[n];
11940598e1a2SLisandro Dalcin       if (gmsh->nodeMap[tag] >= 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Repeated node tag %D", tag);
11950598e1a2SLisandro Dalcin       gmsh->nodeMap[tag] = n;
11960598e1a2SLisandro Dalcin     }
11970598e1a2SLisandro Dalcin   }
11980598e1a2SLisandro Dalcin   PetscFunctionReturn(0);
11990598e1a2SLisandro Dalcin }
12000598e1a2SLisandro Dalcin 
12010598e1a2SLisandro Dalcin static PetscErrorCode GmshReadElements(GmshFile *gmsh, GmshMesh *mesh)
12020598e1a2SLisandro Dalcin {
12030598e1a2SLisandro Dalcin   PetscErrorCode ierr;
12040598e1a2SLisandro Dalcin 
12050598e1a2SLisandro Dalcin   PetscFunctionBegin;
12060598e1a2SLisandro Dalcin   switch (gmsh->fileFormat) {
12070598e1a2SLisandro Dalcin   case 41: ierr = GmshReadElements_v41(gmsh, mesh);CHKERRQ(ierr); break;
12080598e1a2SLisandro Dalcin   case 40: ierr = GmshReadElements_v40(gmsh, mesh);CHKERRQ(ierr); break;
12090598e1a2SLisandro Dalcin   default: ierr = GmshReadElements_v22(gmsh, mesh);CHKERRQ(ierr); break;
12100598e1a2SLisandro Dalcin   }
12110598e1a2SLisandro Dalcin 
12120598e1a2SLisandro Dalcin   { /* Reorder elements by codimension and polytope type */
12130598e1a2SLisandro Dalcin     PetscInt    ne = mesh->numElems;
12140598e1a2SLisandro Dalcin     GmshElement *elements = mesh->elements;
1215066ea43fSLisandro Dalcin     PetscInt    keymap[GMSH_NUM_POLYTOPES], nk = 0;
1216066ea43fSLisandro Dalcin     PetscInt    offset[GMSH_NUM_POLYTOPES+1], e, k;
12170598e1a2SLisandro Dalcin 
1218066ea43fSLisandro Dalcin     for (k = 0; k < GMSH_NUM_POLYTOPES; ++k) keymap[k] = PETSC_MIN_INT;
12190598e1a2SLisandro Dalcin     ierr = PetscMemzero(offset,sizeof(offset));CHKERRQ(ierr);
12200598e1a2SLisandro Dalcin 
1221066ea43fSLisandro Dalcin     keymap[GMSH_TET] = nk++;
1222066ea43fSLisandro Dalcin     keymap[GMSH_HEX] = nk++;
1223066ea43fSLisandro Dalcin     keymap[GMSH_PRI] = nk++;
1224066ea43fSLisandro Dalcin     keymap[GMSH_PYR] = nk++;
1225066ea43fSLisandro Dalcin     keymap[GMSH_TRI] = nk++;
1226066ea43fSLisandro Dalcin     keymap[GMSH_QUA] = nk++;
1227066ea43fSLisandro Dalcin     keymap[GMSH_SEG] = nk++;
1228066ea43fSLisandro Dalcin     keymap[GMSH_VTX] = nk++;
12290598e1a2SLisandro Dalcin 
12300598e1a2SLisandro Dalcin     ierr = GmshElementsCreate(mesh->numElems, &mesh->elements);CHKERRQ(ierr);
12310598e1a2SLisandro Dalcin #define key(eid) keymap[GmshCellMap[elements[(eid)].cellType].polytope]
12320598e1a2SLisandro Dalcin     for (e = 0; e < ne; ++e) offset[1+key(e)]++;
12330598e1a2SLisandro Dalcin     for (k = 1; k < nk; ++k) offset[k] += offset[k-1];
12340598e1a2SLisandro Dalcin     for (e = 0; e < ne; ++e) mesh->elements[offset[key(e)]++] = elements[e];
12350598e1a2SLisandro Dalcin #undef key
12360598e1a2SLisandro Dalcin     ierr = GmshElementsDestroy(&elements);CHKERRQ(ierr);
1237066ea43fSLisandro Dalcin   }
12380598e1a2SLisandro Dalcin 
1239066ea43fSLisandro Dalcin   { /* Mesh dimension and order */
1240066ea43fSLisandro Dalcin     GmshElement *elem = mesh->numElems ? mesh->elements : NULL;
1241066ea43fSLisandro Dalcin     mesh->dim   = elem ? GmshCellMap[elem->cellType].dim   : 0;
1242066ea43fSLisandro Dalcin     mesh->order = elem ? GmshCellMap[elem->cellType].order : 0;
12430598e1a2SLisandro Dalcin   }
12440598e1a2SLisandro Dalcin 
12450598e1a2SLisandro Dalcin   {
12460598e1a2SLisandro Dalcin     PetscBT  vtx;
12470598e1a2SLisandro Dalcin     PetscInt dim = mesh->dim, e, n, v;
12480598e1a2SLisandro Dalcin 
12490598e1a2SLisandro Dalcin     ierr = PetscBTCreate(mesh->numNodes, &vtx);CHKERRQ(ierr);
12500598e1a2SLisandro Dalcin 
12510598e1a2SLisandro Dalcin     /* Compute number of cells and set of vertices */
12520598e1a2SLisandro Dalcin     mesh->numCells = 0;
12530598e1a2SLisandro Dalcin     for (e = 0; e < mesh->numElems; ++e) {
12540598e1a2SLisandro Dalcin       GmshElement *elem = mesh->elements + e;
12550598e1a2SLisandro Dalcin       if (elem->dim == dim && dim > 0) mesh->numCells++;
12560598e1a2SLisandro Dalcin       for (v = 0; v < elem->numVerts; v++) {
12570598e1a2SLisandro Dalcin         ierr = PetscBTSet(vtx, elem->nodes[v]);CHKERRQ(ierr);
12580598e1a2SLisandro Dalcin       }
12590598e1a2SLisandro Dalcin     }
12600598e1a2SLisandro Dalcin 
12610598e1a2SLisandro Dalcin     /* Compute numbering for vertices */
12620598e1a2SLisandro Dalcin     mesh->numVerts = 0;
12630598e1a2SLisandro Dalcin     ierr = PetscMalloc1(mesh->numNodes, &mesh->vertexMap);CHKERRQ(ierr);
12640598e1a2SLisandro Dalcin     for (n = 0; n < mesh->numNodes; ++n)
12650598e1a2SLisandro Dalcin       mesh->vertexMap[n] = PetscBTLookup(vtx, n) ? mesh->numVerts++ : PETSC_MIN_INT;
12660598e1a2SLisandro Dalcin 
12670598e1a2SLisandro Dalcin     ierr = PetscBTDestroy(&vtx);CHKERRQ(ierr);
12680598e1a2SLisandro Dalcin   }
12690598e1a2SLisandro Dalcin   PetscFunctionReturn(0);
12700598e1a2SLisandro Dalcin }
12710598e1a2SLisandro Dalcin 
12720598e1a2SLisandro Dalcin static PetscErrorCode GmshReadPeriodic(GmshFile *gmsh, GmshMesh *mesh)
12730598e1a2SLisandro Dalcin {
12740598e1a2SLisandro Dalcin   PetscInt       n;
12750598e1a2SLisandro Dalcin   PetscErrorCode ierr;
12760598e1a2SLisandro Dalcin 
12770598e1a2SLisandro Dalcin   PetscFunctionBegin;
12780598e1a2SLisandro Dalcin   ierr = PetscMalloc1(mesh->numNodes, &mesh->periodMap);CHKERRQ(ierr);
12790598e1a2SLisandro Dalcin   for (n = 0; n < mesh->numNodes; ++n) mesh->periodMap[n] = n;
12800598e1a2SLisandro Dalcin   switch (gmsh->fileFormat) {
12810598e1a2SLisandro Dalcin   case 41: ierr = GmshReadPeriodic_v41(gmsh, mesh->periodMap);CHKERRQ(ierr); break;
12820598e1a2SLisandro Dalcin   default: ierr = GmshReadPeriodic_v40(gmsh, mesh->periodMap);CHKERRQ(ierr); break;
12830598e1a2SLisandro Dalcin   }
12840598e1a2SLisandro Dalcin 
12859dddd249SSatish Balay   /* Find canonical primary nodes */
12860598e1a2SLisandro Dalcin   for (n = 0; n < mesh->numNodes; ++n)
12870598e1a2SLisandro Dalcin     while (mesh->periodMap[n] != mesh->periodMap[mesh->periodMap[n]])
12880598e1a2SLisandro Dalcin       mesh->periodMap[n] = mesh->periodMap[mesh->periodMap[n]];
12890598e1a2SLisandro Dalcin 
12909dddd249SSatish Balay   /* Renumber vertices (filter out correspondings) */
12910598e1a2SLisandro Dalcin   mesh->numVerts = 0;
12920598e1a2SLisandro Dalcin   for (n = 0; n < mesh->numNodes; ++n)
12930598e1a2SLisandro Dalcin     if (mesh->vertexMap[n] >= 0)   /* is vertex */
12949dddd249SSatish Balay       if (mesh->periodMap[n] == n) /* is primary */
12950598e1a2SLisandro Dalcin         mesh->vertexMap[n] = mesh->numVerts++;
12960598e1a2SLisandro Dalcin   for (n = 0; n < mesh->numNodes; ++n)
12970598e1a2SLisandro Dalcin     if (mesh->vertexMap[n] >= 0)   /* is vertex */
12989dddd249SSatish Balay       if (mesh->periodMap[n] != n) /* is corresponding  */
12990598e1a2SLisandro Dalcin         mesh->vertexMap[n] = mesh->vertexMap[mesh->periodMap[n]];
13000598e1a2SLisandro Dalcin   PetscFunctionReturn(0);
13010598e1a2SLisandro Dalcin }
13020598e1a2SLisandro Dalcin 
1303066ea43fSLisandro Dalcin #define DM_POLYTOPE_VERTEX  DM_POLYTOPE_POINT
1304066ea43fSLisandro Dalcin #define DM_POLYTOPE_PYRAMID DM_POLYTOPE_UNKNOWN
1305066ea43fSLisandro Dalcin static const DMPolytopeType DMPolytopeMap[] = {
1306066ea43fSLisandro Dalcin   /* GMSH_VTX */ DM_POLYTOPE_VERTEX,
1307066ea43fSLisandro Dalcin   /* GMSH_SEG */ DM_POLYTOPE_SEGMENT,
1308066ea43fSLisandro Dalcin   /* GMSH_TRI */ DM_POLYTOPE_TRIANGLE,
1309066ea43fSLisandro Dalcin   /* GMSH_QUA */ DM_POLYTOPE_QUADRILATERAL,
1310066ea43fSLisandro Dalcin   /* GMSH_TET */ DM_POLYTOPE_TETRAHEDRON,
1311066ea43fSLisandro Dalcin   /* GMSH_HEX */ DM_POLYTOPE_HEXAHEDRON,
1312066ea43fSLisandro Dalcin   /* GMSH_PRI */ DM_POLYTOPE_TRI_PRISM,
1313066ea43fSLisandro Dalcin   /* GMSH_PYR */ DM_POLYTOPE_PYRAMID,
1314066ea43fSLisandro Dalcin   DM_POLYTOPE_UNKNOWN
1315066ea43fSLisandro Dalcin };
13160598e1a2SLisandro Dalcin 
13170598e1a2SLisandro Dalcin PETSC_STATIC_INLINE DMPolytopeType DMPolytopeTypeFromGmsh(PetscInt cellType)
13180598e1a2SLisandro Dalcin {
1319066ea43fSLisandro Dalcin   return DMPolytopeMap[GmshCellMap[cellType].polytope];
1320066ea43fSLisandro Dalcin }
1321066ea43fSLisandro Dalcin 
1322066ea43fSLisandro Dalcin static PetscErrorCode GmshCreateFE(MPI_Comm comm, const char prefix[], PetscBool isSimplex, PetscBool continuity, PetscDTNodeType nodeType, PetscInt dim, PetscInt Nc, PetscInt k, PetscFE *fem)
1323066ea43fSLisandro Dalcin {
1324066ea43fSLisandro Dalcin   DM              K;
1325066ea43fSLisandro Dalcin   PetscSpace      P;
1326066ea43fSLisandro Dalcin   PetscDualSpace  Q;
1327066ea43fSLisandro Dalcin   PetscQuadrature q, fq;
1328066ea43fSLisandro Dalcin   PetscBool       isTensor = isSimplex ? PETSC_FALSE : PETSC_TRUE;
1329066ea43fSLisandro Dalcin   PetscBool       endpoint = PETSC_TRUE;
1330066ea43fSLisandro Dalcin   char            name[32];
1331066ea43fSLisandro Dalcin   PetscErrorCode  ierr;
1332066ea43fSLisandro Dalcin 
1333066ea43fSLisandro Dalcin   PetscFunctionBegin;
1334066ea43fSLisandro Dalcin   /* Create space */
1335066ea43fSLisandro Dalcin   ierr = PetscSpaceCreate(comm, &P);CHKERRQ(ierr);
1336066ea43fSLisandro Dalcin   ierr = PetscSpaceSetType(P, PETSCSPACEPOLYNOMIAL);CHKERRQ(ierr);
1337066ea43fSLisandro Dalcin   ierr = PetscSpacePolynomialSetTensor(P, isTensor);CHKERRQ(ierr);
1338066ea43fSLisandro Dalcin   ierr = PetscSpaceSetNumComponents(P, Nc);CHKERRQ(ierr);
1339066ea43fSLisandro Dalcin   ierr = PetscSpaceSetNumVariables(P, dim);CHKERRQ(ierr);
1340066ea43fSLisandro Dalcin   ierr = PetscSpaceSetDegree(P, k, PETSC_DETERMINE);CHKERRQ(ierr);
1341066ea43fSLisandro Dalcin   if (prefix) {
1342066ea43fSLisandro Dalcin     ierr = PetscObjectSetOptionsPrefix((PetscObject) P, prefix);CHKERRQ(ierr);
1343066ea43fSLisandro Dalcin     ierr = PetscSpaceSetFromOptions(P);CHKERRQ(ierr);
1344066ea43fSLisandro Dalcin     ierr = PetscObjectSetOptionsPrefix((PetscObject) P, NULL);CHKERRQ(ierr);
1345066ea43fSLisandro Dalcin     ierr = PetscSpaceGetDegree(P, &k, NULL);CHKERRQ(ierr);
1346066ea43fSLisandro Dalcin   }
1347066ea43fSLisandro Dalcin   ierr = PetscSpaceSetUp(P);CHKERRQ(ierr);
1348066ea43fSLisandro Dalcin   /* Create dual space */
1349066ea43fSLisandro Dalcin   ierr = PetscDualSpaceCreate(comm, &Q);CHKERRQ(ierr);
1350066ea43fSLisandro Dalcin   ierr = PetscDualSpaceSetType(Q, PETSCDUALSPACELAGRANGE);CHKERRQ(ierr);
1351066ea43fSLisandro Dalcin   ierr = PetscDualSpaceLagrangeSetTensor(Q, isTensor);CHKERRQ(ierr);
1352066ea43fSLisandro Dalcin   ierr = PetscDualSpaceLagrangeSetContinuity(Q, continuity);CHKERRQ(ierr);
1353066ea43fSLisandro Dalcin   ierr = PetscDualSpaceLagrangeSetNodeType(Q, nodeType, endpoint, 0);CHKERRQ(ierr);
1354066ea43fSLisandro Dalcin   ierr = PetscDualSpaceSetNumComponents(Q, Nc);CHKERRQ(ierr);
1355066ea43fSLisandro Dalcin   ierr = PetscDualSpaceSetOrder(Q, k);CHKERRQ(ierr);
1356066ea43fSLisandro Dalcin   ierr = PetscDualSpaceCreateReferenceCell(Q, dim, isSimplex, &K);CHKERRQ(ierr);
1357066ea43fSLisandro Dalcin   ierr = PetscDualSpaceSetDM(Q, K);CHKERRQ(ierr);
1358066ea43fSLisandro Dalcin   ierr = DMDestroy(&K);CHKERRQ(ierr);
1359066ea43fSLisandro Dalcin   if (prefix) {
1360066ea43fSLisandro Dalcin     ierr = PetscObjectSetOptionsPrefix((PetscObject) Q, prefix);CHKERRQ(ierr);
1361066ea43fSLisandro Dalcin     ierr = PetscDualSpaceSetFromOptions(Q);CHKERRQ(ierr);
1362066ea43fSLisandro Dalcin     ierr = PetscObjectSetOptionsPrefix((PetscObject) Q, NULL);CHKERRQ(ierr);
1363066ea43fSLisandro Dalcin   }
1364066ea43fSLisandro Dalcin   ierr = PetscDualSpaceSetUp(Q);CHKERRQ(ierr);
1365066ea43fSLisandro Dalcin   /* Create quadrature */
1366066ea43fSLisandro Dalcin   if (isSimplex) {
1367066ea43fSLisandro Dalcin     ierr = PetscDTStroudConicalQuadrature(dim,   1, k+1, -1, +1, &q);CHKERRQ(ierr);
1368066ea43fSLisandro Dalcin     ierr = PetscDTStroudConicalQuadrature(dim-1, 1, k+1, -1, +1, &fq);CHKERRQ(ierr);
1369066ea43fSLisandro Dalcin   } else {
1370066ea43fSLisandro Dalcin     ierr = PetscDTGaussTensorQuadrature(dim,   1, k+1, -1, +1, &q);CHKERRQ(ierr);
1371066ea43fSLisandro Dalcin     ierr = PetscDTGaussTensorQuadrature(dim-1, 1, k+1, -1, +1, &fq);CHKERRQ(ierr);
1372066ea43fSLisandro Dalcin   }
1373066ea43fSLisandro Dalcin   /* Create finite element */
1374066ea43fSLisandro Dalcin   ierr = PetscFECreate(comm, fem);CHKERRQ(ierr);
1375066ea43fSLisandro Dalcin   ierr = PetscFESetType(*fem, PETSCFEBASIC);CHKERRQ(ierr);
1376066ea43fSLisandro Dalcin   ierr = PetscFESetNumComponents(*fem, Nc);CHKERRQ(ierr);
1377066ea43fSLisandro Dalcin   ierr = PetscFESetBasisSpace(*fem, P);CHKERRQ(ierr);
1378066ea43fSLisandro Dalcin   ierr = PetscFESetDualSpace(*fem, Q);CHKERRQ(ierr);
1379066ea43fSLisandro Dalcin   ierr = PetscFESetQuadrature(*fem, q);CHKERRQ(ierr);
1380066ea43fSLisandro Dalcin   ierr = PetscFESetFaceQuadrature(*fem, fq);CHKERRQ(ierr);
1381066ea43fSLisandro Dalcin   if (prefix) {
1382066ea43fSLisandro Dalcin     ierr = PetscObjectSetOptionsPrefix((PetscObject) *fem, prefix);CHKERRQ(ierr);
1383066ea43fSLisandro Dalcin     ierr = PetscFESetFromOptions(*fem);CHKERRQ(ierr);
1384066ea43fSLisandro Dalcin     ierr = PetscObjectSetOptionsPrefix((PetscObject) *fem, NULL);CHKERRQ(ierr);
1385066ea43fSLisandro Dalcin   }
1386066ea43fSLisandro Dalcin   ierr = PetscFESetUp(*fem);CHKERRQ(ierr);
1387066ea43fSLisandro Dalcin   /* Cleanup */
1388066ea43fSLisandro Dalcin   ierr = PetscSpaceDestroy(&P);CHKERRQ(ierr);
1389066ea43fSLisandro Dalcin   ierr = PetscDualSpaceDestroy(&Q);CHKERRQ(ierr);
1390066ea43fSLisandro Dalcin   ierr = PetscQuadratureDestroy(&q);CHKERRQ(ierr);
1391066ea43fSLisandro Dalcin   ierr = PetscQuadratureDestroy(&fq);CHKERRQ(ierr);
1392066ea43fSLisandro Dalcin   /* Set finite element name */
1393066ea43fSLisandro Dalcin   ierr = PetscSNPrintf(name, sizeof(name), "%s%D", isSimplex? "P" : "Q", k);CHKERRQ(ierr);
1394066ea43fSLisandro Dalcin   ierr = PetscFESetName(*fem, name);CHKERRQ(ierr);
1395066ea43fSLisandro Dalcin   PetscFunctionReturn(0);
139696ca5757SLisandro Dalcin }
139796ca5757SLisandro Dalcin 
1398d6689ca9SLisandro Dalcin /*@C
1399d6689ca9SLisandro Dalcin   DMPlexCreateGmshFromFile - Create a DMPlex mesh from a Gmsh file
1400d6689ca9SLisandro Dalcin 
1401d6689ca9SLisandro Dalcin + comm        - The MPI communicator
1402d6689ca9SLisandro Dalcin . filename    - Name of the Gmsh file
1403d6689ca9SLisandro Dalcin - interpolate - Create faces and edges in the mesh
1404d6689ca9SLisandro Dalcin 
1405d6689ca9SLisandro Dalcin   Output Parameter:
1406d6689ca9SLisandro Dalcin . dm  - The DM object representing the mesh
1407d6689ca9SLisandro Dalcin 
1408d6689ca9SLisandro Dalcin   Level: beginner
1409d6689ca9SLisandro Dalcin 
1410d6689ca9SLisandro Dalcin .seealso: DMPlexCreateFromFile(), DMPlexCreateGmsh(), DMPlexCreate()
1411d6689ca9SLisandro Dalcin @*/
1412d6689ca9SLisandro Dalcin PetscErrorCode DMPlexCreateGmshFromFile(MPI_Comm comm, const char filename[], PetscBool interpolate, DM *dm)
1413d6689ca9SLisandro Dalcin {
1414d6689ca9SLisandro Dalcin   PetscViewer     viewer;
1415d6689ca9SLisandro Dalcin   PetscMPIInt     rank;
1416d6689ca9SLisandro Dalcin   int             fileType;
1417d6689ca9SLisandro Dalcin   PetscViewerType vtype;
1418d6689ca9SLisandro Dalcin   PetscErrorCode  ierr;
1419d6689ca9SLisandro Dalcin 
1420d6689ca9SLisandro Dalcin   PetscFunctionBegin;
1421ffc4695bSBarry Smith   ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr);
1422d6689ca9SLisandro Dalcin 
1423d6689ca9SLisandro Dalcin   /* Determine Gmsh file type (ASCII or binary) from file header */
1424dd400576SPatrick Sanan   if (rank == 0) {
14250598e1a2SLisandro Dalcin     GmshFile    gmsh[1];
1426d6689ca9SLisandro Dalcin     char        line[PETSC_MAX_PATH_LEN];
1427d6689ca9SLisandro Dalcin     int         snum;
1428d6689ca9SLisandro Dalcin     float       version;
1429d6689ca9SLisandro Dalcin 
1430580bdb30SBarry Smith     ierr = PetscArrayzero(gmsh,1);CHKERRQ(ierr);
1431d6689ca9SLisandro Dalcin     ierr = PetscViewerCreate(PETSC_COMM_SELF, &gmsh->viewer);CHKERRQ(ierr);
1432d6689ca9SLisandro Dalcin     ierr = PetscViewerSetType(gmsh->viewer, PETSCVIEWERASCII);CHKERRQ(ierr);
1433d6689ca9SLisandro Dalcin     ierr = PetscViewerFileSetMode(gmsh->viewer, FILE_MODE_READ);CHKERRQ(ierr);
1434d6689ca9SLisandro Dalcin     ierr = PetscViewerFileSetName(gmsh->viewer, filename);CHKERRQ(ierr);
1435d6689ca9SLisandro Dalcin     /* Read only the first two lines of the Gmsh file */
1436d6689ca9SLisandro Dalcin     ierr = GmshReadSection(gmsh, line);CHKERRQ(ierr);
1437d6689ca9SLisandro Dalcin     ierr = GmshExpect(gmsh, "$MeshFormat", line);CHKERRQ(ierr);
1438d6689ca9SLisandro Dalcin     ierr = GmshReadString(gmsh, line, 2);CHKERRQ(ierr);
1439d6689ca9SLisandro Dalcin     snum = sscanf(line, "%f %d", &version, &fileType);
14400598e1a2SLisandro Dalcin     if (snum != 2) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to parse Gmsh file header: %s", line);
14410598e1a2SLisandro Dalcin     if (version < 2.2) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at least 2.2", (double)version);
14420598e1a2SLisandro Dalcin     if ((int)version == 3) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f not supported", (double)version);
14430598e1a2SLisandro Dalcin     if (version > 4.1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at most 4.1", (double)version);
1444d6689ca9SLisandro Dalcin     ierr = PetscViewerDestroy(&gmsh->viewer);CHKERRQ(ierr);
1445d6689ca9SLisandro Dalcin   }
1446ffc4695bSBarry Smith   ierr = MPI_Bcast(&fileType, 1, MPI_INT, 0, comm);CHKERRMPI(ierr);
1447d6689ca9SLisandro Dalcin   vtype = (fileType == 0) ? PETSCVIEWERASCII : PETSCVIEWERBINARY;
1448d6689ca9SLisandro Dalcin 
1449d6689ca9SLisandro Dalcin   /* Create appropriate viewer and build plex */
1450d6689ca9SLisandro Dalcin   ierr = PetscViewerCreate(comm, &viewer);CHKERRQ(ierr);
1451d6689ca9SLisandro Dalcin   ierr = PetscViewerSetType(viewer, vtype);CHKERRQ(ierr);
1452d6689ca9SLisandro Dalcin   ierr = PetscViewerFileSetMode(viewer, FILE_MODE_READ);CHKERRQ(ierr);
1453d6689ca9SLisandro Dalcin   ierr = PetscViewerFileSetName(viewer, filename);CHKERRQ(ierr);
1454d6689ca9SLisandro Dalcin   ierr = DMPlexCreateGmsh(comm, viewer, interpolate, dm);CHKERRQ(ierr);
1455d6689ca9SLisandro Dalcin   ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
1456d6689ca9SLisandro Dalcin   PetscFunctionReturn(0);
1457d6689ca9SLisandro Dalcin }
1458d6689ca9SLisandro Dalcin 
1459331830f3SMatthew G. Knepley /*@
14607d282ae0SMichael Lange   DMPlexCreateGmsh - Create a DMPlex mesh from a Gmsh file viewer
1461331830f3SMatthew G. Knepley 
1462d083f849SBarry Smith   Collective
1463331830f3SMatthew G. Knepley 
1464331830f3SMatthew G. Knepley   Input Parameters:
1465331830f3SMatthew G. Knepley + comm  - The MPI communicator
1466331830f3SMatthew G. Knepley . viewer - The Viewer associated with a Gmsh file
1467331830f3SMatthew G. Knepley - interpolate - Create faces and edges in the mesh
1468331830f3SMatthew G. Knepley 
1469331830f3SMatthew G. Knepley   Output Parameter:
1470331830f3SMatthew G. Knepley . dm  - The DM object representing the mesh
1471331830f3SMatthew G. Knepley 
1472698a79b9SLisandro Dalcin   Note: http://gmsh.info/doc/texinfo/gmsh.html#MSH-file-format
1473331830f3SMatthew G. Knepley 
1474331830f3SMatthew G. Knepley   Level: beginner
1475331830f3SMatthew G. Knepley 
1476331830f3SMatthew G. Knepley .seealso: DMPLEX, DMCreate()
1477331830f3SMatthew G. Knepley @*/
1478331830f3SMatthew G. Knepley PetscErrorCode DMPlexCreateGmsh(MPI_Comm comm, PetscViewer viewer, PetscBool interpolate, DM *dm)
1479331830f3SMatthew G. Knepley {
14800598e1a2SLisandro Dalcin   GmshMesh      *mesh = NULL;
148111c56cb0SLisandro Dalcin   PetscViewer    parentviewer = NULL;
14820598e1a2SLisandro Dalcin   PetscBT        periodicVerts = NULL;
14830598e1a2SLisandro Dalcin   PetscBT        periodicCells = NULL;
1484066ea43fSLisandro Dalcin   DM             cdm;
1485331830f3SMatthew G. Knepley   PetscSection   coordSection;
1486331830f3SMatthew G. Knepley   Vec            coordinates;
1487a45dabc8SMatthew G. Knepley   DMLabel        cellSets = NULL, faceSets = NULL, vertSets = NULL, marker = NULL, *regionSets;
1488066ea43fSLisandro Dalcin   PetscInt       dim = 0, coordDim = -1, order = 0;
14890598e1a2SLisandro Dalcin   PetscInt       numNodes = 0, numElems = 0, numVerts = 0, numCells = 0;
1490066ea43fSLisandro Dalcin   PetscInt       cell, cone[8], e, n, v, d;
1491a45dabc8SMatthew G. Knepley   PetscBool      binary, usemarker = PETSC_FALSE, useregions = PETSC_FALSE;
14920598e1a2SLisandro Dalcin   PetscBool      hybrid = interpolate, periodic = PETSC_TRUE;
1493066ea43fSLisandro Dalcin   PetscBool      highOrder = PETSC_TRUE, highOrderSet, project = PETSC_FALSE;
1494066ea43fSLisandro Dalcin   PetscBool      isSimplex = PETSC_FALSE, isHybrid = PETSC_FALSE, hasTetra = PETSC_FALSE;
14950598e1a2SLisandro Dalcin   PetscMPIInt    rank;
1496331830f3SMatthew G. Knepley   PetscErrorCode ierr;
1497331830f3SMatthew G. Knepley 
1498331830f3SMatthew G. Knepley   PetscFunctionBegin;
1499ffc4695bSBarry Smith   ierr = MPI_Comm_rank(comm, &rank);CHKERRMPI(ierr);
1500ef12879bSLisandro Dalcin   ierr = PetscObjectOptionsBegin((PetscObject)viewer);CHKERRQ(ierr);
1501ef12879bSLisandro Dalcin   ierr = PetscOptionsHead(PetscOptionsObject,"DMPlex Gmsh options");CHKERRQ(ierr);
15020598e1a2SLisandro Dalcin   ierr = PetscOptionsBool("-dm_plex_gmsh_hybrid", "Generate hybrid cell bounds", "DMPlexCreateGmsh", hybrid, &hybrid, NULL);CHKERRQ(ierr);
1503ef12879bSLisandro Dalcin   ierr = PetscOptionsBool("-dm_plex_gmsh_periodic","Read Gmsh periodic section", "DMPlexCreateGmsh", periodic, &periodic, NULL);CHKERRQ(ierr);
1504066ea43fSLisandro Dalcin   ierr = PetscOptionsBool("-dm_plex_gmsh_highorder","Generate high-order coordinates", "DMPlexCreateGmsh", highOrder, &highOrder, &highOrderSet);CHKERRQ(ierr);
1505066ea43fSLisandro Dalcin   ierr = PetscOptionsBool("-dm_plex_gmsh_project", "Project high-order coordinates to a different space", "DMPlexCreateGmsh", project, &project, NULL);CHKERRQ(ierr);
1506ef12879bSLisandro Dalcin   ierr = PetscOptionsBool("-dm_plex_gmsh_use_marker", "Generate marker label", "DMPlexCreateGmsh", usemarker, &usemarker, NULL);CHKERRQ(ierr);
1507a45dabc8SMatthew G. Knepley   ierr = PetscOptionsBool("-dm_plex_gmsh_use_regions", "Generate labels with region names", "DMPlexCreateGmsh", useregions, &useregions, NULL);CHKERRQ(ierr);
15080598e1a2SLisandro Dalcin   ierr = PetscOptionsBoundedInt("-dm_plex_gmsh_spacedim", "Embedding space dimension", "DMPlexCreateGmsh", coordDim, &coordDim, NULL, PETSC_DECIDE);CHKERRQ(ierr);
1509ef12879bSLisandro Dalcin   ierr = PetscOptionsTail();CHKERRQ(ierr);
1510ef12879bSLisandro Dalcin   ierr = PetscOptionsEnd();CHKERRQ(ierr);
15110598e1a2SLisandro Dalcin 
15120598e1a2SLisandro Dalcin   ierr = GmshCellInfoSetUp();CHKERRQ(ierr);
151311c56cb0SLisandro Dalcin 
1514331830f3SMatthew G. Knepley   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
1515331830f3SMatthew G. Knepley   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
15160598e1a2SLisandro Dalcin   ierr = PetscLogEventBegin(DMPLEX_CreateGmsh,*dm,NULL,NULL,NULL);CHKERRQ(ierr);
151711c56cb0SLisandro Dalcin 
151811c56cb0SLisandro Dalcin   ierr = PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &binary);CHKERRQ(ierr);
151911c56cb0SLisandro Dalcin 
152011c56cb0SLisandro Dalcin   /* Binary viewers read on all ranks, get subviewer to read only in rank 0 */
15213b46f529SLisandro Dalcin   if (binary) {
152211c56cb0SLisandro Dalcin     parentviewer = viewer;
152311c56cb0SLisandro Dalcin     ierr = PetscViewerGetSubViewer(parentviewer, PETSC_COMM_SELF, &viewer);CHKERRQ(ierr);
152411c56cb0SLisandro Dalcin   }
152511c56cb0SLisandro Dalcin 
1526dd400576SPatrick Sanan   if (rank == 0) {
15270598e1a2SLisandro Dalcin     GmshFile  gmsh[1];
1528698a79b9SLisandro Dalcin     char      line[PETSC_MAX_PATH_LEN];
1529698a79b9SLisandro Dalcin     PetscBool match;
1530331830f3SMatthew G. Knepley 
1531580bdb30SBarry Smith     ierr = PetscArrayzero(gmsh,1);CHKERRQ(ierr);
1532698a79b9SLisandro Dalcin     gmsh->viewer = viewer;
1533698a79b9SLisandro Dalcin     gmsh->binary = binary;
1534698a79b9SLisandro Dalcin 
15350598e1a2SLisandro Dalcin     ierr = GmshMeshCreate(&mesh);CHKERRQ(ierr);
15360598e1a2SLisandro Dalcin 
1537698a79b9SLisandro Dalcin     /* Read mesh format */
1538d6689ca9SLisandro Dalcin     ierr = GmshReadSection(gmsh, line);CHKERRQ(ierr);
1539d6689ca9SLisandro Dalcin     ierr = GmshExpect(gmsh, "$MeshFormat", line);CHKERRQ(ierr);
15400598e1a2SLisandro Dalcin     ierr = GmshReadMeshFormat(gmsh);CHKERRQ(ierr);
1541d6689ca9SLisandro Dalcin     ierr = GmshReadEndSection(gmsh, "$EndMeshFormat", line);CHKERRQ(ierr);
154211c56cb0SLisandro Dalcin 
1543dc0ede3bSMatthew G. Knepley     /* OPTIONAL Read physical names */
1544d6689ca9SLisandro Dalcin     ierr = GmshReadSection(gmsh, line);CHKERRQ(ierr);
1545d6689ca9SLisandro Dalcin     ierr = GmshMatch(gmsh, "$PhysicalNames", line, &match);CHKERRQ(ierr);
1546dc0ede3bSMatthew G. Knepley     if (match) {
15470598e1a2SLisandro Dalcin       ierr = GmshExpect(gmsh, "$PhysicalNames", line);CHKERRQ(ierr);
1548a45dabc8SMatthew G. Knepley       ierr = GmshReadPhysicalNames(gmsh, mesh);CHKERRQ(ierr);
1549d6689ca9SLisandro Dalcin       ierr = GmshReadEndSection(gmsh, "$EndPhysicalNames", line);CHKERRQ(ierr);
1550698a79b9SLisandro Dalcin       /* Initial read for entity section */
1551d6689ca9SLisandro Dalcin       ierr = GmshReadSection(gmsh, line);CHKERRQ(ierr);
1552dc0ede3bSMatthew G. Knepley     }
155311c56cb0SLisandro Dalcin 
1554de78e4feSLisandro Dalcin     /* Read entities */
1555698a79b9SLisandro Dalcin     if (gmsh->fileFormat >= 40) {
1556d6689ca9SLisandro Dalcin       ierr = GmshExpect(gmsh, "$Entities", line);CHKERRQ(ierr);
15570598e1a2SLisandro Dalcin       ierr = GmshReadEntities(gmsh, mesh);CHKERRQ(ierr);
1558d6689ca9SLisandro Dalcin       ierr = GmshReadEndSection(gmsh, "$EndEntities", line);CHKERRQ(ierr);
1559698a79b9SLisandro Dalcin       /* Initial read for nodes section */
1560d6689ca9SLisandro Dalcin       ierr = GmshReadSection(gmsh, line);CHKERRQ(ierr);
1561de78e4feSLisandro Dalcin     }
1562de78e4feSLisandro Dalcin 
1563698a79b9SLisandro Dalcin     /* Read nodes */
1564d6689ca9SLisandro Dalcin     ierr = GmshExpect(gmsh, "$Nodes", line);CHKERRQ(ierr);
15650598e1a2SLisandro Dalcin     ierr = GmshReadNodes(gmsh, mesh);CHKERRQ(ierr);
1566d6689ca9SLisandro Dalcin     ierr = GmshReadEndSection(gmsh, "$EndNodes", line);CHKERRQ(ierr);
156711c56cb0SLisandro Dalcin 
1568698a79b9SLisandro Dalcin     /* Read elements */
1569feb237baSPierre Jolivet     ierr = GmshReadSection(gmsh, line);CHKERRQ(ierr);
1570d6689ca9SLisandro Dalcin     ierr = GmshExpect(gmsh, "$Elements", line);CHKERRQ(ierr);
15710598e1a2SLisandro Dalcin     ierr = GmshReadElements(gmsh, mesh);CHKERRQ(ierr);
1572d6689ca9SLisandro Dalcin     ierr = GmshReadEndSection(gmsh, "$EndElements", line);CHKERRQ(ierr);
1573de78e4feSLisandro Dalcin 
15740598e1a2SLisandro Dalcin     /* Read periodic section (OPTIONAL) */
1575698a79b9SLisandro Dalcin     if (periodic) {
1576ef12879bSLisandro Dalcin       ierr = GmshReadSection(gmsh, line);CHKERRQ(ierr);
1577ef12879bSLisandro Dalcin       ierr = GmshMatch(gmsh, "$Periodic", line, &periodic);CHKERRQ(ierr);
1578ef12879bSLisandro Dalcin     }
1579ef12879bSLisandro Dalcin     if (periodic) {
1580d6689ca9SLisandro Dalcin       ierr = GmshExpect(gmsh, "$Periodic", line);CHKERRQ(ierr);
15810598e1a2SLisandro Dalcin       ierr = GmshReadPeriodic(gmsh, mesh);CHKERRQ(ierr);
1582d6689ca9SLisandro Dalcin       ierr = GmshReadEndSection(gmsh, "$EndPeriodic", line);CHKERRQ(ierr);
1583698a79b9SLisandro Dalcin     }
1584698a79b9SLisandro Dalcin 
1585698a79b9SLisandro Dalcin     ierr = PetscFree(gmsh->wbuf);CHKERRQ(ierr);
1586698a79b9SLisandro Dalcin     ierr = PetscFree(gmsh->sbuf);CHKERRQ(ierr);
15870598e1a2SLisandro Dalcin     ierr = PetscFree(gmsh->nbuf);CHKERRQ(ierr);
15880598e1a2SLisandro Dalcin 
15890598e1a2SLisandro Dalcin     dim       = mesh->dim;
1590066ea43fSLisandro Dalcin     order     = mesh->order;
15910598e1a2SLisandro Dalcin     numNodes  = mesh->numNodes;
15920598e1a2SLisandro Dalcin     numElems  = mesh->numElems;
15930598e1a2SLisandro Dalcin     numVerts  = mesh->numVerts;
15940598e1a2SLisandro Dalcin     numCells  = mesh->numCells;
1595066ea43fSLisandro Dalcin 
1596066ea43fSLisandro Dalcin     {
1597066ea43fSLisandro Dalcin       GmshElement *elemA = mesh->numCells > 0 ? mesh->elements : NULL;
1598066ea43fSLisandro Dalcin       GmshElement *elemB = elemA ? elemA + mesh->numCells - 1  : NULL;
1599066ea43fSLisandro Dalcin       int ptA = elemA ? GmshCellMap[elemA->cellType].polytope : -1;
1600066ea43fSLisandro Dalcin       int ptB = elemB ? GmshCellMap[elemB->cellType].polytope : -1;
1601066ea43fSLisandro Dalcin       isSimplex = (ptA == GMSH_QUA || ptA == GMSH_HEX) ? PETSC_FALSE : PETSC_TRUE;
1602066ea43fSLisandro Dalcin       isHybrid  = (ptA == ptB) ? PETSC_FALSE : PETSC_TRUE;
1603066ea43fSLisandro Dalcin       hasTetra  = (ptA == GMSH_TET) ? PETSC_TRUE : PETSC_FALSE;
1604066ea43fSLisandro Dalcin     }
1605698a79b9SLisandro Dalcin   }
1606698a79b9SLisandro Dalcin 
1607698a79b9SLisandro Dalcin   if (parentviewer) {
1608698a79b9SLisandro Dalcin     ierr = PetscViewerRestoreSubViewer(parentviewer, PETSC_COMM_SELF, &viewer);CHKERRQ(ierr);
1609698a79b9SLisandro Dalcin   }
1610698a79b9SLisandro Dalcin 
1611066ea43fSLisandro Dalcin   {
1612066ea43fSLisandro Dalcin     int buf[6];
1613698a79b9SLisandro Dalcin 
1614066ea43fSLisandro Dalcin     buf[0] = (int)dim;
1615066ea43fSLisandro Dalcin     buf[1] = (int)order;
1616066ea43fSLisandro Dalcin     buf[2] = periodic;
1617066ea43fSLisandro Dalcin     buf[3] = isSimplex;
1618066ea43fSLisandro Dalcin     buf[4] = isHybrid;
1619066ea43fSLisandro Dalcin     buf[5] = hasTetra;
1620066ea43fSLisandro Dalcin 
1621ffc4695bSBarry Smith     ierr = MPI_Bcast(buf, 6, MPI_INT, 0, comm);CHKERRMPI(ierr);
1622066ea43fSLisandro Dalcin 
1623066ea43fSLisandro Dalcin     dim       = buf[0];
1624066ea43fSLisandro Dalcin     order     = buf[1];
1625066ea43fSLisandro Dalcin     periodic  = buf[2] ? PETSC_TRUE : PETSC_FALSE;
1626066ea43fSLisandro Dalcin     isSimplex = buf[3] ? PETSC_TRUE : PETSC_FALSE;
1627066ea43fSLisandro Dalcin     isHybrid  = buf[4] ? PETSC_TRUE : PETSC_FALSE;
1628066ea43fSLisandro Dalcin     hasTetra  = buf[5] ? PETSC_TRUE : PETSC_FALSE;
1629dea2a3c7SStefano Zampini   }
1630dea2a3c7SStefano Zampini 
1631066ea43fSLisandro Dalcin   if (!highOrderSet) highOrder = (order > 1) ? PETSC_TRUE : PETSC_FALSE;
1632066ea43fSLisandro Dalcin   if (highOrder && isHybrid) SETERRQ(comm, PETSC_ERR_SUP, "No support for discretization on hybrid meshes yet");
1633066ea43fSLisandro Dalcin 
16340598e1a2SLisandro Dalcin   /* We do not want this label automatically computed, instead we fill it here */
16350598e1a2SLisandro Dalcin   ierr = DMCreateLabel(*dm, "celltype");CHKERRQ(ierr);
163611c56cb0SLisandro Dalcin 
1637a4bb7517SMichael Lange   /* Allocate the cell-vertex mesh */
16380598e1a2SLisandro Dalcin   ierr = DMPlexSetChart(*dm, 0, numCells+numVerts);CHKERRQ(ierr);
16390598e1a2SLisandro Dalcin   for (cell = 0; cell < numCells; ++cell) {
16400598e1a2SLisandro Dalcin     GmshElement *elem = mesh->elements + cell;
16410598e1a2SLisandro Dalcin     DMPolytopeType ctype = DMPolytopeTypeFromGmsh(elem->cellType);
16420598e1a2SLisandro Dalcin     if (hybrid && hasTetra && ctype == DM_POLYTOPE_TRI_PRISM) ctype = DM_POLYTOPE_TRI_PRISM_TENSOR;
16430598e1a2SLisandro Dalcin     ierr = DMPlexSetConeSize(*dm, cell, elem->numVerts);CHKERRQ(ierr);
16440598e1a2SLisandro Dalcin     ierr = DMPlexSetCellType(*dm, cell, ctype);CHKERRQ(ierr);
1645db397164SMichael Lange   }
16460598e1a2SLisandro Dalcin   for (v = numCells; v < numCells+numVerts; ++v) {
164796ca5757SLisandro Dalcin     ierr = DMPlexSetCellType(*dm, v, DM_POLYTOPE_POINT);CHKERRQ(ierr);
164896ca5757SLisandro Dalcin   }
1649331830f3SMatthew G. Knepley   ierr = DMSetUp(*dm);CHKERRQ(ierr);
165096ca5757SLisandro Dalcin 
1651a4bb7517SMichael Lange   /* Add cell-vertex connections */
16520598e1a2SLisandro Dalcin   for (cell = 0; cell < numCells; ++cell) {
16530598e1a2SLisandro Dalcin     GmshElement *elem = mesh->elements + cell;
16540598e1a2SLisandro Dalcin     for (v = 0; v < elem->numVerts; ++v) {
16550598e1a2SLisandro Dalcin       const PetscInt nn = elem->nodes[v];
16560598e1a2SLisandro Dalcin       const PetscInt vv = mesh->vertexMap[nn];
16570598e1a2SLisandro Dalcin       cone[v] = numCells + vv;
1658db397164SMichael Lange     }
16590598e1a2SLisandro Dalcin     ierr = DMPlexReorderCell(*dm, cell, cone);CHKERRQ(ierr);
16600598e1a2SLisandro Dalcin     ierr = DMPlexSetCone(*dm, cell, cone);CHKERRQ(ierr);
1661a4bb7517SMichael Lange   }
166296ca5757SLisandro Dalcin 
1663c73cfb54SMatthew G. Knepley   ierr = DMSetDimension(*dm, dim);CHKERRQ(ierr);
1664331830f3SMatthew G. Knepley   ierr = DMPlexSymmetrize(*dm);CHKERRQ(ierr);
1665331830f3SMatthew G. Knepley   ierr = DMPlexStratify(*dm);CHKERRQ(ierr);
1666331830f3SMatthew G. Knepley   if (interpolate) {
16675fd9971aSMatthew G. Knepley     DM idm;
1668331830f3SMatthew G. Knepley 
1669331830f3SMatthew G. Knepley     ierr = DMPlexInterpolate(*dm, &idm);CHKERRQ(ierr);
1670331830f3SMatthew G. Knepley     ierr = DMDestroy(dm);CHKERRQ(ierr);
1671331830f3SMatthew G. Knepley     *dm  = idm;
1672331830f3SMatthew G. Knepley   }
1673917266a4SLisandro Dalcin 
1674f6c8a31fSLisandro Dalcin   if (usemarker && !interpolate && dim > 1) SETERRQ(comm,PETSC_ERR_SUP,"Cannot create marker label without interpolation");
1675dd400576SPatrick Sanan   if (rank == 0 && usemarker) {
1676d3f73514SStefano Zampini     PetscInt f, fStart, fEnd;
1677d3f73514SStefano Zampini 
1678d3f73514SStefano Zampini     ierr = DMCreateLabel(*dm, "marker");CHKERRQ(ierr);
1679d3f73514SStefano Zampini     ierr = DMPlexGetHeightStratum(*dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
1680d3f73514SStefano Zampini     for (f = fStart; f < fEnd; ++f) {
1681d3f73514SStefano Zampini       PetscInt suppSize;
1682d3f73514SStefano Zampini 
1683d3f73514SStefano Zampini       ierr = DMPlexGetSupportSize(*dm, f, &suppSize);CHKERRQ(ierr);
1684d3f73514SStefano Zampini       if (suppSize == 1) {
1685d3f73514SStefano Zampini         PetscInt *cone = NULL, coneSize, p;
1686d3f73514SStefano Zampini 
1687d3f73514SStefano Zampini         ierr = DMPlexGetTransitiveClosure(*dm, f, PETSC_TRUE, &coneSize, &cone);CHKERRQ(ierr);
1688d3f73514SStefano Zampini         for (p = 0; p < coneSize; p += 2) {
16897dd454faSLisandro Dalcin           ierr = DMSetLabelValue_Fast(*dm, &marker, "marker", cone[p], 1);CHKERRQ(ierr);
1690d3f73514SStefano Zampini         }
1691d3f73514SStefano Zampini         ierr = DMPlexRestoreTransitiveClosure(*dm, f, PETSC_TRUE, &coneSize, &cone);CHKERRQ(ierr);
1692d3f73514SStefano Zampini       }
1693d3f73514SStefano Zampini     }
1694d3f73514SStefano Zampini   }
169516ad7e67SMichael Lange 
1696dd400576SPatrick Sanan   if (rank == 0) {
1697a45dabc8SMatthew G. Knepley     const PetscInt Nr = useregions ? mesh->numRegions : 0;
169811c56cb0SLisandro Dalcin     PetscInt       vStart, vEnd;
1699d1a54cefSMatthew G. Knepley 
1700a45dabc8SMatthew G. Knepley     ierr = PetscCalloc1(Nr, &regionSets);CHKERRQ(ierr);
170116ad7e67SMichael Lange     ierr = DMPlexGetDepthStratum(*dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
17020598e1a2SLisandro Dalcin     for (cell = 0, e = 0; e < numElems; ++e) {
17030598e1a2SLisandro Dalcin       GmshElement *elem = mesh->elements + e;
17046e1dd89aSLawrence Mitchell 
17056e1dd89aSLawrence Mitchell       /* Create cell sets */
17060598e1a2SLisandro Dalcin       if (elem->dim == dim && dim > 0) {
17070598e1a2SLisandro Dalcin         if (elem->numTags > 0) {
1708a45dabc8SMatthew G. Knepley           const PetscInt tag = elem->tags[0];
1709a45dabc8SMatthew G. Knepley           PetscInt       r;
1710a45dabc8SMatthew G. Knepley 
1711a45dabc8SMatthew G. Knepley           ierr = DMSetLabelValue_Fast(*dm, &cellSets, "Cell Sets", cell, tag);CHKERRQ(ierr);
1712a45dabc8SMatthew G. Knepley           for (r = 0; r < Nr; ++r) {
1713a45dabc8SMatthew G. Knepley             if (mesh->regionTags[r] == tag) {ierr = DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], cell, tag);CHKERRQ(ierr);}
1714a45dabc8SMatthew G. Knepley           }
17156e1dd89aSLawrence Mitchell         }
1716917266a4SLisandro Dalcin         cell++;
17176e1dd89aSLawrence Mitchell       }
17180c070f12SSander Arens 
17190598e1a2SLisandro Dalcin       /* Create face sets */
17200598e1a2SLisandro Dalcin       if (interpolate && elem->dim == dim-1) {
17210598e1a2SLisandro Dalcin         PetscInt        joinSize;
17220598e1a2SLisandro Dalcin         const PetscInt *join = NULL;
1723a45dabc8SMatthew G. Knepley         const PetscInt  tag = elem->tags[0];
1724a45dabc8SMatthew G. Knepley         PetscInt        r;
1725a45dabc8SMatthew G. Knepley 
17260598e1a2SLisandro Dalcin         /* Find the relevant facet with vertex joins */
17270598e1a2SLisandro Dalcin         for (v = 0; v < elem->numVerts; ++v) {
17280598e1a2SLisandro Dalcin           const PetscInt nn = elem->nodes[v];
17290598e1a2SLisandro Dalcin           const PetscInt vv = mesh->vertexMap[nn];
17300598e1a2SLisandro Dalcin           cone[v] = vStart + vv;
17310598e1a2SLisandro Dalcin         }
17320598e1a2SLisandro Dalcin         ierr = DMPlexGetFullJoin(*dm, elem->numVerts, cone, &joinSize, &join);CHKERRQ(ierr);
17330598e1a2SLisandro Dalcin         if (joinSize != 1) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_SUP, "Could not determine Plex facet for Gmsh element %D (Plex cell %D)", elem->id, e);
1734a45dabc8SMatthew G. Knepley         ierr = DMSetLabelValue_Fast(*dm, &faceSets, "Face Sets", join[0], tag);CHKERRQ(ierr);
1735a45dabc8SMatthew G. Knepley         for (r = 0; r < Nr; ++r) {
1736a45dabc8SMatthew G. Knepley           if (mesh->regionTags[r] == tag) {ierr = DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], join[0], tag);CHKERRQ(ierr);}
1737a45dabc8SMatthew G. Knepley         }
17380598e1a2SLisandro Dalcin         ierr = DMPlexRestoreJoin(*dm, elem->numVerts, cone, &joinSize, &join);CHKERRQ(ierr);
17390598e1a2SLisandro Dalcin       }
17400598e1a2SLisandro Dalcin 
17410c070f12SSander Arens       /* Create vertex sets */
17420598e1a2SLisandro Dalcin       if (elem->dim == 0) {
17430598e1a2SLisandro Dalcin         if (elem->numTags > 0) {
17440598e1a2SLisandro Dalcin           const PetscInt nn = elem->nodes[0];
17450598e1a2SLisandro Dalcin           const PetscInt vv = mesh->vertexMap[nn];
1746a45dabc8SMatthew G. Knepley           const PetscInt tag = elem->tags[0];
1747a45dabc8SMatthew G. Knepley           PetscInt       r;
1748a45dabc8SMatthew G. Knepley 
1749a45dabc8SMatthew G. Knepley           ierr = DMSetLabelValue_Fast(*dm, &vertSets, "Vertex Sets", vStart + vv, tag);CHKERRQ(ierr);
1750a45dabc8SMatthew G. Knepley           for (r = 0; r < Nr; ++r) {
1751a45dabc8SMatthew G. Knepley             if (mesh->regionTags[r] == tag) {ierr = DMSetLabelValue_Fast(*dm, &regionSets[r], mesh->regionNames[r], vStart + vv, tag);CHKERRQ(ierr);}
17520598e1a2SLisandro Dalcin           }
17530598e1a2SLisandro Dalcin         }
17540598e1a2SLisandro Dalcin       }
17550598e1a2SLisandro Dalcin     }
1756a45dabc8SMatthew G. Knepley     ierr = PetscFree(regionSets);CHKERRQ(ierr);
1757a45dabc8SMatthew G. Knepley   }
17580598e1a2SLisandro Dalcin 
17597dd454faSLisandro Dalcin   { /* Create Cell/Face/Vertex Sets labels at all processes */
17607dd454faSLisandro Dalcin     enum {n = 4};
17617dd454faSLisandro Dalcin     PetscBool flag[n];
17627dd454faSLisandro Dalcin 
17637dd454faSLisandro Dalcin     flag[0] = cellSets ? PETSC_TRUE : PETSC_FALSE;
17647dd454faSLisandro Dalcin     flag[1] = faceSets ? PETSC_TRUE : PETSC_FALSE;
17657dd454faSLisandro Dalcin     flag[2] = vertSets ? PETSC_TRUE : PETSC_FALSE;
17667dd454faSLisandro Dalcin     flag[3] = marker   ? PETSC_TRUE : PETSC_FALSE;
17677dd454faSLisandro Dalcin     ierr = MPI_Bcast(flag, n, MPIU_BOOL, 0, comm);CHKERRMPI(ierr);
17687dd454faSLisandro Dalcin     if (flag[0]) {ierr = DMCreateLabel(*dm, "Cell Sets");CHKERRQ(ierr);}
17697dd454faSLisandro Dalcin     if (flag[1]) {ierr = DMCreateLabel(*dm, "Face Sets");CHKERRQ(ierr);}
17707dd454faSLisandro Dalcin     if (flag[2]) {ierr = DMCreateLabel(*dm, "Vertex Sets");CHKERRQ(ierr);}
17717dd454faSLisandro Dalcin     if (flag[3]) {ierr = DMCreateLabel(*dm, "marker");CHKERRQ(ierr);}
17727dd454faSLisandro Dalcin   }
17737dd454faSLisandro Dalcin 
17740598e1a2SLisandro Dalcin   if (periodic) {
17750598e1a2SLisandro Dalcin     ierr = PetscBTCreate(numVerts, &periodicVerts);CHKERRQ(ierr);
17760598e1a2SLisandro Dalcin     for (n = 0; n < numNodes; ++n) {
17770598e1a2SLisandro Dalcin       if (mesh->vertexMap[n] >= 0) {
17780598e1a2SLisandro Dalcin         if (PetscUnlikely(mesh->periodMap[n] != n)) {
17790598e1a2SLisandro Dalcin           PetscInt m = mesh->periodMap[n];
17800598e1a2SLisandro Dalcin           ierr = PetscBTSet(periodicVerts, mesh->vertexMap[n]);CHKERRQ(ierr);
17810598e1a2SLisandro Dalcin           ierr = PetscBTSet(periodicVerts, mesh->vertexMap[m]);CHKERRQ(ierr);
17820598e1a2SLisandro Dalcin         }
17830598e1a2SLisandro Dalcin       }
17840598e1a2SLisandro Dalcin     }
17850598e1a2SLisandro Dalcin     ierr = PetscBTCreate(numCells, &periodicCells);CHKERRQ(ierr);
17860598e1a2SLisandro Dalcin     for (cell = 0; cell < numCells; ++cell) {
17870598e1a2SLisandro Dalcin       GmshElement *elem = mesh->elements + cell;
17880598e1a2SLisandro Dalcin       for (v = 0; v < elem->numVerts; ++v) {
17890598e1a2SLisandro Dalcin         PetscInt nn = elem->nodes[v];
17900598e1a2SLisandro Dalcin         PetscInt vv = mesh->vertexMap[nn];
17910598e1a2SLisandro Dalcin         if (PetscUnlikely(PetscBTLookup(periodicVerts, vv))) {
17920598e1a2SLisandro Dalcin           ierr = PetscBTSet(periodicCells, cell);CHKERRQ(ierr); break;
17930c070f12SSander Arens         }
17940c070f12SSander Arens       }
17950c070f12SSander Arens     }
179616ad7e67SMichael Lange   }
179716ad7e67SMichael Lange 
1798066ea43fSLisandro Dalcin   /* Setup coordinate DM */
17990598e1a2SLisandro Dalcin   if (coordDim < 0) coordDim = dim;
18000598e1a2SLisandro Dalcin   ierr = DMSetCoordinateDim(*dm, coordDim);CHKERRQ(ierr);
1801066ea43fSLisandro Dalcin   ierr = DMGetCoordinateDM(*dm, &cdm);CHKERRQ(ierr);
1802066ea43fSLisandro Dalcin   if (highOrder) {
1803066ea43fSLisandro Dalcin     PetscFE         fe;
1804066ea43fSLisandro Dalcin     PetscBool       continuity = periodic ? PETSC_FALSE : PETSC_TRUE;
1805066ea43fSLisandro Dalcin     PetscDTNodeType nodeType   = PETSCDTNODES_EQUISPACED;
1806066ea43fSLisandro Dalcin 
1807066ea43fSLisandro Dalcin     if (isSimplex) continuity = PETSC_FALSE; /* XXX FIXME Requires DMPlexSetClosurePermutationLexicographic() */
1808066ea43fSLisandro Dalcin 
1809066ea43fSLisandro Dalcin     ierr = GmshCreateFE(comm, NULL, isSimplex, continuity, nodeType, dim, coordDim, order, &fe);CHKERRQ(ierr);
1810066ea43fSLisandro Dalcin     ierr = PetscFEViewFromOptions(fe, NULL, "-dm_plex_gmsh_fe_view");CHKERRQ(ierr);
1811066ea43fSLisandro Dalcin     ierr = DMSetField(cdm, 0, NULL, (PetscObject) fe);CHKERRQ(ierr);
1812066ea43fSLisandro Dalcin     ierr = PetscFEDestroy(&fe);CHKERRQ(ierr);
1813066ea43fSLisandro Dalcin     ierr = DMCreateDS(cdm);CHKERRQ(ierr);
1814066ea43fSLisandro Dalcin   }
1815066ea43fSLisandro Dalcin 
1816066ea43fSLisandro Dalcin   /* Create coordinates */
1817066ea43fSLisandro Dalcin   if (highOrder) {
1818066ea43fSLisandro Dalcin 
1819066ea43fSLisandro Dalcin     PetscInt     maxDof = GmshNumNodes_HEX(order)*coordDim;
1820066ea43fSLisandro Dalcin     double       *coords = mesh ? mesh->nodelist->xyz : NULL;
1821066ea43fSLisandro Dalcin     PetscSection section;
1822066ea43fSLisandro Dalcin     PetscScalar  *cellCoords;
1823066ea43fSLisandro Dalcin 
1824066ea43fSLisandro Dalcin     ierr = DMSetLocalSection(cdm, NULL);CHKERRQ(ierr);
1825066ea43fSLisandro Dalcin     ierr = DMGetLocalSection(cdm, &coordSection);CHKERRQ(ierr);
1826066ea43fSLisandro Dalcin     ierr = PetscSectionClone(coordSection, &section);CHKERRQ(ierr);
1827066ea43fSLisandro Dalcin     ierr = DMPlexSetClosurePermutationTensor(cdm, 0, section);CHKERRQ(ierr); /* XXX Implement DMPlexSetClosurePermutationLexicographic() */
1828066ea43fSLisandro Dalcin 
1829066ea43fSLisandro Dalcin     ierr = DMCreateLocalVector(cdm, &coordinates);CHKERRQ(ierr);
1830066ea43fSLisandro Dalcin     ierr = PetscMalloc1(maxDof, &cellCoords);CHKERRQ(ierr);
1831066ea43fSLisandro Dalcin     for (cell = 0; cell < numCells; ++cell) {
1832066ea43fSLisandro Dalcin       GmshElement *elem = mesh->elements + cell;
1833066ea43fSLisandro Dalcin       const int *lexorder = GmshCellMap[elem->cellType].lexorder();
1834*b9bf55e5SMatthew G. Knepley       int s = 0;
1835066ea43fSLisandro Dalcin       for (n = 0; n < elem->numNodes; ++n) {
1836*b9bf55e5SMatthew G. Knepley         while (lexorder[n+s] < 0) ++s;
1837*b9bf55e5SMatthew G. Knepley         const PetscInt node = elem->nodes[lexorder[n+s]];
1838*b9bf55e5SMatthew G. Knepley         for (d = 0; d < coordDim; ++d) cellCoords[(n+s)*coordDim+d] = (PetscReal) coords[node*3+d];
1839*b9bf55e5SMatthew G. Knepley       }
1840*b9bf55e5SMatthew G. Knepley       if (s) {
1841*b9bf55e5SMatthew G. Knepley         /* For the coordinate mapping we weight vertices by -1/4 and edges by 1/2, which we get from Q_2 interpolation */
1842*b9bf55e5SMatthew G. Knepley         PetscReal quaCenterWeights[9]  = {-0.25, 0.5, -0.25, 0.5, 0.0, 0.5, -0.25, 0.5, -0.25};
1843*b9bf55e5SMatthew G. Knepley         /* For the coordinate mapping we weight vertices by -1/4 and edges by 1/2, which we get from Q_2 interpolation */
1844*b9bf55e5SMatthew G. Knepley         PetscReal hexBottomWeights[27] = {-0.25, 0.5,  -0.25, 0.5,  0.0, 0.5,  -0.25, 0.5,  -0.25,
1845*b9bf55e5SMatthew G. Knepley                                            0.0,  0.0,   0.0,  0.0,  0.0, 0.0,   0.0,  0.0,   0.0,
1846*b9bf55e5SMatthew G. Knepley                                            0.0,  0.0,   0.0,  0.0,  0.0, 0.0,   0.0,  0.0,   0.0};
1847*b9bf55e5SMatthew G. Knepley         PetscReal hexFrontWeights[27]  = {-0.25, 0.5,  -0.25, 0.0,  0.0, 0.0,   0.0,  0.0,   0.0,
1848*b9bf55e5SMatthew G. Knepley                                            0.5,  0.0,   0.5,  0.0,  0.0, 0.0,   0.0,  0.0,   0.0,
1849*b9bf55e5SMatthew G. Knepley                                           -0.25, 0.5,  -0.25, 0.0,  0.0, 0.0,   0.0,  0.0,   0.0};
1850*b9bf55e5SMatthew G. Knepley         PetscReal hexLeftWeights[27]   = {-0.25, 0.0,   0.0,  0.5,  0.0, 0.0,  -0.25, 0.0,   0.0,
1851*b9bf55e5SMatthew G. Knepley                                            0.5,  0.0,   0.0,  0.0,  0.0, 0.0,   0.5,  0.0,   0.0,
1852*b9bf55e5SMatthew G. Knepley                                           -0.25, 0.0,   0.0,  0.5,  0.0, 0.0,  -0.25, 0.0,   0.0};
1853*b9bf55e5SMatthew G. Knepley         PetscReal hexRightWeights[27]  = { 0.0,  0.0,  -0.25, 0.0,  0.0, 0.5,   0.0,  0.0,  -0.25,
1854*b9bf55e5SMatthew G. Knepley                                            0.0,  0.0,   0.5,  0.0,  0.0, 0.0,   0.0,  0.0,   0.5,
1855*b9bf55e5SMatthew G. Knepley                                            0.0,  0.0,  -0.25, 0.0,  0.0, 0.5,   0.0,  0.0,  -0.25};
1856*b9bf55e5SMatthew G. Knepley         PetscReal hexBackWeights[27]   = { 0.0,  0.0,   0.0,  0.0,  0.0, 0.0,  -0.25, 0.5,  -0.25,
1857*b9bf55e5SMatthew G. Knepley                                            0.0,  0.0,   0.0,  0.0,  0.0, 0.0,   0.5,  0.0,   0.5,
1858*b9bf55e5SMatthew G. Knepley                                            0.0,  0.0,   0.0,  0.0,  0.0, 0.0,  -0.25, 0.5,  -0.25};
1859*b9bf55e5SMatthew G. Knepley         PetscReal hexTopWeights[27]    = { 0.0,  0.0,   0.0,  0.0,  0.0, 0.0,   0.0,  0.0,   0.0,
1860*b9bf55e5SMatthew G. Knepley                                            0.0,  0.0,   0.0,  0.0,  0.0, 0.0,   0.0,  0.0,   0.0,
1861*b9bf55e5SMatthew G. Knepley                                           -0.25, 0.5,  -0.25, 0.5,  0.0, 0.5,  -0.25, 0.5,  -0.25};
1862*b9bf55e5SMatthew G. Knepley         PetscReal hexCenterWeights[27] = {-0.25, 0.25, -0.25, 0.25, 0.0, 0.25, -0.25, 0.25, -0.25,
1863*b9bf55e5SMatthew G. Knepley                                            0.25, 0.0,   0.25, 0.0,  0.0, 0.0,   0.25, 0.0,   0.25,
1864*b9bf55e5SMatthew G. Knepley                                           -0.25, 0.25, -0.25, 0.25, 0.0, 0.25, -0.25, 0.25, -0.25};
1865*b9bf55e5SMatthew G. Knepley         PetscReal  *sdWeights2[9]      = {NULL, NULL, NULL, NULL, quaCenterWeights, NULL, NULL, NULL, NULL};
1866*b9bf55e5SMatthew G. Knepley         PetscReal  *sdWeights3[27]     = {NULL, NULL, NULL, NULL, hexBottomWeights, NULL, NULL, NULL, NULL,
1867*b9bf55e5SMatthew G. Knepley                                           NULL, hexFrontWeights, NULL, hexLeftWeights, hexCenterWeights, hexRightWeights, NULL, hexBackWeights, NULL,
1868*b9bf55e5SMatthew G. Knepley                                           NULL, NULL, NULL, NULL, hexTopWeights,    NULL, NULL, NULL, NULL};
1869*b9bf55e5SMatthew G. Knepley         PetscReal **sdWeights[4]       = {NULL, NULL, sdWeights2, sdWeights3};
1870*b9bf55e5SMatthew G. Knepley 
1871*b9bf55e5SMatthew G. Knepley         /* Missing entries in serendipity cell, only works for 8-node quad and 20-node hex */
1872*b9bf55e5SMatthew G. Knepley         for (n = 0; n < elem->numNodes+s; ++n) {
1873*b9bf55e5SMatthew G. Knepley           if (lexorder[n] >= 0) continue;
1874*b9bf55e5SMatthew G. Knepley           for (d = 0; d < coordDim; ++d) cellCoords[n*coordDim+d] = 0.0;
1875*b9bf55e5SMatthew G. Knepley           for (int bn = 0; bn < elem->numNodes+s; ++bn) {
1876*b9bf55e5SMatthew G. Knepley             if (lexorder[bn] < 0) continue;
1877*b9bf55e5SMatthew G. Knepley             const PetscReal *weights = sdWeights[coordDim][n];
1878*b9bf55e5SMatthew G. Knepley             const PetscInt   bnode   = elem->nodes[lexorder[bn]];
1879*b9bf55e5SMatthew G. Knepley             for (d = 0; d < coordDim; ++d) cellCoords[n*coordDim+d] += weights[bn] * (PetscReal) coords[bnode*3+d];
1880*b9bf55e5SMatthew G. Knepley           }
1881*b9bf55e5SMatthew G. Knepley         }
1882066ea43fSLisandro Dalcin       }
1883066ea43fSLisandro Dalcin       ierr = DMPlexVecSetClosure(cdm, section, coordinates, cell, cellCoords, INSERT_VALUES);CHKERRQ(ierr);
1884066ea43fSLisandro Dalcin     }
1885066ea43fSLisandro Dalcin     ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
1886066ea43fSLisandro Dalcin     ierr = PetscFree(cellCoords);CHKERRQ(ierr);
1887066ea43fSLisandro Dalcin 
1888066ea43fSLisandro Dalcin   } else {
1889066ea43fSLisandro Dalcin 
1890066ea43fSLisandro Dalcin     PetscInt    *nodeMap;
1891066ea43fSLisandro Dalcin     double      *coords = mesh ? mesh->nodelist->xyz : NULL;
1892066ea43fSLisandro Dalcin     PetscScalar *pointCoords;
1893066ea43fSLisandro Dalcin 
1894066ea43fSLisandro Dalcin     ierr = DMGetLocalSection(cdm, &coordSection);CHKERRQ(ierr);
1895331830f3SMatthew G. Knepley     ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
18960598e1a2SLisandro Dalcin     ierr = PetscSectionSetFieldComponents(coordSection, 0, coordDim);CHKERRQ(ierr);
18970598e1a2SLisandro Dalcin     if (periodic) { /* we need to localize coordinates on cells */
18980598e1a2SLisandro Dalcin       ierr = PetscSectionSetChart(coordSection, 0, numCells+numVerts);CHKERRQ(ierr);
1899f45c9589SStefano Zampini     } else {
19000598e1a2SLisandro Dalcin       ierr = PetscSectionSetChart(coordSection, numCells, numCells+numVerts);CHKERRQ(ierr);
1901f45c9589SStefano Zampini     }
19020598e1a2SLisandro Dalcin     if (periodic) {
19030598e1a2SLisandro Dalcin       for (cell = 0; cell < numCells; ++cell) {
19040598e1a2SLisandro Dalcin         if (PetscUnlikely(PetscBTLookup(periodicCells, cell))) {
19050598e1a2SLisandro Dalcin           GmshElement *elem = mesh->elements + cell;
19060598e1a2SLisandro Dalcin           PetscInt dof = elem->numVerts * coordDim;
19070598e1a2SLisandro Dalcin           ierr = PetscSectionSetDof(coordSection, cell, dof);CHKERRQ(ierr);
19080598e1a2SLisandro Dalcin           ierr = PetscSectionSetFieldDof(coordSection, cell, 0, dof);CHKERRQ(ierr);
1909f45c9589SStefano Zampini         }
1910f45c9589SStefano Zampini       }
1911f45c9589SStefano Zampini     }
19120598e1a2SLisandro Dalcin     for (v = numCells; v < numCells+numVerts; ++v) {
19130598e1a2SLisandro Dalcin       ierr = PetscSectionSetDof(coordSection, v, coordDim);CHKERRQ(ierr);
19140598e1a2SLisandro Dalcin       ierr = PetscSectionSetFieldDof(coordSection, v, 0, coordDim);CHKERRQ(ierr);
19150598e1a2SLisandro Dalcin     }
1916331830f3SMatthew G. Knepley     ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
1917066ea43fSLisandro Dalcin 
1918066ea43fSLisandro Dalcin     ierr = DMCreateLocalVector(cdm, &coordinates);CHKERRQ(ierr);
1919066ea43fSLisandro Dalcin     ierr = VecGetArray(coordinates, &pointCoords);CHKERRQ(ierr);
19200598e1a2SLisandro Dalcin     if (periodic) {
19210598e1a2SLisandro Dalcin       for (cell = 0; cell < numCells; ++cell) {
19220598e1a2SLisandro Dalcin         if (PetscUnlikely(PetscBTLookup(periodicCells, cell))) {
19230598e1a2SLisandro Dalcin           GmshElement *elem = mesh->elements + cell;
19240598e1a2SLisandro Dalcin           PetscInt off, node;
19250598e1a2SLisandro Dalcin           for (v = 0; v < elem->numVerts; ++v)
19260598e1a2SLisandro Dalcin             cone[v] = elem->nodes[v];
1927066ea43fSLisandro Dalcin           ierr = DMPlexReorderCell(cdm, cell, cone);CHKERRQ(ierr);
19280598e1a2SLisandro Dalcin           ierr = PetscSectionGetOffset(coordSection, cell, &off);CHKERRQ(ierr);
19290598e1a2SLisandro Dalcin           for (v = 0; v < elem->numVerts; ++v)
19300598e1a2SLisandro Dalcin             for (node = cone[v], d = 0; d < coordDim; ++d)
1931066ea43fSLisandro Dalcin               pointCoords[off++] = (PetscReal) coords[node*3+d];
1932331830f3SMatthew G. Knepley         }
1933331830f3SMatthew G. Knepley       }
1934331830f3SMatthew G. Knepley     }
1935066ea43fSLisandro Dalcin     ierr = PetscMalloc1(numVerts, &nodeMap);CHKERRQ(ierr);
19360598e1a2SLisandro Dalcin     for (n = 0; n < numNodes; n++)
19370598e1a2SLisandro Dalcin       if (mesh->vertexMap[n] >= 0)
1938066ea43fSLisandro Dalcin         nodeMap[mesh->vertexMap[n]] = n;
19390598e1a2SLisandro Dalcin     for (v = 0; v < numVerts; ++v) {
1940066ea43fSLisandro Dalcin       PetscInt off, node = nodeMap[v];
19410598e1a2SLisandro Dalcin       ierr = PetscSectionGetOffset(coordSection, numCells + v, &off);CHKERRQ(ierr);
19420598e1a2SLisandro Dalcin       for (d = 0; d < coordDim; ++d)
1943066ea43fSLisandro Dalcin         pointCoords[off+d] = (PetscReal) coords[node*3+d];
19440598e1a2SLisandro Dalcin     }
1945066ea43fSLisandro Dalcin     ierr = PetscFree(nodeMap);CHKERRQ(ierr);
1946066ea43fSLisandro Dalcin     ierr = VecRestoreArray(coordinates, &pointCoords);CHKERRQ(ierr);
1947066ea43fSLisandro Dalcin 
1948066ea43fSLisandro Dalcin   }
1949066ea43fSLisandro Dalcin 
1950066ea43fSLisandro Dalcin   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
1951066ea43fSLisandro Dalcin   ierr = VecSetBlockSize(coordinates, coordDim);CHKERRQ(ierr);
1952331830f3SMatthew G. Knepley   ierr = DMSetCoordinatesLocal(*dm, coordinates);CHKERRQ(ierr);
19530598e1a2SLisandro Dalcin   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
195411c56cb0SLisandro Dalcin   ierr = DMSetPeriodicity(*dm, periodic, NULL, NULL, NULL);CHKERRQ(ierr);
195511c56cb0SLisandro Dalcin 
19560598e1a2SLisandro Dalcin   ierr = GmshMeshDestroy(&mesh);CHKERRQ(ierr);
19570598e1a2SLisandro Dalcin   ierr = PetscBTDestroy(&periodicVerts);CHKERRQ(ierr);
19580598e1a2SLisandro Dalcin   ierr = PetscBTDestroy(&periodicCells);CHKERRQ(ierr);
195911c56cb0SLisandro Dalcin 
1960066ea43fSLisandro Dalcin   if (highOrder && project)  {
1961066ea43fSLisandro Dalcin     PetscFE         fe;
1962066ea43fSLisandro Dalcin     const char      prefix[]   = "dm_plex_gmsh_project_";
1963066ea43fSLisandro Dalcin     PetscBool       continuity = periodic ? PETSC_FALSE : PETSC_TRUE;
1964066ea43fSLisandro Dalcin     PetscDTNodeType nodeType   = PETSCDTNODES_GAUSSJACOBI;
1965066ea43fSLisandro Dalcin 
1966066ea43fSLisandro Dalcin     if (isSimplex) continuity = PETSC_FALSE; /* XXX FIXME Requires DMPlexSetClosurePermutationLexicographic() */
1967066ea43fSLisandro Dalcin 
1968066ea43fSLisandro Dalcin     ierr = GmshCreateFE(comm, prefix, isSimplex, continuity, nodeType, dim, coordDim, order, &fe);CHKERRQ(ierr);
1969066ea43fSLisandro Dalcin     ierr = PetscFEViewFromOptions(fe, NULL, "-dm_plex_gmsh_project_fe_view");CHKERRQ(ierr);
1970066ea43fSLisandro Dalcin     ierr = DMProjectCoordinates(*dm, fe);CHKERRQ(ierr);
1971066ea43fSLisandro Dalcin     ierr = PetscFEDestroy(&fe);CHKERRQ(ierr);
1972066ea43fSLisandro Dalcin   }
1973066ea43fSLisandro Dalcin 
19740598e1a2SLisandro Dalcin   ierr = PetscLogEventEnd(DMPLEX_CreateGmsh,*dm,NULL,NULL,NULL);CHKERRQ(ierr);
1975331830f3SMatthew G. Knepley   PetscFunctionReturn(0);
1976331830f3SMatthew G. Knepley }
1977