1 #define PETSCDM_DLL 2 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 3 #include <petsc/private/hashmapi.h> 4 5 #include <../src/dm/impls/plex/gmshlex.h> 6 7 #define GMSH_LEXORDER_ITEM(T, p) \ 8 static int *GmshLexOrder_##T##_##p(void) \ 9 { \ 10 static int Gmsh_LexOrder_##T##_##p[GmshNumNodes_##T(p)] = {-1}; \ 11 int *lex = Gmsh_LexOrder_##T##_##p; \ 12 if (lex[0] == -1) (void)GmshLexOrder_##T(p, lex, 0); \ 13 return lex; \ 14 } 15 16 static int *GmshLexOrder_QUA_2_Serendipity(void) 17 { 18 static int Gmsh_LexOrder_QUA_2_Serendipity[9] = {-1}; 19 int *lex = Gmsh_LexOrder_QUA_2_Serendipity; 20 if (lex[0] == -1) { 21 /* Vertices */ 22 lex[0] = 0; 23 lex[2] = 1; 24 lex[8] = 2; 25 lex[6] = 3; 26 /* Edges */ 27 lex[1] = 4; 28 lex[5] = 5; 29 lex[7] = 6; 30 lex[3] = 7; 31 /* Cell */ 32 lex[4] = -8; 33 } 34 return lex; 35 } 36 37 static int *GmshLexOrder_HEX_2_Serendipity(void) 38 { 39 static int Gmsh_LexOrder_HEX_2_Serendipity[27] = {-1}; 40 int *lex = Gmsh_LexOrder_HEX_2_Serendipity; 41 if (lex[0] == -1) { 42 /* Vertices */ 43 lex[0] = 0; 44 lex[2] = 1; 45 lex[8] = 2; 46 lex[6] = 3; 47 lex[18] = 4; 48 lex[20] = 5; 49 lex[26] = 6; 50 lex[24] = 7; 51 /* Edges */ 52 lex[1] = 8; 53 lex[3] = 9; 54 lex[9] = 10; 55 lex[5] = 11; 56 lex[11] = 12; 57 lex[7] = 13; 58 lex[17] = 14; 59 lex[15] = 15; 60 lex[19] = 16; 61 lex[21] = 17; 62 lex[23] = 18; 63 lex[25] = 19; 64 /* Faces */ 65 lex[4] = -20; 66 lex[10] = -21; 67 lex[12] = -22; 68 lex[14] = -23; 69 lex[16] = -24; 70 lex[22] = -25; 71 /* Cell */ 72 lex[13] = -26; 73 } 74 return lex; 75 } 76 77 #define GMSH_LEXORDER_LIST(T) \ 78 GMSH_LEXORDER_ITEM(T, 1) \ 79 GMSH_LEXORDER_ITEM(T, 2) \ 80 GMSH_LEXORDER_ITEM(T, 3) \ 81 GMSH_LEXORDER_ITEM(T, 4) \ 82 GMSH_LEXORDER_ITEM(T, 5) \ 83 GMSH_LEXORDER_ITEM(T, 6) \ 84 GMSH_LEXORDER_ITEM(T, 7) \ 85 GMSH_LEXORDER_ITEM(T, 8) \ 86 GMSH_LEXORDER_ITEM(T, 9) \ 87 GMSH_LEXORDER_ITEM(T, 10) 88 89 GMSH_LEXORDER_ITEM(VTX, 0) 90 GMSH_LEXORDER_LIST(SEG) 91 GMSH_LEXORDER_LIST(TRI) 92 GMSH_LEXORDER_LIST(QUA) 93 GMSH_LEXORDER_LIST(TET) 94 GMSH_LEXORDER_LIST(HEX) 95 GMSH_LEXORDER_LIST(PRI) 96 GMSH_LEXORDER_LIST(PYR) 97 98 typedef enum { 99 GMSH_VTX = 0, 100 GMSH_SEG = 1, 101 GMSH_TRI = 2, 102 GMSH_QUA = 3, 103 GMSH_TET = 4, 104 GMSH_HEX = 5, 105 GMSH_PRI = 6, 106 GMSH_PYR = 7, 107 GMSH_NUM_POLYTOPES = 8 108 } GmshPolytopeType; 109 110 typedef struct { 111 int cellType; 112 int polytope; 113 int dim; 114 int order; 115 int numVerts; 116 int numNodes; 117 int *(*lexorder)(void); 118 } GmshCellInfo; 119 120 // clang-format off 121 #define GmshCellEntry(cellType, polytope, dim, order) {cellType, GMSH_##polytope, dim, order, GmshNumNodes_##polytope(1), GmshNumNodes_##polytope(order), GmshLexOrder_##polytope##_##order} 122 // clang-format on 123 124 static const GmshCellInfo GmshCellTable[] = { 125 GmshCellEntry(15, VTX, 0, 0), 126 127 GmshCellEntry(1, SEG, 1, 1), GmshCellEntry(8, SEG, 1, 2), GmshCellEntry(26, SEG, 1, 3), 128 GmshCellEntry(27, SEG, 1, 4), GmshCellEntry(28, SEG, 1, 5), GmshCellEntry(62, SEG, 1, 6), 129 GmshCellEntry(63, SEG, 1, 7), GmshCellEntry(64, SEG, 1, 8), GmshCellEntry(65, SEG, 1, 9), 130 GmshCellEntry(66, SEG, 1, 10), 131 132 GmshCellEntry(2, TRI, 2, 1), GmshCellEntry(9, TRI, 2, 2), GmshCellEntry(21, TRI, 2, 3), 133 GmshCellEntry(23, TRI, 2, 4), GmshCellEntry(25, TRI, 2, 5), GmshCellEntry(42, TRI, 2, 6), 134 GmshCellEntry(43, TRI, 2, 7), GmshCellEntry(44, TRI, 2, 8), GmshCellEntry(45, TRI, 2, 9), 135 GmshCellEntry(46, TRI, 2, 10), 136 137 GmshCellEntry(3, QUA, 2, 1), GmshCellEntry(10, QUA, 2, 2), {16, GMSH_QUA, 2, 2, 4, 8, GmshLexOrder_QUA_2_Serendipity}, 138 GmshCellEntry(36, QUA, 2, 3), GmshCellEntry(37, QUA, 2, 4), GmshCellEntry(38, QUA, 2, 5), 139 GmshCellEntry(47, QUA, 2, 6), GmshCellEntry(48, QUA, 2, 7), GmshCellEntry(49, QUA, 2, 8), 140 GmshCellEntry(50, QUA, 2, 9), GmshCellEntry(51, QUA, 2, 10), 141 142 GmshCellEntry(4, TET, 3, 1), GmshCellEntry(11, TET, 3, 2), GmshCellEntry(29, TET, 3, 3), 143 GmshCellEntry(30, TET, 3, 4), GmshCellEntry(31, TET, 3, 5), GmshCellEntry(71, TET, 3, 6), 144 GmshCellEntry(72, TET, 3, 7), GmshCellEntry(73, TET, 3, 8), GmshCellEntry(74, TET, 3, 9), 145 GmshCellEntry(75, TET, 3, 10), 146 147 GmshCellEntry(5, HEX, 3, 1), GmshCellEntry(12, HEX, 3, 2), {17, GMSH_HEX, 3, 2, 8, 20, GmshLexOrder_HEX_2_Serendipity}, 148 GmshCellEntry(92, HEX, 3, 3), GmshCellEntry(93, HEX, 3, 4), GmshCellEntry(94, HEX, 3, 5), 149 GmshCellEntry(95, HEX, 3, 6), GmshCellEntry(96, HEX, 3, 7), GmshCellEntry(97, HEX, 3, 8), 150 GmshCellEntry(98, HEX, 3, 9), GmshCellEntry(-1, HEX, 3, 10), 151 152 GmshCellEntry(6, PRI, 3, 1), GmshCellEntry(13, PRI, 3, 2), GmshCellEntry(90, PRI, 3, 3), 153 GmshCellEntry(91, PRI, 3, 4), GmshCellEntry(106, PRI, 3, 5), GmshCellEntry(107, PRI, 3, 6), 154 GmshCellEntry(108, PRI, 3, 7), GmshCellEntry(109, PRI, 3, 8), GmshCellEntry(110, PRI, 3, 9), 155 GmshCellEntry(-1, PRI, 3, 10), 156 157 GmshCellEntry(7, PYR, 3, 1), GmshCellEntry(14, PYR, 3, 2), GmshCellEntry(118, PYR, 3, 3), 158 GmshCellEntry(119, PYR, 3, 4), GmshCellEntry(120, PYR, 3, 5), GmshCellEntry(121, PYR, 3, 6), 159 GmshCellEntry(122, PYR, 3, 7), GmshCellEntry(123, PYR, 3, 8), GmshCellEntry(124, PYR, 3, 9), 160 GmshCellEntry(-1, PYR, 3, 10) 161 162 #if 0 163 {20, GMSH_TRI, 2, 3, 3, 9, NULL}, 164 {18, GMSH_PRI, 3, 2, 6, 15, NULL}, 165 {19, GMSH_PYR, 3, 2, 5, 13, NULL}, 166 #endif 167 }; 168 169 static GmshCellInfo GmshCellMap[150]; 170 171 static PetscErrorCode GmshCellInfoSetUp(void) 172 { 173 size_t i, n; 174 static PetscBool called = PETSC_FALSE; 175 176 PetscFunctionBegin; 177 if (called) PetscFunctionReturn(PETSC_SUCCESS); 178 called = PETSC_TRUE; 179 n = PETSC_STATIC_ARRAY_LENGTH(GmshCellMap); 180 for (i = 0; i < n; ++i) { 181 GmshCellMap[i].cellType = -1; 182 GmshCellMap[i].polytope = -1; 183 } 184 n = PETSC_STATIC_ARRAY_LENGTH(GmshCellTable); 185 for (i = 0; i < n; ++i) { 186 if (GmshCellTable[i].cellType <= 0) continue; 187 GmshCellMap[GmshCellTable[i].cellType] = GmshCellTable[i]; 188 } 189 PetscFunctionReturn(PETSC_SUCCESS); 190 } 191 192 #define GmshCellTypeCheck(ct) \ 193 PetscMacroReturnStandard(const int _ct_ = (int)ct; PetscCheck(_ct_ >= 0 && _ct_ < (int)PETSC_STATIC_ARRAY_LENGTH(GmshCellMap), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid Gmsh element type %d", _ct_); PetscCheck(GmshCellMap[_ct_].cellType == _ct_, PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported Gmsh element type %d", _ct_); \ 194 PetscCheck(GmshCellMap[_ct_].polytope != -1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Unsupported Gmsh element type %d", _ct_);) 195 196 typedef struct { 197 PetscViewer viewer; 198 int fileFormat; 199 int dataSize; 200 PetscBool binary; 201 PetscBool byteSwap; 202 size_t wlen; 203 void *wbuf; 204 size_t slen; 205 void *sbuf; 206 PetscInt *nbuf; 207 PetscInt nodeStart; 208 PetscInt nodeEnd; 209 PetscInt *nodeMap; 210 } GmshFile; 211 212 static PetscErrorCode GmshBufferGet(GmshFile *gmsh, size_t count, size_t eltsize, void *buf) 213 { 214 size_t size = count * eltsize; 215 216 PetscFunctionBegin; 217 if (gmsh->wlen < size) { 218 PetscCall(PetscFree(gmsh->wbuf)); 219 PetscCall(PetscMalloc(size, &gmsh->wbuf)); 220 gmsh->wlen = size; 221 } 222 *(void **)buf = size ? gmsh->wbuf : NULL; 223 PetscFunctionReturn(PETSC_SUCCESS); 224 } 225 226 static PetscErrorCode GmshBufferSizeGet(GmshFile *gmsh, size_t count, void *buf) 227 { 228 size_t dataSize = (size_t)gmsh->dataSize; 229 size_t size = count * dataSize; 230 231 PetscFunctionBegin; 232 if (gmsh->slen < size) { 233 PetscCall(PetscFree(gmsh->sbuf)); 234 PetscCall(PetscMalloc(size, &gmsh->sbuf)); 235 gmsh->slen = size; 236 } 237 *(void **)buf = size ? gmsh->sbuf : NULL; 238 PetscFunctionReturn(PETSC_SUCCESS); 239 } 240 241 static PetscErrorCode GmshRead(GmshFile *gmsh, void *buf, PetscInt count, PetscDataType dtype) 242 { 243 PetscFunctionBegin; 244 PetscCall(PetscViewerRead(gmsh->viewer, buf, count, NULL, dtype)); 245 if (gmsh->byteSwap) PetscCall(PetscByteSwap(buf, dtype, count)); 246 PetscFunctionReturn(PETSC_SUCCESS); 247 } 248 249 static PetscErrorCode GmshReadString(GmshFile *gmsh, char *buf, PetscInt count) 250 { 251 PetscFunctionBegin; 252 PetscCall(PetscViewerRead(gmsh->viewer, buf, count, NULL, PETSC_STRING)); 253 PetscFunctionReturn(PETSC_SUCCESS); 254 } 255 256 static PetscErrorCode GmshMatch(PETSC_UNUSED GmshFile *gmsh, const char Section[], char line[PETSC_MAX_PATH_LEN], PetscBool *match) 257 { 258 PetscFunctionBegin; 259 PetscCall(PetscStrcmp(line, Section, match)); 260 PetscFunctionReturn(PETSC_SUCCESS); 261 } 262 263 static PetscErrorCode GmshExpect(GmshFile *gmsh, const char Section[], char line[PETSC_MAX_PATH_LEN]) 264 { 265 PetscBool match; 266 267 PetscFunctionBegin; 268 PetscCall(GmshMatch(gmsh, Section, line, &match)); 269 PetscCheck(match, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file, expecting %s, not %s", Section, line); 270 PetscFunctionReturn(PETSC_SUCCESS); 271 } 272 273 static PetscErrorCode GmshReadSection(GmshFile *gmsh, char line[PETSC_MAX_PATH_LEN]) 274 { 275 PetscBool match; 276 277 PetscFunctionBegin; 278 while (PETSC_TRUE) { 279 PetscCall(GmshReadString(gmsh, line, 1)); 280 PetscCall(GmshMatch(gmsh, "$Comments", line, &match)); 281 if (!match) break; 282 while (PETSC_TRUE) { 283 PetscCall(GmshReadString(gmsh, line, 1)); 284 PetscCall(GmshMatch(gmsh, "$EndComments", line, &match)); 285 if (match) break; 286 } 287 } 288 PetscFunctionReturn(PETSC_SUCCESS); 289 } 290 291 static PetscErrorCode GmshReadEndSection(GmshFile *gmsh, const char EndSection[], char line[PETSC_MAX_PATH_LEN]) 292 { 293 PetscFunctionBegin; 294 PetscCall(GmshReadString(gmsh, line, 1)); 295 PetscCall(GmshExpect(gmsh, EndSection, line)); 296 PetscFunctionReturn(PETSC_SUCCESS); 297 } 298 299 static PetscErrorCode GmshReadSize(GmshFile *gmsh, PetscInt *buf, PetscInt count) 300 { 301 PetscInt i; 302 size_t dataSize = (size_t)gmsh->dataSize; 303 304 PetscFunctionBegin; 305 if (dataSize == sizeof(PetscInt)) { 306 PetscCall(GmshRead(gmsh, buf, count, PETSC_INT)); 307 } else if (dataSize == sizeof(int)) { 308 int *ibuf = NULL; 309 PetscCall(GmshBufferSizeGet(gmsh, count, &ibuf)); 310 PetscCall(GmshRead(gmsh, ibuf, count, PETSC_ENUM)); 311 for (i = 0; i < count; ++i) buf[i] = (PetscInt)ibuf[i]; 312 } else if (dataSize == sizeof(long)) { 313 long *ibuf = NULL; 314 PetscCall(GmshBufferSizeGet(gmsh, count, &ibuf)); 315 PetscCall(GmshRead(gmsh, ibuf, count, PETSC_LONG)); 316 for (i = 0; i < count; ++i) buf[i] = (PetscInt)ibuf[i]; 317 } else if (dataSize == sizeof(PetscInt64)) { 318 PetscInt64 *ibuf = NULL; 319 PetscCall(GmshBufferSizeGet(gmsh, count, &ibuf)); 320 PetscCall(GmshRead(gmsh, ibuf, count, PETSC_INT64)); 321 for (i = 0; i < count; ++i) buf[i] = (PetscInt)ibuf[i]; 322 } 323 PetscFunctionReturn(PETSC_SUCCESS); 324 } 325 326 static PetscErrorCode GmshReadInt(GmshFile *gmsh, int *buf, PetscInt count) 327 { 328 PetscFunctionBegin; 329 PetscCall(GmshRead(gmsh, buf, count, PETSC_ENUM)); 330 PetscFunctionReturn(PETSC_SUCCESS); 331 } 332 333 static PetscErrorCode GmshReadDouble(GmshFile *gmsh, double *buf, PetscInt count) 334 { 335 PetscFunctionBegin; 336 PetscCall(GmshRead(gmsh, buf, count, PETSC_DOUBLE)); 337 PetscFunctionReturn(PETSC_SUCCESS); 338 } 339 340 #define GMSH_MAX_TAGS 16 341 342 typedef struct { 343 PetscInt id; /* Entity ID */ 344 PetscInt dim; /* Dimension */ 345 double bbox[6]; /* Bounding box */ 346 PetscInt numTags; /* Size of tag array */ 347 int tags[GMSH_MAX_TAGS]; /* Tag array */ 348 } GmshEntity; 349 350 typedef struct { 351 GmshEntity *entity[4]; 352 PetscHMapI entityMap[4]; 353 } GmshEntities; 354 355 static PetscErrorCode GmshEntitiesCreate(PetscInt count[4], GmshEntities **entities) 356 { 357 PetscInt dim; 358 359 PetscFunctionBegin; 360 PetscCall(PetscNew(entities)); 361 for (dim = 0; dim < 4; ++dim) { 362 PetscCall(PetscCalloc1(count[dim], &(*entities)->entity[dim])); 363 PetscCall(PetscHMapICreate(&(*entities)->entityMap[dim])); 364 } 365 PetscFunctionReturn(PETSC_SUCCESS); 366 } 367 368 static PetscErrorCode GmshEntitiesDestroy(GmshEntities **entities) 369 { 370 PetscInt dim; 371 372 PetscFunctionBegin; 373 if (!*entities) PetscFunctionReturn(PETSC_SUCCESS); 374 for (dim = 0; dim < 4; ++dim) { 375 PetscCall(PetscFree((*entities)->entity[dim])); 376 PetscCall(PetscHMapIDestroy(&(*entities)->entityMap[dim])); 377 } 378 PetscCall(PetscFree(*entities)); 379 PetscFunctionReturn(PETSC_SUCCESS); 380 } 381 382 static PetscErrorCode GmshEntitiesAdd(GmshEntities *entities, PetscInt index, PetscInt dim, PetscInt eid, GmshEntity **entity) 383 { 384 PetscFunctionBegin; 385 PetscCall(PetscHMapISet(entities->entityMap[dim], eid, index)); 386 entities->entity[dim][index].dim = dim; 387 entities->entity[dim][index].id = eid; 388 if (entity) *entity = &entities->entity[dim][index]; 389 PetscFunctionReturn(PETSC_SUCCESS); 390 } 391 392 static PetscErrorCode GmshEntitiesGet(GmshEntities *entities, PetscInt dim, PetscInt eid, GmshEntity **entity) 393 { 394 PetscInt index; 395 396 PetscFunctionBegin; 397 PetscCall(PetscHMapIGet(entities->entityMap[dim], eid, &index)); 398 *entity = &entities->entity[dim][index]; 399 PetscFunctionReturn(PETSC_SUCCESS); 400 } 401 402 typedef struct { 403 PetscInt *id; /* Node IDs */ 404 double *xyz; /* Coordinates */ 405 PetscInt *tag; /* Physical tag */ 406 } GmshNodes; 407 408 static PetscErrorCode GmshNodesCreate(PetscInt count, GmshNodes **nodes) 409 { 410 PetscFunctionBegin; 411 PetscCall(PetscNew(nodes)); 412 PetscCall(PetscMalloc1(count * 1, &(*nodes)->id)); 413 PetscCall(PetscMalloc1(count * 3, &(*nodes)->xyz)); 414 PetscCall(PetscMalloc1(count * GMSH_MAX_TAGS, &(*nodes)->tag)); 415 PetscFunctionReturn(PETSC_SUCCESS); 416 } 417 418 static PetscErrorCode GmshNodesDestroy(GmshNodes **nodes) 419 { 420 PetscFunctionBegin; 421 if (!*nodes) PetscFunctionReturn(PETSC_SUCCESS); 422 PetscCall(PetscFree((*nodes)->id)); 423 PetscCall(PetscFree((*nodes)->xyz)); 424 PetscCall(PetscFree((*nodes)->tag)); 425 PetscCall(PetscFree(*nodes)); 426 PetscFunctionReturn(PETSC_SUCCESS); 427 } 428 429 typedef struct { 430 PetscInt id; /* Element ID */ 431 PetscInt dim; /* Dimension */ 432 PetscInt cellType; /* Cell type */ 433 PetscInt numVerts; /* Size of vertex array */ 434 PetscInt numNodes; /* Size of node array */ 435 PetscInt *nodes; /* Vertex/Node array */ 436 PetscInt numTags; /* Size of physical tag array */ 437 int tags[GMSH_MAX_TAGS]; /* Physical tag array */ 438 } GmshElement; 439 440 static PetscErrorCode GmshElementsCreate(PetscInt count, GmshElement **elements) 441 { 442 PetscFunctionBegin; 443 PetscCall(PetscCalloc1(count, elements)); 444 PetscFunctionReturn(PETSC_SUCCESS); 445 } 446 447 static PetscErrorCode GmshElementsDestroy(GmshElement **elements) 448 { 449 PetscFunctionBegin; 450 if (!*elements) PetscFunctionReturn(PETSC_SUCCESS); 451 PetscCall(PetscFree(*elements)); 452 PetscFunctionReturn(PETSC_SUCCESS); 453 } 454 455 typedef struct { 456 PetscInt dim; 457 PetscInt order; 458 GmshEntities *entities; 459 PetscInt numNodes; 460 GmshNodes *nodelist; 461 PetscInt numElems; 462 GmshElement *elements; 463 PetscInt numVerts; 464 PetscInt numCells; 465 PetscInt *periodMap; 466 PetscInt *vertexMap; 467 PetscSegBuffer segbuf; 468 PetscInt numRegions; 469 PetscInt *regionDims; 470 PetscInt *regionTags; 471 char **regionNames; 472 } GmshMesh; 473 474 static PetscErrorCode GmshMeshCreate(GmshMesh **mesh) 475 { 476 PetscFunctionBegin; 477 PetscCall(PetscNew(mesh)); 478 PetscCall(PetscSegBufferCreate(sizeof(PetscInt), 0, &(*mesh)->segbuf)); 479 PetscFunctionReturn(PETSC_SUCCESS); 480 } 481 482 static PetscErrorCode GmshMeshDestroy(GmshMesh **mesh) 483 { 484 PetscInt r; 485 486 PetscFunctionBegin; 487 if (!*mesh) PetscFunctionReturn(PETSC_SUCCESS); 488 PetscCall(GmshEntitiesDestroy(&(*mesh)->entities)); 489 PetscCall(GmshNodesDestroy(&(*mesh)->nodelist)); 490 PetscCall(GmshElementsDestroy(&(*mesh)->elements)); 491 PetscCall(PetscFree((*mesh)->periodMap)); 492 PetscCall(PetscFree((*mesh)->vertexMap)); 493 PetscCall(PetscSegBufferDestroy(&(*mesh)->segbuf)); 494 for (r = 0; r < (*mesh)->numRegions; ++r) PetscCall(PetscFree((*mesh)->regionNames[r])); 495 PetscCall(PetscFree3((*mesh)->regionDims, (*mesh)->regionTags, (*mesh)->regionNames)); 496 PetscCall(PetscFree(*mesh)); 497 PetscFunctionReturn(PETSC_SUCCESS); 498 } 499 500 static PetscErrorCode GmshReadNodes_v22(GmshFile *gmsh, GmshMesh *mesh) 501 { 502 PetscViewer viewer = gmsh->viewer; 503 PetscBool byteSwap = gmsh->byteSwap; 504 char line[PETSC_MAX_PATH_LEN]; 505 int n, t, num, nid, snum; 506 GmshNodes *nodes; 507 508 PetscFunctionBegin; 509 PetscCall(PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING)); 510 snum = sscanf(line, "%d", &num); 511 PetscCheck(snum == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file"); 512 PetscCall(GmshNodesCreate(num, &nodes)); 513 mesh->numNodes = num; 514 mesh->nodelist = nodes; 515 for (n = 0; n < num; ++n) { 516 double *xyz = nodes->xyz + n * 3; 517 PetscCall(PetscViewerRead(viewer, &nid, 1, NULL, PETSC_ENUM)); 518 PetscCall(PetscViewerRead(viewer, xyz, 3, NULL, PETSC_DOUBLE)); 519 if (byteSwap) PetscCall(PetscByteSwap(&nid, PETSC_ENUM, 1)); 520 if (byteSwap) PetscCall(PetscByteSwap(xyz, PETSC_DOUBLE, 3)); 521 nodes->id[n] = nid; 522 for (t = 0; t < GMSH_MAX_TAGS; ++t) nodes->tag[n * GMSH_MAX_TAGS + t] = -1; 523 } 524 PetscFunctionReturn(PETSC_SUCCESS); 525 } 526 527 /* Gmsh elements can be of any dimension/co-dimension, so we need to traverse the 528 file contents multiple times to figure out the true number of cells and facets 529 in the given mesh. To make this more efficient we read the file contents only 530 once and store them in memory, while determining the true number of cells. */ 531 static PetscErrorCode GmshReadElements_v22(GmshFile *gmsh, GmshMesh *mesh) 532 { 533 PetscViewer viewer = gmsh->viewer; 534 PetscBool binary = gmsh->binary; 535 PetscBool byteSwap = gmsh->byteSwap; 536 char line[PETSC_MAX_PATH_LEN]; 537 int i, c, p, num, ibuf[1 + 4 + 1000], snum; 538 int cellType, numElem, numVerts, numNodes, numTags; 539 GmshElement *elements; 540 PetscInt *nodeMap = gmsh->nodeMap; 541 542 PetscFunctionBegin; 543 PetscCall(PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING)); 544 snum = sscanf(line, "%d", &num); 545 PetscCheck(snum == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file"); 546 PetscCall(GmshElementsCreate(num, &elements)); 547 mesh->numElems = num; 548 mesh->elements = elements; 549 for (c = 0; c < num;) { 550 PetscCall(PetscViewerRead(viewer, ibuf, 3, NULL, PETSC_ENUM)); 551 if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, 3)); 552 553 cellType = binary ? ibuf[0] : ibuf[1]; 554 numElem = binary ? ibuf[1] : 1; 555 numTags = ibuf[2]; 556 557 PetscCall(GmshCellTypeCheck(cellType)); 558 numVerts = GmshCellMap[cellType].numVerts; 559 numNodes = GmshCellMap[cellType].numNodes; 560 561 for (i = 0; i < numElem; ++i, ++c) { 562 GmshElement *element = elements + c; 563 const int off = binary ? 0 : 1, nint = 1 + numTags + numNodes - off; 564 const int *id = ibuf, *nodes = ibuf + 1 + numTags, *tags = ibuf + 1; 565 PetscCall(PetscViewerRead(viewer, ibuf + off, nint, NULL, PETSC_ENUM)); 566 if (byteSwap) PetscCall(PetscByteSwap(ibuf + off, PETSC_ENUM, nint)); 567 element->id = id[0]; 568 element->dim = GmshCellMap[cellType].dim; 569 element->cellType = cellType; 570 element->numVerts = numVerts; 571 element->numNodes = numNodes; 572 element->numTags = PetscMin(numTags, GMSH_MAX_TAGS); 573 PetscCall(PetscSegBufferGet(mesh->segbuf, (size_t)element->numNodes, &element->nodes)); 574 for (p = 0; p < element->numNodes; p++) element->nodes[p] = nodeMap[nodes[p]]; 575 for (p = 0; p < element->numTags; p++) element->tags[p] = tags[p]; 576 } 577 } 578 PetscFunctionReturn(PETSC_SUCCESS); 579 } 580 581 /* 582 $Entities 583 numPoints(unsigned long) numCurves(unsigned long) 584 numSurfaces(unsigned long) numVolumes(unsigned long) 585 // points 586 tag(int) boxMinX(double) boxMinY(double) boxMinZ(double) 587 boxMaxX(double) boxMaxY(double) boxMaxZ(double) 588 numPhysicals(unsigned long) phyisicalTag[...](int) 589 ... 590 // curves 591 tag(int) boxMinX(double) boxMinY(double) boxMinZ(double) 592 boxMaxX(double) boxMaxY(double) boxMaxZ(double) 593 numPhysicals(unsigned long) physicalTag[...](int) 594 numBREPVert(unsigned long) tagBREPVert[...](int) 595 ... 596 // surfaces 597 tag(int) boxMinX(double) boxMinY(double) boxMinZ(double) 598 boxMaxX(double) boxMaxY(double) boxMaxZ(double) 599 numPhysicals(unsigned long) physicalTag[...](int) 600 numBREPCurve(unsigned long) tagBREPCurve[...](int) 601 ... 602 // volumes 603 tag(int) boxMinX(double) boxMinY(double) boxMinZ(double) 604 boxMaxX(double) boxMaxY(double) boxMaxZ(double) 605 numPhysicals(unsigned long) physicalTag[...](int) 606 numBREPSurfaces(unsigned long) tagBREPSurfaces[...](int) 607 ... 608 $EndEntities 609 */ 610 static PetscErrorCode GmshReadEntities_v40(GmshFile *gmsh, GmshMesh *mesh) 611 { 612 PetscViewer viewer = gmsh->viewer; 613 PetscBool byteSwap = gmsh->byteSwap; 614 long index, num, lbuf[4]; 615 int dim, eid, numTags, *ibuf, t; 616 PetscInt count[4], i; 617 GmshEntity *entity = NULL; 618 619 PetscFunctionBegin; 620 PetscCall(PetscViewerRead(viewer, lbuf, 4, NULL, PETSC_LONG)); 621 if (byteSwap) PetscCall(PetscByteSwap(lbuf, PETSC_LONG, 4)); 622 for (i = 0; i < 4; ++i) count[i] = lbuf[i]; 623 PetscCall(GmshEntitiesCreate(count, &mesh->entities)); 624 for (dim = 0; dim < 4; ++dim) { 625 for (index = 0; index < count[dim]; ++index) { 626 PetscCall(PetscViewerRead(viewer, &eid, 1, NULL, PETSC_ENUM)); 627 if (byteSwap) PetscCall(PetscByteSwap(&eid, PETSC_ENUM, 1)); 628 PetscCall(GmshEntitiesAdd(mesh->entities, (PetscInt)index, dim, eid, &entity)); 629 PetscCall(PetscViewerRead(viewer, entity->bbox, 6, NULL, PETSC_DOUBLE)); 630 if (byteSwap) PetscCall(PetscByteSwap(entity->bbox, PETSC_DOUBLE, 6)); 631 PetscCall(PetscViewerRead(viewer, &num, 1, NULL, PETSC_LONG)); 632 if (byteSwap) PetscCall(PetscByteSwap(&num, PETSC_LONG, 1)); 633 PetscCall(GmshBufferGet(gmsh, num, sizeof(int), &ibuf)); 634 PetscCall(PetscViewerRead(viewer, ibuf, num, NULL, PETSC_ENUM)); 635 if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, num)); 636 entity->numTags = numTags = (int)PetscMin(num, GMSH_MAX_TAGS); 637 for (t = 0; t < numTags; ++t) entity->tags[t] = ibuf[t]; 638 if (dim == 0) continue; 639 PetscCall(PetscViewerRead(viewer, &num, 1, NULL, PETSC_LONG)); 640 if (byteSwap) PetscCall(PetscByteSwap(&num, PETSC_LONG, 1)); 641 PetscCall(GmshBufferGet(gmsh, num, sizeof(int), &ibuf)); 642 PetscCall(PetscViewerRead(viewer, ibuf, num, NULL, PETSC_ENUM)); 643 if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, num)); 644 } 645 } 646 PetscFunctionReturn(PETSC_SUCCESS); 647 } 648 649 /* 650 $Nodes 651 numEntityBlocks(unsigned long) numNodes(unsigned long) 652 tagEntity(int) dimEntity(int) typeNode(int) numNodes(unsigned long) 653 tag(int) x(double) y(double) z(double) 654 ... 655 ... 656 $EndNodes 657 */ 658 static PetscErrorCode GmshReadNodes_v40(GmshFile *gmsh, GmshMesh *mesh) 659 { 660 PetscViewer viewer = gmsh->viewer; 661 PetscBool byteSwap = gmsh->byteSwap; 662 long block, node, n, t, numEntityBlocks, numTotalNodes, numNodes; 663 int info[3], nid; 664 GmshNodes *nodes; 665 666 PetscFunctionBegin; 667 PetscCall(PetscViewerRead(viewer, &numEntityBlocks, 1, NULL, PETSC_LONG)); 668 if (byteSwap) PetscCall(PetscByteSwap(&numEntityBlocks, PETSC_LONG, 1)); 669 PetscCall(PetscViewerRead(viewer, &numTotalNodes, 1, NULL, PETSC_LONG)); 670 if (byteSwap) PetscCall(PetscByteSwap(&numTotalNodes, PETSC_LONG, 1)); 671 PetscCall(GmshNodesCreate(numTotalNodes, &nodes)); 672 mesh->numNodes = numTotalNodes; 673 mesh->nodelist = nodes; 674 for (n = 0, block = 0; block < numEntityBlocks; ++block) { 675 PetscCall(PetscViewerRead(viewer, info, 3, NULL, PETSC_ENUM)); 676 PetscCall(PetscViewerRead(viewer, &numNodes, 1, NULL, PETSC_LONG)); 677 if (byteSwap) PetscCall(PetscByteSwap(&numNodes, PETSC_LONG, 1)); 678 if (gmsh->binary) { 679 size_t nbytes = sizeof(int) + 3 * sizeof(double); 680 char *cbuf = NULL; /* dummy value to prevent warning from compiler about possible uninitialized value */ 681 PetscCall(GmshBufferGet(gmsh, numNodes, nbytes, &cbuf)); 682 PetscCall(PetscViewerRead(viewer, cbuf, numNodes * nbytes, NULL, PETSC_CHAR)); 683 for (node = 0; node < numNodes; ++node, ++n) { 684 char *cnid = cbuf + node * nbytes, *cxyz = cnid + sizeof(int); 685 double *xyz = nodes->xyz + n * 3; 686 if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(cnid, PETSC_ENUM, 1)); 687 if (!PetscBinaryBigEndian()) PetscCall(PetscByteSwap(cxyz, PETSC_DOUBLE, 3)); 688 PetscCall(PetscMemcpy(&nid, cnid, sizeof(int))); 689 PetscCall(PetscMemcpy(xyz, cxyz, 3 * sizeof(double))); 690 if (byteSwap) PetscCall(PetscByteSwap(&nid, PETSC_ENUM, 1)); 691 if (byteSwap) PetscCall(PetscByteSwap(xyz, PETSC_DOUBLE, 3)); 692 nodes->id[n] = nid; 693 for (t = 0; t < GMSH_MAX_TAGS; ++t) nodes->tag[n * GMSH_MAX_TAGS + t] = -1; 694 } 695 } else { 696 for (node = 0; node < numNodes; ++node, ++n) { 697 double *xyz = nodes->xyz + n * 3; 698 PetscCall(PetscViewerRead(viewer, &nid, 1, NULL, PETSC_ENUM)); 699 PetscCall(PetscViewerRead(viewer, xyz, 3, NULL, PETSC_DOUBLE)); 700 if (byteSwap) PetscCall(PetscByteSwap(&nid, PETSC_ENUM, 1)); 701 if (byteSwap) PetscCall(PetscByteSwap(xyz, PETSC_DOUBLE, 3)); 702 nodes->id[n] = nid; 703 for (t = 0; t < GMSH_MAX_TAGS; ++t) nodes->tag[n * GMSH_MAX_TAGS + t] = -1; 704 } 705 } 706 } 707 PetscFunctionReturn(PETSC_SUCCESS); 708 } 709 710 /* 711 $Elements 712 numEntityBlocks(unsigned long) numElements(unsigned long) 713 tagEntity(int) dimEntity(int) typeEle(int) numElements(unsigned long) 714 tag(int) numVert[...](int) 715 ... 716 ... 717 $EndElements 718 */ 719 static PetscErrorCode GmshReadElements_v40(GmshFile *gmsh, GmshMesh *mesh) 720 { 721 PetscViewer viewer = gmsh->viewer; 722 PetscBool byteSwap = gmsh->byteSwap; 723 long c, block, numEntityBlocks, numTotalElements, elem, numElements; 724 int p, info[3], *ibuf = NULL; 725 int eid, dim, cellType, numVerts, numNodes, numTags; 726 GmshEntity *entity = NULL; 727 GmshElement *elements; 728 PetscInt *nodeMap = gmsh->nodeMap; 729 730 PetscFunctionBegin; 731 PetscCall(PetscViewerRead(viewer, &numEntityBlocks, 1, NULL, PETSC_LONG)); 732 if (byteSwap) PetscCall(PetscByteSwap(&numEntityBlocks, PETSC_LONG, 1)); 733 PetscCall(PetscViewerRead(viewer, &numTotalElements, 1, NULL, PETSC_LONG)); 734 if (byteSwap) PetscCall(PetscByteSwap(&numTotalElements, PETSC_LONG, 1)); 735 PetscCall(GmshElementsCreate(numTotalElements, &elements)); 736 mesh->numElems = numTotalElements; 737 mesh->elements = elements; 738 for (c = 0, block = 0; block < numEntityBlocks; ++block) { 739 PetscCall(PetscViewerRead(viewer, info, 3, NULL, PETSC_ENUM)); 740 if (byteSwap) PetscCall(PetscByteSwap(info, PETSC_ENUM, 3)); 741 eid = info[0]; 742 dim = info[1]; 743 cellType = info[2]; 744 PetscCall(GmshEntitiesGet(mesh->entities, dim, eid, &entity)); 745 PetscCall(GmshCellTypeCheck(cellType)); 746 numVerts = GmshCellMap[cellType].numVerts; 747 numNodes = GmshCellMap[cellType].numNodes; 748 numTags = entity->numTags; 749 PetscCall(PetscViewerRead(viewer, &numElements, 1, NULL, PETSC_LONG)); 750 if (byteSwap) PetscCall(PetscByteSwap(&numElements, PETSC_LONG, 1)); 751 PetscCall(GmshBufferGet(gmsh, (1 + numNodes) * numElements, sizeof(int), &ibuf)); 752 PetscCall(PetscViewerRead(viewer, ibuf, (1 + numNodes) * numElements, NULL, PETSC_ENUM)); 753 if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, (1 + numNodes) * numElements)); 754 for (elem = 0; elem < numElements; ++elem, ++c) { 755 GmshElement *element = elements + c; 756 const int *id = ibuf + elem * (1 + numNodes), *nodes = id + 1; 757 element->id = id[0]; 758 element->dim = dim; 759 element->cellType = cellType; 760 element->numVerts = numVerts; 761 element->numNodes = numNodes; 762 element->numTags = numTags; 763 PetscCall(PetscSegBufferGet(mesh->segbuf, (size_t)element->numNodes, &element->nodes)); 764 for (p = 0; p < element->numNodes; p++) element->nodes[p] = nodeMap[nodes[p]]; 765 for (p = 0; p < element->numTags; p++) element->tags[p] = entity->tags[p]; 766 } 767 } 768 PetscFunctionReturn(PETSC_SUCCESS); 769 } 770 771 static PetscErrorCode GmshReadPeriodic_v40(GmshFile *gmsh, PetscInt periodicMap[]) 772 { 773 PetscViewer viewer = gmsh->viewer; 774 int fileFormat = gmsh->fileFormat; 775 PetscBool binary = gmsh->binary; 776 PetscBool byteSwap = gmsh->byteSwap; 777 int numPeriodic, snum, i; 778 char line[PETSC_MAX_PATH_LEN]; 779 PetscInt *nodeMap = gmsh->nodeMap; 780 781 PetscFunctionBegin; 782 if (fileFormat == 22 || !binary) { 783 PetscCall(PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING)); 784 snum = sscanf(line, "%d", &numPeriodic); 785 PetscCheck(snum == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file"); 786 } else { 787 PetscCall(PetscViewerRead(viewer, &numPeriodic, 1, NULL, PETSC_ENUM)); 788 if (byteSwap) PetscCall(PetscByteSwap(&numPeriodic, PETSC_ENUM, 1)); 789 } 790 for (i = 0; i < numPeriodic; i++) { 791 int ibuf[3], correspondingDim = -1, correspondingTag = -1, primaryTag = -1, correspondingNode, primaryNode; 792 long j, nNodes; 793 double affine[16]; 794 795 if (fileFormat == 22 || !binary) { 796 PetscCall(PetscViewerRead(viewer, line, 3, NULL, PETSC_STRING)); 797 snum = sscanf(line, "%d %d %d", &correspondingDim, &correspondingTag, &primaryTag); 798 PetscCheck(snum == 3, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file"); 799 } else { 800 PetscCall(PetscViewerRead(viewer, ibuf, 3, NULL, PETSC_ENUM)); 801 if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, 3)); 802 correspondingDim = ibuf[0]; 803 correspondingTag = ibuf[1]; 804 primaryTag = ibuf[2]; 805 } 806 (void)correspondingDim; 807 (void)correspondingTag; 808 (void)primaryTag; /* unused */ 809 810 if (fileFormat == 22 || !binary) { 811 PetscCall(PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING)); 812 snum = sscanf(line, "%ld", &nNodes); 813 if (snum != 1) { /* discard transformation and try again */ 814 PetscCall(PetscViewerRead(viewer, line, -PETSC_MAX_PATH_LEN, NULL, PETSC_STRING)); 815 PetscCall(PetscViewerRead(viewer, line, 1, NULL, PETSC_STRING)); 816 snum = sscanf(line, "%ld", &nNodes); 817 PetscCheck(snum == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file"); 818 } 819 } else { 820 PetscCall(PetscViewerRead(viewer, &nNodes, 1, NULL, PETSC_LONG)); 821 if (byteSwap) PetscCall(PetscByteSwap(&nNodes, PETSC_LONG, 1)); 822 if (nNodes == -1) { /* discard transformation and try again */ 823 PetscCall(PetscViewerRead(viewer, affine, 16, NULL, PETSC_DOUBLE)); 824 PetscCall(PetscViewerRead(viewer, &nNodes, 1, NULL, PETSC_LONG)); 825 if (byteSwap) PetscCall(PetscByteSwap(&nNodes, PETSC_LONG, 1)); 826 } 827 } 828 829 for (j = 0; j < nNodes; j++) { 830 if (fileFormat == 22 || !binary) { 831 PetscCall(PetscViewerRead(viewer, line, 2, NULL, PETSC_STRING)); 832 snum = sscanf(line, "%d %d", &correspondingNode, &primaryNode); 833 PetscCheck(snum == 2, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file"); 834 } else { 835 PetscCall(PetscViewerRead(viewer, ibuf, 2, NULL, PETSC_ENUM)); 836 if (byteSwap) PetscCall(PetscByteSwap(ibuf, PETSC_ENUM, 2)); 837 correspondingNode = ibuf[0]; 838 primaryNode = ibuf[1]; 839 } 840 correspondingNode = (int)nodeMap[correspondingNode]; 841 primaryNode = (int)nodeMap[primaryNode]; 842 periodicMap[correspondingNode] = primaryNode; 843 } 844 } 845 PetscFunctionReturn(PETSC_SUCCESS); 846 } 847 848 /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format 849 $Entities 850 numPoints(size_t) numCurves(size_t) 851 numSurfaces(size_t) numVolumes(size_t) 852 pointTag(int) X(double) Y(double) Z(double) 853 numPhysicalTags(size_t) physicalTag(int) ... 854 ... 855 curveTag(int) minX(double) minY(double) minZ(double) 856 maxX(double) maxY(double) maxZ(double) 857 numPhysicalTags(size_t) physicalTag(int) ... 858 numBoundingPoints(size_t) pointTag(int) ... 859 ... 860 surfaceTag(int) minX(double) minY(double) minZ(double) 861 maxX(double) maxY(double) maxZ(double) 862 numPhysicalTags(size_t) physicalTag(int) ... 863 numBoundingCurves(size_t) curveTag(int) ... 864 ... 865 volumeTag(int) minX(double) minY(double) minZ(double) 866 maxX(double) maxY(double) maxZ(double) 867 numPhysicalTags(size_t) physicalTag(int) ... 868 numBoundngSurfaces(size_t) surfaceTag(int) ... 869 ... 870 $EndEntities 871 */ 872 static PetscErrorCode GmshReadEntities_v41(GmshFile *gmsh, GmshMesh *mesh) 873 { 874 PetscInt count[4], index, numTags, i; 875 int dim, eid, *tags = NULL; 876 GmshEntity *entity = NULL; 877 878 PetscFunctionBegin; 879 PetscCall(GmshReadSize(gmsh, count, 4)); 880 PetscCall(GmshEntitiesCreate(count, &mesh->entities)); 881 for (dim = 0; dim < 4; ++dim) { 882 for (index = 0; index < count[dim]; ++index) { 883 PetscCall(GmshReadInt(gmsh, &eid, 1)); 884 PetscCall(GmshEntitiesAdd(mesh->entities, (PetscInt)index, dim, eid, &entity)); 885 PetscCall(GmshReadDouble(gmsh, entity->bbox, (dim == 0) ? 3 : 6)); 886 PetscCall(GmshReadSize(gmsh, &numTags, 1)); 887 PetscCall(GmshBufferGet(gmsh, numTags, sizeof(int), &tags)); 888 PetscCall(GmshReadInt(gmsh, tags, numTags)); 889 PetscCheck(numTags <= GMSH_MAX_TAGS, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "PETSc currently supports up to %" PetscInt_FMT " tags per entity, not %" PetscInt_FMT, (PetscInt)GMSH_MAX_TAGS, numTags); 890 entity->numTags = numTags; 891 for (i = 0; i < entity->numTags; ++i) entity->tags[i] = tags[i]; 892 if (dim == 0) continue; 893 PetscCall(GmshReadSize(gmsh, &numTags, 1)); 894 PetscCall(GmshBufferGet(gmsh, numTags, sizeof(int), &tags)); 895 PetscCall(GmshReadInt(gmsh, tags, numTags)); 896 /* Currently, we do not save the ids for the bounding entities */ 897 } 898 } 899 PetscFunctionReturn(PETSC_SUCCESS); 900 } 901 902 /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format 903 $Nodes 904 numEntityBlocks(size_t) numNodes(size_t) 905 minNodeTag(size_t) maxNodeTag(size_t) 906 entityDim(int) entityTag(int) parametric(int; 0 or 1) numNodesBlock(size_t) 907 nodeTag(size_t) 908 ... 909 x(double) y(double) z(double) 910 < u(double; if parametric and entityDim = 1 or entityDim = 2) > 911 < v(double; if parametric and entityDim = 2) > 912 ... 913 ... 914 $EndNodes 915 */ 916 static PetscErrorCode GmshReadNodes_v41(GmshFile *gmsh, GmshMesh *mesh) 917 { 918 int info[3], dim, eid, parametric; 919 PetscInt sizes[4], numEntityBlocks, numTags, t, numNodes, numNodesBlock = 0, block, node, n; 920 GmshEntity *entity = NULL; 921 GmshNodes *nodes; 922 923 PetscFunctionBegin; 924 PetscCall(GmshReadSize(gmsh, sizes, 4)); 925 numEntityBlocks = sizes[0]; 926 numNodes = sizes[1]; 927 PetscCall(GmshNodesCreate(numNodes, &nodes)); 928 mesh->numNodes = numNodes; 929 mesh->nodelist = nodes; 930 if (numEntityBlocks && !mesh->entities) PetscCall(PetscInfo(NULL, "File specifies %" PetscInt_FMT " entity blocks, but was missing the $Entities section\n", numEntityBlocks)); 931 for (block = 0, node = 0; block < numEntityBlocks; ++block, node += numNodesBlock) { 932 PetscCall(GmshReadInt(gmsh, info, 3)); 933 dim = info[0]; 934 eid = info[1]; 935 parametric = info[2]; 936 if (mesh->entities) PetscCall(GmshEntitiesGet(mesh->entities, dim, eid, &entity)); 937 numTags = entity ? entity->numTags : 0; 938 PetscCheck(!parametric, PETSC_COMM_SELF, PETSC_ERR_SUP, "Parametric coordinates not supported"); 939 PetscCall(GmshReadSize(gmsh, &numNodesBlock, 1)); 940 PetscCall(GmshReadSize(gmsh, nodes->id + node, numNodesBlock)); 941 PetscCall(GmshReadDouble(gmsh, nodes->xyz + node * 3, numNodesBlock * 3)); 942 for (n = 0; n < numNodesBlock; ++n) { 943 PetscInt *tags = &nodes->tag[node * GMSH_MAX_TAGS]; 944 945 for (t = 0; t < numTags; ++t) tags[n * GMSH_MAX_TAGS + t] = entity->tags[t]; 946 for (t = numTags; t < GMSH_MAX_TAGS; ++t) tags[n * GMSH_MAX_TAGS + t] = -1; 947 } 948 } 949 gmsh->nodeStart = sizes[2]; 950 gmsh->nodeEnd = sizes[3] + 1; 951 PetscFunctionReturn(PETSC_SUCCESS); 952 } 953 954 /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format 955 $Elements 956 numEntityBlocks(size_t) numElements(size_t) 957 minElementTag(size_t) maxElementTag(size_t) 958 entityDim(int) entityTag(int) elementType(int; see below) numElementsBlock(size_t) 959 elementTag(size_t) nodeTag(size_t) ... 960 ... 961 ... 962 $EndElements 963 */ 964 static PetscErrorCode GmshReadElements_v41(GmshFile *gmsh, GmshMesh *mesh) 965 { 966 int info[3], eid, dim, cellType; 967 PetscInt sizes[4], *ibuf = NULL, numEntityBlocks, numElements, numBlockElements, numVerts, numNodes, numTags, block, elem, c, p; 968 GmshEntity *entity = NULL; 969 GmshElement *elements; 970 PetscInt *nodeMap = gmsh->nodeMap; 971 972 PetscFunctionBegin; 973 PetscCall(GmshReadSize(gmsh, sizes, 4)); 974 numEntityBlocks = sizes[0]; 975 numElements = sizes[1]; 976 PetscCall(GmshElementsCreate(numElements, &elements)); 977 mesh->numElems = numElements; 978 mesh->elements = elements; 979 if (numEntityBlocks && !mesh->entities) PetscCall(PetscInfo(NULL, "File specifies %" PetscInt_FMT " entity blocks, but was missing the $Entities section\n", numEntityBlocks)); 980 for (c = 0, block = 0; block < numEntityBlocks; ++block) { 981 PetscCall(GmshReadInt(gmsh, info, 3)); 982 dim = info[0]; 983 eid = info[1]; 984 cellType = info[2]; 985 if (mesh->entities) PetscCall(GmshEntitiesGet(mesh->entities, dim, eid, &entity)); 986 PetscCall(GmshCellTypeCheck(cellType)); 987 numVerts = GmshCellMap[cellType].numVerts; 988 numNodes = GmshCellMap[cellType].numNodes; 989 numTags = entity ? entity->numTags : 0; 990 PetscCall(GmshReadSize(gmsh, &numBlockElements, 1)); 991 PetscCall(GmshBufferGet(gmsh, (1 + numNodes) * numBlockElements, sizeof(PetscInt), &ibuf)); 992 PetscCall(GmshReadSize(gmsh, ibuf, (1 + numNodes) * numBlockElements)); 993 for (elem = 0; elem < numBlockElements; ++elem, ++c) { 994 GmshElement *element = elements + c; 995 const PetscInt *id = ibuf + elem * (1 + numNodes), *nodes = id + 1; 996 element->id = id[0]; 997 element->dim = dim; 998 element->cellType = cellType; 999 element->numVerts = numVerts; 1000 element->numNodes = numNodes; 1001 element->numTags = numTags; 1002 PetscCall(PetscSegBufferGet(mesh->segbuf, (size_t)element->numNodes, &element->nodes)); 1003 for (p = 0; p < element->numNodes; p++) element->nodes[p] = nodeMap[nodes[p]]; 1004 for (p = 0; p < element->numTags; p++) element->tags[p] = entity->tags[p]; 1005 } 1006 } 1007 PetscFunctionReturn(PETSC_SUCCESS); 1008 } 1009 1010 /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format 1011 $Periodic 1012 numPeriodicLinks(size_t) 1013 entityDim(int) entityTag(int) entityTagPrimary(int) 1014 numAffine(size_t) value(double) ... 1015 numCorrespondingNodes(size_t) 1016 nodeTag(size_t) nodeTagPrimary(size_t) 1017 ... 1018 ... 1019 $EndPeriodic 1020 */ 1021 static PetscErrorCode GmshReadPeriodic_v41(GmshFile *gmsh, PetscInt periodicMap[]) 1022 { 1023 int info[3]; 1024 double dbuf[16]; 1025 PetscInt numPeriodicLinks, numAffine, numCorrespondingNodes, *nodeTags = NULL, link, node; 1026 PetscInt *nodeMap = gmsh->nodeMap; 1027 1028 PetscFunctionBegin; 1029 PetscCall(GmshReadSize(gmsh, &numPeriodicLinks, 1)); 1030 for (link = 0; link < numPeriodicLinks; ++link) { 1031 PetscCall(GmshReadInt(gmsh, info, 3)); 1032 PetscCall(GmshReadSize(gmsh, &numAffine, 1)); 1033 PetscCall(GmshReadDouble(gmsh, dbuf, numAffine)); 1034 PetscCall(GmshReadSize(gmsh, &numCorrespondingNodes, 1)); 1035 PetscCall(GmshBufferGet(gmsh, numCorrespondingNodes, sizeof(PetscInt), &nodeTags)); 1036 PetscCall(GmshReadSize(gmsh, nodeTags, numCorrespondingNodes * 2)); 1037 for (node = 0; node < numCorrespondingNodes; ++node) { 1038 PetscInt correspondingNode = nodeMap[nodeTags[node * 2 + 0]]; 1039 PetscInt primaryNode = nodeMap[nodeTags[node * 2 + 1]]; 1040 periodicMap[correspondingNode] = primaryNode; 1041 } 1042 } 1043 PetscFunctionReturn(PETSC_SUCCESS); 1044 } 1045 1046 /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format 1047 $MeshFormat // same as MSH version 2 1048 version(ASCII double; currently 4.1) 1049 file-type(ASCII int; 0 for ASCII mode, 1 for binary mode) 1050 data-size(ASCII int; sizeof(size_t)) 1051 < int with value one; only in binary mode, to detect endianness > 1052 $EndMeshFormat 1053 */ 1054 static PetscErrorCode GmshReadMeshFormat(GmshFile *gmsh) 1055 { 1056 char line[PETSC_MAX_PATH_LEN]; 1057 int snum, fileType, fileFormat, dataSize, checkEndian; 1058 float version; 1059 1060 PetscFunctionBegin; 1061 PetscCall(GmshReadString(gmsh, line, 3)); 1062 snum = sscanf(line, "%f %d %d", &version, &fileType, &dataSize); 1063 fileFormat = (int)roundf(version * 10); 1064 PetscCheck(snum == 3, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to parse Gmsh file header: %s", line); 1065 PetscCheck(fileFormat >= 22, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at least 2.2", (double)version); 1066 PetscCheck((int)version != 3, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f not supported", (double)version); 1067 PetscCheck(fileFormat <= 41, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at most 4.1", (double)version); 1068 PetscCheck(!gmsh->binary || fileType, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Viewer is binary but Gmsh file is ASCII"); 1069 PetscCheck(gmsh->binary || !fileType, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Viewer is ASCII but Gmsh file is binary"); 1070 PetscCheck(fileFormat > 40 || dataSize == sizeof(double), PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Data size %d is not valid for a Gmsh file", dataSize); 1071 PetscCheck(fileFormat < 41 || dataSize == sizeof(int) || dataSize == sizeof(PetscInt64), PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Data size %d is not valid for a Gmsh file", dataSize); 1072 gmsh->fileFormat = fileFormat; 1073 gmsh->dataSize = dataSize; 1074 gmsh->byteSwap = PETSC_FALSE; 1075 if (gmsh->binary) { 1076 PetscCall(GmshReadInt(gmsh, &checkEndian, 1)); 1077 if (checkEndian != 1) { 1078 PetscCall(PetscByteSwap(&checkEndian, PETSC_ENUM, 1)); 1079 PetscCheck(checkEndian == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to detect endianness in Gmsh file header: %s", line); 1080 gmsh->byteSwap = PETSC_TRUE; 1081 } 1082 } 1083 PetscFunctionReturn(PETSC_SUCCESS); 1084 } 1085 1086 /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format 1087 Neper: https://neper.info/ adds this section 1088 1089 $MeshVersion 1090 <major>.<minor>,<patch> 1091 $EndMeshVersion 1092 */ 1093 static PetscErrorCode GmshReadMeshVersion(GmshFile *gmsh) 1094 { 1095 char line[PETSC_MAX_PATH_LEN]; 1096 int snum, major, minor, patch; 1097 1098 PetscFunctionBegin; 1099 PetscCall(GmshReadString(gmsh, line, 1)); 1100 snum = sscanf(line, "%d.%d.%d", &major, &minor, &patch); 1101 PetscCheck(snum == 3, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to parse Gmsh file header: %s", line); 1102 PetscFunctionReturn(PETSC_SUCCESS); 1103 } 1104 1105 /* http://gmsh.info/dev/doc/texinfo/gmsh.html#MSH-file-format 1106 Neper: https://neper.info/ adds this section 1107 1108 $Domain 1109 <shape> 1110 $EndDomain 1111 */ 1112 static PetscErrorCode GmshReadMeshDomain(GmshFile *gmsh) 1113 { 1114 char line[PETSC_MAX_PATH_LEN]; 1115 1116 PetscFunctionBegin; 1117 PetscCall(GmshReadString(gmsh, line, 1)); 1118 PetscFunctionReturn(PETSC_SUCCESS); 1119 } 1120 1121 /* 1122 PhysicalNames 1123 numPhysicalNames(ASCII int) 1124 dimension(ASCII int) physicalTag(ASCII int) "name"(127 characters max) 1125 ... 1126 $EndPhysicalNames 1127 */ 1128 static PetscErrorCode GmshReadPhysicalNames(GmshFile *gmsh, GmshMesh *mesh) 1129 { 1130 char line[PETSC_MAX_PATH_LEN], name[128 + 2], *p = NULL, *q = NULL, *r = NULL; 1131 int snum, region, dim, tag; 1132 1133 PetscFunctionBegin; 1134 PetscCall(GmshReadString(gmsh, line, 1)); 1135 snum = sscanf(line, "%d", ®ion); 1136 mesh->numRegions = region; 1137 PetscCheck(snum == 1, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file"); 1138 PetscCall(PetscMalloc3(mesh->numRegions, &mesh->regionDims, mesh->numRegions, &mesh->regionTags, mesh->numRegions, &mesh->regionNames)); 1139 for (region = 0; region < mesh->numRegions; ++region) { 1140 PetscCall(GmshReadString(gmsh, line, 2)); 1141 snum = sscanf(line, "%d %d", &dim, &tag); 1142 PetscCheck(snum == 2, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file"); 1143 PetscCall(GmshReadString(gmsh, line, -(PetscInt)sizeof(line))); 1144 PetscCall(PetscStrchr(line, '"', &p)); 1145 PetscCheck(p, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file"); 1146 PetscCall(PetscStrrchr(line, '"', &q)); 1147 PetscCheck(q != p, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "File is not a valid Gmsh file"); 1148 PetscCall(PetscStrrchr(line, ':', &r)); 1149 if (p != r) q = r; 1150 PetscCall(PetscStrncpy(name, p + 1, (size_t)(q - p - 1))); 1151 mesh->regionDims[region] = dim; 1152 mesh->regionTags[region] = tag; 1153 PetscCall(PetscStrallocpy(name, &mesh->regionNames[region])); 1154 } 1155 PetscFunctionReturn(PETSC_SUCCESS); 1156 } 1157 1158 static PetscErrorCode GmshReadEntities(GmshFile *gmsh, GmshMesh *mesh) 1159 { 1160 PetscFunctionBegin; 1161 switch (gmsh->fileFormat) { 1162 case 41: 1163 PetscCall(GmshReadEntities_v41(gmsh, mesh)); 1164 break; 1165 default: 1166 PetscCall(GmshReadEntities_v40(gmsh, mesh)); 1167 break; 1168 } 1169 PetscFunctionReturn(PETSC_SUCCESS); 1170 } 1171 1172 static PetscErrorCode GmshReadNodes(GmshFile *gmsh, GmshMesh *mesh) 1173 { 1174 PetscFunctionBegin; 1175 switch (gmsh->fileFormat) { 1176 case 41: 1177 PetscCall(GmshReadNodes_v41(gmsh, mesh)); 1178 break; 1179 case 40: 1180 PetscCall(GmshReadNodes_v40(gmsh, mesh)); 1181 break; 1182 default: 1183 PetscCall(GmshReadNodes_v22(gmsh, mesh)); 1184 break; 1185 } 1186 1187 { /* Gmsh v2.2/v4.0 does not provide min/max node tags */ 1188 if (mesh->numNodes > 0 && gmsh->nodeEnd >= gmsh->nodeStart) { 1189 PetscInt tagMin = PETSC_MAX_INT, tagMax = PETSC_MIN_INT, n; 1190 GmshNodes *nodes = mesh->nodelist; 1191 for (n = 0; n < mesh->numNodes; ++n) { 1192 const PetscInt tag = nodes->id[n]; 1193 tagMin = PetscMin(tag, tagMin); 1194 tagMax = PetscMax(tag, tagMax); 1195 } 1196 gmsh->nodeStart = tagMin; 1197 gmsh->nodeEnd = tagMax + 1; 1198 } 1199 } 1200 1201 { /* Support for sparse node tags */ 1202 PetscInt n, t; 1203 GmshNodes *nodes = mesh->nodelist; 1204 PetscCall(PetscMalloc1(gmsh->nodeEnd - gmsh->nodeStart, &gmsh->nbuf)); 1205 for (t = 0; t < gmsh->nodeEnd - gmsh->nodeStart; ++t) gmsh->nbuf[t] = PETSC_MIN_INT; 1206 gmsh->nodeMap = gmsh->nbuf - gmsh->nodeStart; 1207 for (n = 0; n < mesh->numNodes; ++n) { 1208 const PetscInt tag = nodes->id[n]; 1209 PetscCheck(gmsh->nodeMap[tag] < 0, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Repeated node tag %" PetscInt_FMT, tag); 1210 gmsh->nodeMap[tag] = n; 1211 } 1212 } 1213 PetscFunctionReturn(PETSC_SUCCESS); 1214 } 1215 1216 static PetscErrorCode GmshReadElements(GmshFile *gmsh, GmshMesh *mesh) 1217 { 1218 PetscFunctionBegin; 1219 switch (gmsh->fileFormat) { 1220 case 41: 1221 PetscCall(GmshReadElements_v41(gmsh, mesh)); 1222 break; 1223 case 40: 1224 PetscCall(GmshReadElements_v40(gmsh, mesh)); 1225 break; 1226 default: 1227 PetscCall(GmshReadElements_v22(gmsh, mesh)); 1228 break; 1229 } 1230 1231 { /* Reorder elements by codimension and polytope type */ 1232 PetscInt ne = mesh->numElems; 1233 GmshElement *elements = mesh->elements; 1234 PetscInt keymap[GMSH_NUM_POLYTOPES], nk = 0; 1235 PetscInt offset[GMSH_NUM_POLYTOPES + 1], e, k; 1236 1237 for (k = 0; k < GMSH_NUM_POLYTOPES; ++k) keymap[k] = PETSC_MIN_INT; 1238 PetscCall(PetscMemzero(offset, sizeof(offset))); 1239 1240 keymap[GMSH_TET] = nk++; 1241 keymap[GMSH_HEX] = nk++; 1242 keymap[GMSH_PRI] = nk++; 1243 keymap[GMSH_PYR] = nk++; 1244 keymap[GMSH_TRI] = nk++; 1245 keymap[GMSH_QUA] = nk++; 1246 keymap[GMSH_SEG] = nk++; 1247 keymap[GMSH_VTX] = nk++; 1248 1249 PetscCall(GmshElementsCreate(mesh->numElems, &mesh->elements)); 1250 #define key(eid) keymap[GmshCellMap[elements[eid].cellType].polytope] 1251 for (e = 0; e < ne; ++e) offset[1 + key(e)]++; 1252 for (k = 1; k < nk; ++k) offset[k] += offset[k - 1]; 1253 for (e = 0; e < ne; ++e) mesh->elements[offset[key(e)]++] = elements[e]; 1254 #undef key 1255 PetscCall(GmshElementsDestroy(&elements)); 1256 } 1257 1258 { /* Mesh dimension and order */ 1259 GmshElement *elem = mesh->numElems ? mesh->elements : NULL; 1260 mesh->dim = elem ? GmshCellMap[elem->cellType].dim : 0; 1261 mesh->order = elem ? GmshCellMap[elem->cellType].order : 0; 1262 } 1263 1264 { 1265 PetscBT vtx; 1266 PetscInt dim = mesh->dim, e, n, v; 1267 1268 PetscCall(PetscBTCreate(mesh->numNodes, &vtx)); 1269 1270 /* Compute number of cells and set of vertices */ 1271 mesh->numCells = 0; 1272 for (e = 0; e < mesh->numElems; ++e) { 1273 GmshElement *elem = mesh->elements + e; 1274 if (elem->dim == dim && dim > 0) mesh->numCells++; 1275 for (v = 0; v < elem->numVerts; v++) PetscCall(PetscBTSet(vtx, elem->nodes[v])); 1276 } 1277 1278 /* Compute numbering for vertices */ 1279 mesh->numVerts = 0; 1280 PetscCall(PetscMalloc1(mesh->numNodes, &mesh->vertexMap)); 1281 for (n = 0; n < mesh->numNodes; ++n) mesh->vertexMap[n] = PetscBTLookup(vtx, n) ? mesh->numVerts++ : PETSC_MIN_INT; 1282 1283 PetscCall(PetscBTDestroy(&vtx)); 1284 } 1285 PetscFunctionReturn(PETSC_SUCCESS); 1286 } 1287 1288 static PetscErrorCode GmshReadPeriodic(GmshFile *gmsh, GmshMesh *mesh) 1289 { 1290 PetscInt n; 1291 1292 PetscFunctionBegin; 1293 PetscCall(PetscMalloc1(mesh->numNodes, &mesh->periodMap)); 1294 for (n = 0; n < mesh->numNodes; ++n) mesh->periodMap[n] = n; 1295 switch (gmsh->fileFormat) { 1296 case 41: 1297 PetscCall(GmshReadPeriodic_v41(gmsh, mesh->periodMap)); 1298 break; 1299 default: 1300 PetscCall(GmshReadPeriodic_v40(gmsh, mesh->periodMap)); 1301 break; 1302 } 1303 1304 /* Find canonical primary nodes */ 1305 for (n = 0; n < mesh->numNodes; ++n) 1306 while (mesh->periodMap[n] != mesh->periodMap[mesh->periodMap[n]]) mesh->periodMap[n] = mesh->periodMap[mesh->periodMap[n]]; 1307 1308 /* Renumber vertices (filter out correspondings) */ 1309 mesh->numVerts = 0; 1310 for (n = 0; n < mesh->numNodes; ++n) 1311 if (mesh->vertexMap[n] >= 0) /* is vertex */ 1312 if (mesh->periodMap[n] == n) /* is primary */ 1313 mesh->vertexMap[n] = mesh->numVerts++; 1314 for (n = 0; n < mesh->numNodes; ++n) 1315 if (mesh->vertexMap[n] >= 0) /* is vertex */ 1316 if (mesh->periodMap[n] != n) /* is corresponding */ 1317 mesh->vertexMap[n] = mesh->vertexMap[mesh->periodMap[n]]; 1318 PetscFunctionReturn(PETSC_SUCCESS); 1319 } 1320 1321 #define DM_POLYTOPE_VERTEX DM_POLYTOPE_POINT 1322 static const DMPolytopeType DMPolytopeMap[] = { 1323 /* GMSH_VTX */ DM_POLYTOPE_VERTEX, 1324 /* GMSH_SEG */ DM_POLYTOPE_SEGMENT, 1325 /* GMSH_TRI */ DM_POLYTOPE_TRIANGLE, 1326 /* GMSH_QUA */ DM_POLYTOPE_QUADRILATERAL, 1327 /* GMSH_TET */ DM_POLYTOPE_TETRAHEDRON, 1328 /* GMSH_HEX */ DM_POLYTOPE_HEXAHEDRON, 1329 /* GMSH_PRI */ DM_POLYTOPE_TRI_PRISM, 1330 /* GMSH_PYR */ DM_POLYTOPE_PYRAMID, DM_POLYTOPE_UNKNOWN}; 1331 1332 static inline DMPolytopeType DMPolytopeTypeFromGmsh(PetscInt cellType) 1333 { 1334 return DMPolytopeMap[GmshCellMap[cellType].polytope]; 1335 } 1336 1337 static PetscErrorCode GmshCreateFE(MPI_Comm comm, const char prefix[], PetscBool isSimplex, PetscBool continuity, PetscDTNodeType nodeType, PetscInt dim, PetscInt Nc, PetscInt k, PetscFE *fem) 1338 { 1339 DM K; 1340 PetscSpace P; 1341 PetscDualSpace Q; 1342 PetscQuadrature q, fq; 1343 PetscBool isTensor = isSimplex ? PETSC_FALSE : PETSC_TRUE; 1344 PetscBool endpoint = PETSC_TRUE; 1345 char name[32]; 1346 1347 PetscFunctionBegin; 1348 /* Create space */ 1349 PetscCall(PetscSpaceCreate(comm, &P)); 1350 PetscCall(PetscSpaceSetType(P, PETSCSPACEPOLYNOMIAL)); 1351 PetscCall(PetscSpacePolynomialSetTensor(P, isTensor)); 1352 PetscCall(PetscSpaceSetNumComponents(P, Nc)); 1353 PetscCall(PetscSpaceSetNumVariables(P, dim)); 1354 PetscCall(PetscSpaceSetDegree(P, k, PETSC_DETERMINE)); 1355 if (prefix) { 1356 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)P, prefix)); 1357 PetscCall(PetscSpaceSetFromOptions(P)); 1358 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)P, NULL)); 1359 PetscCall(PetscSpaceGetDegree(P, &k, NULL)); 1360 } 1361 PetscCall(PetscSpaceSetUp(P)); 1362 /* Create dual space */ 1363 PetscCall(PetscDualSpaceCreate(comm, &Q)); 1364 PetscCall(PetscDualSpaceSetType(Q, PETSCDUALSPACELAGRANGE)); 1365 PetscCall(PetscDualSpaceLagrangeSetTensor(Q, isTensor)); 1366 PetscCall(PetscDualSpaceLagrangeSetContinuity(Q, continuity)); 1367 PetscCall(PetscDualSpaceLagrangeSetNodeType(Q, nodeType, endpoint, 0)); 1368 PetscCall(PetscDualSpaceSetNumComponents(Q, Nc)); 1369 PetscCall(PetscDualSpaceSetOrder(Q, k)); 1370 PetscCall(DMPlexCreateReferenceCell(PETSC_COMM_SELF, DMPolytopeTypeSimpleShape(dim, isSimplex), &K)); 1371 PetscCall(PetscDualSpaceSetDM(Q, K)); 1372 PetscCall(DMDestroy(&K)); 1373 if (prefix) { 1374 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)Q, prefix)); 1375 PetscCall(PetscDualSpaceSetFromOptions(Q)); 1376 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)Q, NULL)); 1377 } 1378 PetscCall(PetscDualSpaceSetUp(Q)); 1379 /* Create quadrature */ 1380 if (isSimplex) { 1381 PetscCall(PetscDTStroudConicalQuadrature(dim, 1, k + 1, -1, +1, &q)); 1382 PetscCall(PetscDTStroudConicalQuadrature(dim - 1, 1, k + 1, -1, +1, &fq)); 1383 } else { 1384 PetscCall(PetscDTGaussTensorQuadrature(dim, 1, k + 1, -1, +1, &q)); 1385 PetscCall(PetscDTGaussTensorQuadrature(dim - 1, 1, k + 1, -1, +1, &fq)); 1386 } 1387 /* Create finite element */ 1388 PetscCall(PetscFECreate(comm, fem)); 1389 PetscCall(PetscFESetType(*fem, PETSCFEBASIC)); 1390 PetscCall(PetscFESetNumComponents(*fem, Nc)); 1391 PetscCall(PetscFESetBasisSpace(*fem, P)); 1392 PetscCall(PetscFESetDualSpace(*fem, Q)); 1393 PetscCall(PetscFESetQuadrature(*fem, q)); 1394 PetscCall(PetscFESetFaceQuadrature(*fem, fq)); 1395 if (prefix) { 1396 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*fem, prefix)); 1397 PetscCall(PetscFESetFromOptions(*fem)); 1398 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*fem, NULL)); 1399 } 1400 PetscCall(PetscFESetUp(*fem)); 1401 /* Cleanup */ 1402 PetscCall(PetscSpaceDestroy(&P)); 1403 PetscCall(PetscDualSpaceDestroy(&Q)); 1404 PetscCall(PetscQuadratureDestroy(&q)); 1405 PetscCall(PetscQuadratureDestroy(&fq)); 1406 /* Set finite element name */ 1407 PetscCall(PetscSNPrintf(name, sizeof(name), "%s%" PetscInt_FMT, isSimplex ? "P" : "Q", k)); 1408 PetscCall(PetscFESetName(*fem, name)); 1409 PetscFunctionReturn(PETSC_SUCCESS); 1410 } 1411 1412 /*@ 1413 DMPlexCreateGmshFromFile - Create a `DMPLEX` mesh from a Gmsh file 1414 1415 Input Parameters: 1416 + comm - The MPI communicator 1417 . filename - Name of the Gmsh file 1418 - interpolate - Create faces and edges in the mesh 1419 1420 Output Parameter: 1421 . dm - The `DM` object representing the mesh 1422 1423 Level: beginner 1424 1425 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateFromFile()`, `DMPlexCreateGmsh()`, `DMPlexCreate()` 1426 @*/ 1427 PetscErrorCode DMPlexCreateGmshFromFile(MPI_Comm comm, const char filename[], PetscBool interpolate, DM *dm) 1428 { 1429 PetscViewer viewer; 1430 PetscMPIInt rank; 1431 int fileType; 1432 PetscViewerType vtype; 1433 1434 PetscFunctionBegin; 1435 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1436 1437 /* Determine Gmsh file type (ASCII or binary) from file header */ 1438 if (rank == 0) { 1439 GmshFile gmsh[1]; 1440 char line[PETSC_MAX_PATH_LEN]; 1441 int snum; 1442 float version; 1443 int fileFormat; 1444 1445 PetscCall(PetscArrayzero(gmsh, 1)); 1446 PetscCall(PetscViewerCreate(PETSC_COMM_SELF, &gmsh->viewer)); 1447 PetscCall(PetscViewerSetType(gmsh->viewer, PETSCVIEWERASCII)); 1448 PetscCall(PetscViewerFileSetMode(gmsh->viewer, FILE_MODE_READ)); 1449 PetscCall(PetscViewerFileSetName(gmsh->viewer, filename)); 1450 /* Read only the first two lines of the Gmsh file */ 1451 PetscCall(GmshReadSection(gmsh, line)); 1452 PetscCall(GmshExpect(gmsh, "$MeshFormat", line)); 1453 PetscCall(GmshReadString(gmsh, line, 2)); 1454 snum = sscanf(line, "%f %d", &version, &fileType); 1455 fileFormat = (int)roundf(version * 10); 1456 PetscCheck(snum == 2, PETSC_COMM_SELF, PETSC_ERR_FILE_UNEXPECTED, "Unable to parse Gmsh file header: %s", line); 1457 PetscCheck(fileFormat >= 22, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at least 2.2", (double)version); 1458 PetscCheck((int)version != 3, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f not supported", (double)version); 1459 PetscCheck(fileFormat <= 41, PETSC_COMM_SELF, PETSC_ERR_SUP, "Gmsh file version %3.1f must be at most 4.1", (double)version); 1460 PetscCall(PetscViewerDestroy(&gmsh->viewer)); 1461 } 1462 PetscCallMPI(MPI_Bcast(&fileType, 1, MPI_INT, 0, comm)); 1463 vtype = (fileType == 0) ? PETSCVIEWERASCII : PETSCVIEWERBINARY; 1464 1465 /* Create appropriate viewer and build plex */ 1466 PetscCall(PetscViewerCreate(comm, &viewer)); 1467 PetscCall(PetscViewerSetType(viewer, vtype)); 1468 PetscCall(PetscViewerFileSetMode(viewer, FILE_MODE_READ)); 1469 PetscCall(PetscViewerFileSetName(viewer, filename)); 1470 PetscCall(DMPlexCreateGmsh(comm, viewer, interpolate, dm)); 1471 PetscCall(PetscViewerDestroy(&viewer)); 1472 PetscFunctionReturn(PETSC_SUCCESS); 1473 } 1474 1475 /*@ 1476 DMPlexCreateGmsh - Create a `DMPLEX` mesh from a Gmsh file viewer 1477 1478 Collective 1479 1480 Input Parameters: 1481 + comm - The MPI communicator 1482 . viewer - The `PetscViewer` associated with a Gmsh file 1483 - interpolate - Create faces and edges in the mesh 1484 1485 Output Parameter: 1486 . dm - The `DM` object representing the mesh 1487 1488 Options Database Keys: 1489 + -dm_plex_gmsh_hybrid - Force triangular prisms to use tensor order 1490 . -dm_plex_gmsh_periodic - Read Gmsh periodic section and construct a periodic Plex 1491 . -dm_plex_gmsh_highorder - Generate high-order coordinates 1492 . -dm_plex_gmsh_project - Project high-order coordinates to a different space, use the prefix dm_plex_gmsh_project_ to define the space 1493 . -dm_plex_gmsh_use_generic - Generate generic labels, i.e. Cell Sets, Face Sets, etc. 1494 . -dm_plex_gmsh_use_regions - Generate labels with region names 1495 . -dm_plex_gmsh_mark_vertices - Add vertices to generated labels 1496 . -dm_plex_gmsh_multiple_tags - Allow multiple tags for default labels 1497 - -dm_plex_gmsh_spacedim <d> - Embedding space dimension, if different from topological dimension 1498 1499 Level: beginner 1500 1501 Notes: 1502 The Gmsh file format is described in <http://gmsh.info/doc/texinfo/gmsh.html#MSH-file-format> 1503 1504 By default, the "Cell Sets", "Face Sets", and "Vertex Sets" labels are created, and only insert the first tag on a point. By using -dm_plex_gmsh_multiple_tags, all tags can be inserted. Alternatively, -dm_plex_gmsh_use_regions creates labels based on the region names from the PhysicalNames section, and all tags are used, but you can retain the generic labels using -dm_plex_gmsh_use_generic. 1505 1506 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()` 1507 @*/ 1508 PetscErrorCode DMPlexCreateGmsh(MPI_Comm comm, PetscViewer viewer, PetscBool interpolate, DM *dm) 1509 { 1510 GmshMesh *mesh = NULL; 1511 PetscViewer parentviewer = NULL; 1512 PetscBT periodicVerts = NULL; 1513 PetscBT *periodicCells = NULL; 1514 DM cdm, cdmCell = NULL; 1515 PetscSection cs, csCell = NULL; 1516 Vec coordinates, coordinatesCell; 1517 DMLabel cellSets = NULL, faceSets = NULL, edgeSets = NULL, vertSets = NULL, marker = NULL, *regionSets; 1518 PetscInt dim = 0, coordDim = -1, order = 0, maxHeight = 0; 1519 PetscInt numNodes = 0, numElems = 0, numVerts = 0, numCells = 0, vStart, vEnd; 1520 PetscInt cell, cone[8], e, n, v, d; 1521 PetscBool usegeneric = PETSC_TRUE, useregions = PETSC_FALSE, markvertices = PETSC_FALSE, multipleTags = PETSC_FALSE; 1522 PetscBool flg, binary, hybrid = interpolate, periodic = PETSC_TRUE; 1523 PetscBool highOrder = PETSC_TRUE, highOrderSet, project = PETSC_FALSE; 1524 PetscBool isSimplex = PETSC_FALSE, isHybrid = PETSC_FALSE, hasTetra = PETSC_FALSE; 1525 PetscMPIInt rank; 1526 1527 PetscFunctionBegin; 1528 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1529 PetscObjectOptionsBegin((PetscObject)viewer); 1530 PetscOptionsHeadBegin(PetscOptionsObject, "DMPlex Gmsh options"); 1531 PetscCall(PetscOptionsBool("-dm_plex_gmsh_hybrid", "Force triangular prisms to use tensor order", "DMPlexCreateGmsh", hybrid, &hybrid, NULL)); 1532 PetscCall(PetscOptionsBool("-dm_plex_gmsh_periodic", "Read Gmsh periodic section", "DMPlexCreateGmsh", periodic, &periodic, NULL)); 1533 PetscCall(PetscOptionsBool("-dm_plex_gmsh_highorder", "Generate high-order coordinates", "DMPlexCreateGmsh", highOrder, &highOrder, &highOrderSet)); 1534 PetscCall(PetscOptionsBool("-dm_plex_gmsh_project", "Project high-order coordinates to a different space", "DMPlexCreateGmsh", project, &project, NULL)); 1535 PetscCall(PetscOptionsBool("-dm_plex_gmsh_use_regions", "Generate labels with region names", "DMPlexCreateGmsh", useregions, &useregions, NULL)); 1536 PetscCall(PetscOptionsBool("-dm_plex_gmsh_use_generic", "Generate generic labels, i.e. Cell Sets, Face Sets, etc", "DMPlexCreateGmsh", usegeneric, &usegeneric, &flg)); 1537 if (!flg && useregions) usegeneric = PETSC_FALSE; 1538 PetscCall(PetscOptionsBool("-dm_plex_gmsh_mark_vertices", "Add vertices to generated labels", "DMPlexCreateGmsh", markvertices, &markvertices, NULL)); 1539 PetscCall(PetscOptionsBool("-dm_plex_gmsh_multiple_tags", "Allow multiple tags for default labels", "DMPlexCreateGmsh", multipleTags, &multipleTags, NULL)); 1540 PetscCall(PetscOptionsBoundedInt("-dm_plex_gmsh_spacedim", "Embedding space dimension", "DMPlexCreateGmsh", coordDim, &coordDim, NULL, PETSC_DECIDE)); 1541 PetscCall(PetscOptionsBoundedInt("-dm_localize_height", "Localize edges and faces in addition to cells", "", maxHeight, &maxHeight, NULL, 0)); 1542 PetscOptionsHeadEnd(); 1543 PetscOptionsEnd(); 1544 1545 PetscCall(GmshCellInfoSetUp()); 1546 1547 PetscCall(DMCreate(comm, dm)); 1548 PetscCall(DMSetType(*dm, DMPLEX)); 1549 PetscCall(PetscLogEventBegin(DMPLEX_CreateGmsh, *dm, NULL, NULL, NULL)); 1550 1551 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &binary)); 1552 1553 /* Binary viewers read on all ranks, get subviewer to read only in rank 0 */ 1554 if (binary) { 1555 parentviewer = viewer; 1556 PetscCall(PetscViewerGetSubViewer(parentviewer, PETSC_COMM_SELF, &viewer)); 1557 } 1558 1559 if (rank == 0) { 1560 GmshFile gmsh[1]; 1561 char line[PETSC_MAX_PATH_LEN]; 1562 PetscBool match; 1563 1564 PetscCall(PetscArrayzero(gmsh, 1)); 1565 gmsh->viewer = viewer; 1566 gmsh->binary = binary; 1567 1568 PetscCall(GmshMeshCreate(&mesh)); 1569 1570 /* Read mesh format */ 1571 PetscCall(GmshReadSection(gmsh, line)); 1572 PetscCall(GmshExpect(gmsh, "$MeshFormat", line)); 1573 PetscCall(GmshReadMeshFormat(gmsh)); 1574 PetscCall(GmshReadEndSection(gmsh, "$EndMeshFormat", line)); 1575 1576 /* OPTIONAL Read mesh version (Neper only) */ 1577 PetscCall(GmshReadSection(gmsh, line)); 1578 PetscCall(GmshMatch(gmsh, "$MeshVersion", line, &match)); 1579 if (match) { 1580 PetscCall(GmshExpect(gmsh, "$MeshVersion", line)); 1581 PetscCall(GmshReadMeshVersion(gmsh)); 1582 PetscCall(GmshReadEndSection(gmsh, "$EndMeshVersion", line)); 1583 /* Initial read for entity section */ 1584 PetscCall(GmshReadSection(gmsh, line)); 1585 } 1586 1587 /* OPTIONAL Read mesh domain (Neper only) */ 1588 PetscCall(GmshMatch(gmsh, "$Domain", line, &match)); 1589 if (match) { 1590 PetscCall(GmshExpect(gmsh, "$Domain", line)); 1591 PetscCall(GmshReadMeshDomain(gmsh)); 1592 PetscCall(GmshReadEndSection(gmsh, "$EndDomain", line)); 1593 /* Initial read for entity section */ 1594 PetscCall(GmshReadSection(gmsh, line)); 1595 } 1596 1597 /* OPTIONAL Read physical names */ 1598 PetscCall(GmshMatch(gmsh, "$PhysicalNames", line, &match)); 1599 if (match) { 1600 PetscCall(GmshExpect(gmsh, "$PhysicalNames", line)); 1601 PetscCall(GmshReadPhysicalNames(gmsh, mesh)); 1602 PetscCall(GmshReadEndSection(gmsh, "$EndPhysicalNames", line)); 1603 /* Initial read for entity section */ 1604 PetscCall(GmshReadSection(gmsh, line)); 1605 } 1606 1607 /* OPTIONAL Read entities */ 1608 if (gmsh->fileFormat >= 40) { 1609 PetscCall(GmshMatch(gmsh, "$Entities", line, &match)); 1610 if (match) { 1611 PetscCall(GmshExpect(gmsh, "$Entities", line)); 1612 PetscCall(GmshReadEntities(gmsh, mesh)); 1613 PetscCall(GmshReadEndSection(gmsh, "$EndEntities", line)); 1614 /* Initial read for nodes section */ 1615 PetscCall(GmshReadSection(gmsh, line)); 1616 } 1617 } 1618 1619 /* Read nodes */ 1620 PetscCall(GmshExpect(gmsh, "$Nodes", line)); 1621 PetscCall(GmshReadNodes(gmsh, mesh)); 1622 PetscCall(GmshReadEndSection(gmsh, "$EndNodes", line)); 1623 1624 /* Read elements */ 1625 PetscCall(GmshReadSection(gmsh, line)); 1626 PetscCall(GmshExpect(gmsh, "$Elements", line)); 1627 PetscCall(GmshReadElements(gmsh, mesh)); 1628 PetscCall(GmshReadEndSection(gmsh, "$EndElements", line)); 1629 1630 /* Read periodic section (OPTIONAL) */ 1631 if (periodic) { 1632 PetscCall(GmshReadSection(gmsh, line)); 1633 PetscCall(GmshMatch(gmsh, "$Periodic", line, &periodic)); 1634 } 1635 if (periodic) { 1636 PetscCall(GmshExpect(gmsh, "$Periodic", line)); 1637 PetscCall(GmshReadPeriodic(gmsh, mesh)); 1638 PetscCall(GmshReadEndSection(gmsh, "$EndPeriodic", line)); 1639 } 1640 1641 PetscCall(PetscFree(gmsh->wbuf)); 1642 PetscCall(PetscFree(gmsh->sbuf)); 1643 PetscCall(PetscFree(gmsh->nbuf)); 1644 1645 dim = mesh->dim; 1646 order = mesh->order; 1647 numNodes = mesh->numNodes; 1648 numElems = mesh->numElems; 1649 numVerts = mesh->numVerts; 1650 numCells = mesh->numCells; 1651 1652 { 1653 GmshElement *elemA = mesh->numCells > 0 ? mesh->elements : NULL; 1654 GmshElement *elemB = PetscSafePointerPlusOffset(elemA, mesh->numCells - 1); 1655 int ptA = elemA ? GmshCellMap[elemA->cellType].polytope : -1; 1656 int ptB = elemB ? GmshCellMap[elemB->cellType].polytope : -1; 1657 isSimplex = (ptA == GMSH_QUA || ptA == GMSH_HEX) ? PETSC_FALSE : PETSC_TRUE; 1658 isHybrid = (ptA == ptB) ? PETSC_FALSE : PETSC_TRUE; 1659 hasTetra = (ptA == GMSH_TET) ? PETSC_TRUE : PETSC_FALSE; 1660 } 1661 } 1662 1663 if (parentviewer) PetscCall(PetscViewerRestoreSubViewer(parentviewer, PETSC_COMM_SELF, &viewer)); 1664 1665 { 1666 int buf[6]; 1667 1668 buf[0] = (int)dim; 1669 buf[1] = (int)order; 1670 buf[2] = periodic; 1671 buf[3] = isSimplex; 1672 buf[4] = isHybrid; 1673 buf[5] = hasTetra; 1674 1675 PetscCallMPI(MPI_Bcast(buf, 6, MPI_INT, 0, comm)); 1676 1677 dim = buf[0]; 1678 order = buf[1]; 1679 periodic = buf[2] ? PETSC_TRUE : PETSC_FALSE; 1680 isSimplex = buf[3] ? PETSC_TRUE : PETSC_FALSE; 1681 isHybrid = buf[4] ? PETSC_TRUE : PETSC_FALSE; 1682 hasTetra = buf[5] ? PETSC_TRUE : PETSC_FALSE; 1683 } 1684 1685 if (!highOrderSet) highOrder = (order > 1) ? PETSC_TRUE : PETSC_FALSE; 1686 PetscCheck(!highOrder || !isHybrid, comm, PETSC_ERR_SUP, "No support for discretization on hybrid meshes yet"); 1687 1688 /* We do not want this label automatically computed, instead we fill it here */ 1689 PetscCall(DMCreateLabel(*dm, "celltype")); 1690 1691 /* Allocate the cell-vertex mesh */ 1692 PetscCall(DMPlexSetChart(*dm, 0, numCells + numVerts)); 1693 for (cell = 0; cell < numCells; ++cell) { 1694 GmshElement *elem = mesh->elements + cell; 1695 DMPolytopeType ctype = DMPolytopeTypeFromGmsh(elem->cellType); 1696 if (hybrid && hasTetra && ctype == DM_POLYTOPE_TRI_PRISM) ctype = DM_POLYTOPE_TRI_PRISM_TENSOR; 1697 PetscCall(DMPlexSetConeSize(*dm, cell, elem->numVerts)); 1698 PetscCall(DMPlexSetCellType(*dm, cell, ctype)); 1699 } 1700 for (v = numCells; v < numCells + numVerts; ++v) PetscCall(DMPlexSetCellType(*dm, v, DM_POLYTOPE_POINT)); 1701 PetscCall(DMSetUp(*dm)); 1702 1703 /* Add cell-vertex connections */ 1704 for (cell = 0; cell < numCells; ++cell) { 1705 GmshElement *elem = mesh->elements + cell; 1706 for (v = 0; v < elem->numVerts; ++v) { 1707 const PetscInt nn = elem->nodes[v]; 1708 const PetscInt vv = mesh->vertexMap[nn]; 1709 cone[v] = numCells + vv; 1710 } 1711 PetscCall(DMPlexReorderCell(*dm, cell, cone)); 1712 PetscCall(DMPlexSetCone(*dm, cell, cone)); 1713 } 1714 1715 PetscCall(DMSetDimension(*dm, dim)); 1716 PetscCall(DMPlexSymmetrize(*dm)); 1717 PetscCall(DMPlexStratify(*dm)); 1718 if (interpolate) { 1719 DM idm; 1720 1721 PetscCall(DMPlexInterpolate(*dm, &idm)); 1722 PetscCall(DMDestroy(dm)); 1723 *dm = idm; 1724 } 1725 PetscCall(DMPlexGetDepthStratum(*dm, 0, &vStart, &vEnd)); 1726 1727 if (rank == 0) { 1728 const PetscInt Nr = useregions ? mesh->numRegions : 0; 1729 1730 PetscCall(PetscCalloc1(Nr, ®ionSets)); 1731 for (cell = 0, e = 0; e < numElems; ++e) { 1732 GmshElement *elem = mesh->elements + e; 1733 1734 /* Create cell sets */ 1735 if (elem->dim == dim && dim > 0) { 1736 if (elem->numTags > 0) { 1737 PetscInt Nt = elem->numTags, t, r; 1738 1739 for (t = 0; t < Nt; ++t) { 1740 const PetscInt tag = elem->tags[t]; 1741 const PetscBool generic = usegeneric && (!t || multipleTags) ? PETSC_TRUE : PETSC_FALSE; 1742 1743 if (generic) PetscCall(DMSetLabelValue_Fast(*dm, &cellSets, "Cell Sets", cell, tag)); 1744 for (r = 0; r < Nr; ++r) { 1745 if (mesh->regionDims[r] != dim) continue; 1746 if (mesh->regionTags[r] == tag) PetscCall(DMSetLabelValue_Fast(*dm, ®ionSets[r], mesh->regionNames[r], cell, tag)); 1747 } 1748 } 1749 } 1750 cell++; 1751 } 1752 1753 /* Create face sets */ 1754 if (elem->numTags && interpolate && elem->dim == dim - 1) { 1755 PetscInt joinSize; 1756 const PetscInt *join = NULL; 1757 PetscInt Nt = elem->numTags, pdepth; 1758 1759 /* Find the relevant facet with vertex joins */ 1760 for (v = 0; v < elem->numVerts; ++v) { 1761 const PetscInt nn = elem->nodes[v]; 1762 const PetscInt vv = mesh->vertexMap[nn]; 1763 cone[v] = vStart + vv; 1764 } 1765 PetscCall(DMPlexGetFullJoin(*dm, elem->numVerts, cone, &joinSize, &join)); 1766 PetscCheck(joinSize == 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Could not determine Plex facet for Gmsh element %" PetscInt_FMT " (Plex cell %" PetscInt_FMT ")", elem->id, e); 1767 PetscCall(DMPlexGetPointDepth(*dm, join[0], &pdepth)); 1768 PetscCheck(pdepth == dim - 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Plex facet %" PetscInt_FMT " for Gmsh element %" PetscInt_FMT " had depth %" PetscInt_FMT " != %" PetscInt_FMT, join[0], elem->id, pdepth, dim - 1); 1769 for (PetscInt t = 0; t < Nt; ++t) { 1770 const PetscInt tag = elem->tags[t]; 1771 const PetscBool generic = usegeneric && (!t || multipleTags) ? PETSC_TRUE : PETSC_FALSE; 1772 1773 if (generic) PetscCall(DMSetLabelValue_Fast(*dm, &faceSets, "Face Sets", join[0], tag)); 1774 for (PetscInt r = 0; r < Nr; ++r) { 1775 if (mesh->regionDims[r] != dim - 1) continue; 1776 if (mesh->regionTags[r] == tag) PetscCall(DMSetLabelValue_Fast(*dm, ®ionSets[r], mesh->regionNames[r], join[0], tag)); 1777 } 1778 } 1779 PetscCall(DMPlexRestoreJoin(*dm, elem->numVerts, cone, &joinSize, &join)); 1780 } 1781 1782 /* Create edge sets */ 1783 if (elem->numTags && interpolate && dim > 2 && elem->dim == 1) { 1784 PetscInt joinSize; 1785 const PetscInt *join = NULL; 1786 PetscInt Nt = elem->numTags, t, r; 1787 1788 /* Find the relevant edge with vertex joins */ 1789 for (v = 0; v < elem->numVerts; ++v) { 1790 const PetscInt nn = elem->nodes[v]; 1791 const PetscInt vv = mesh->vertexMap[nn]; 1792 cone[v] = vStart + vv; 1793 } 1794 PetscCall(DMPlexGetJoin(*dm, elem->numVerts, cone, &joinSize, &join)); 1795 PetscCheck(joinSize == 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Could not determine Plex edge for Gmsh element %" PetscInt_FMT " (Plex cell %" PetscInt_FMT ")", elem->id, e); 1796 for (t = 0; t < Nt; ++t) { 1797 const PetscInt tag = elem->tags[t]; 1798 const PetscBool generic = usegeneric && (!t || multipleTags) ? PETSC_TRUE : PETSC_FALSE; 1799 1800 if (generic) PetscCall(DMSetLabelValue_Fast(*dm, &edgeSets, "Edge Sets", join[0], tag)); 1801 for (r = 0; r < Nr; ++r) { 1802 if (mesh->regionDims[r] != 1) continue; 1803 if (mesh->regionTags[r] == tag) PetscCall(DMSetLabelValue_Fast(*dm, ®ionSets[r], mesh->regionNames[r], join[0], tag)); 1804 } 1805 } 1806 PetscCall(DMPlexRestoreJoin(*dm, elem->numVerts, cone, &joinSize, &join)); 1807 } 1808 1809 /* Create vertex sets */ 1810 if (elem->numTags && elem->dim == 0 && markvertices) { 1811 const PetscInt nn = elem->nodes[0]; 1812 const PetscInt vv = mesh->vertexMap[nn]; 1813 const PetscInt tag = elem->tags[0]; 1814 PetscInt r; 1815 1816 if (vv < 0) continue; 1817 if (usegeneric) PetscCall(DMSetLabelValue_Fast(*dm, &vertSets, "Vertex Sets", vStart + vv, tag)); 1818 for (r = 0; r < Nr; ++r) { 1819 if (mesh->regionDims[r] != 0) continue; 1820 if (mesh->regionTags[r] == tag) PetscCall(DMSetLabelValue_Fast(*dm, ®ionSets[r], mesh->regionNames[r], vStart + vv, tag)); 1821 } 1822 } 1823 } 1824 if (markvertices) { 1825 for (v = 0; v < numNodes; ++v) { 1826 const PetscInt vv = mesh->vertexMap[v]; 1827 const PetscInt *tags = &mesh->nodelist->tag[v * GMSH_MAX_TAGS]; 1828 PetscInt r, t; 1829 1830 if (vv < 0) continue; 1831 for (t = 0; t < GMSH_MAX_TAGS; ++t) { 1832 const PetscInt tag = tags[t]; 1833 const PetscBool generic = usegeneric && (!t || multipleTags) ? PETSC_TRUE : PETSC_FALSE; 1834 1835 if (tag == -1) continue; 1836 if (generic) PetscCall(DMSetLabelValue_Fast(*dm, &vertSets, "Vertex Sets", vStart + vv, tag)); 1837 for (r = 0; r < Nr; ++r) { 1838 if (mesh->regionTags[r] == tag) PetscCall(DMSetLabelValue_Fast(*dm, ®ionSets[r], mesh->regionNames[r], vStart + vv, tag)); 1839 } 1840 } 1841 } 1842 } 1843 PetscCall(PetscFree(regionSets)); 1844 } 1845 1846 { /* Create Cell/Face/Edge/Vertex Sets labels at all processes */ 1847 enum { 1848 n = 5 1849 }; 1850 PetscBool flag[n]; 1851 1852 flag[0] = cellSets ? PETSC_TRUE : PETSC_FALSE; 1853 flag[1] = faceSets ? PETSC_TRUE : PETSC_FALSE; 1854 flag[2] = edgeSets ? PETSC_TRUE : PETSC_FALSE; 1855 flag[3] = vertSets ? PETSC_TRUE : PETSC_FALSE; 1856 flag[4] = marker ? PETSC_TRUE : PETSC_FALSE; 1857 PetscCallMPI(MPI_Bcast(flag, n, MPIU_BOOL, 0, comm)); 1858 if (flag[0]) PetscCall(DMCreateLabel(*dm, "Cell Sets")); 1859 if (flag[1]) PetscCall(DMCreateLabel(*dm, "Face Sets")); 1860 if (flag[2]) PetscCall(DMCreateLabel(*dm, "Edge Sets")); 1861 if (flag[3]) PetscCall(DMCreateLabel(*dm, "Vertex Sets")); 1862 if (flag[4]) PetscCall(DMCreateLabel(*dm, "marker")); 1863 } 1864 1865 if (periodic) { 1866 PetscCall(PetscBTCreate(numVerts, &periodicVerts)); 1867 for (n = 0; n < numNodes; ++n) { 1868 if (mesh->vertexMap[n] >= 0) { 1869 if (PetscUnlikely(mesh->periodMap[n] != n)) { 1870 PetscInt m = mesh->periodMap[n]; 1871 PetscCall(PetscBTSet(periodicVerts, mesh->vertexMap[n])); 1872 PetscCall(PetscBTSet(periodicVerts, mesh->vertexMap[m])); 1873 } 1874 } 1875 } 1876 PetscCall(DMGetCoordinateDM(*dm, &cdm)); 1877 PetscCall(PetscMalloc1(maxHeight + 1, &periodicCells)); 1878 for (PetscInt h = 0; h <= maxHeight; ++h) { 1879 PetscInt pStart, pEnd; 1880 1881 PetscCall(DMPlexGetHeightStratum(*dm, h, &pStart, &pEnd)); 1882 PetscCall(PetscBTCreate(pEnd - pStart, &periodicCells[h])); 1883 for (PetscInt p = pStart; p < pEnd; ++p) { 1884 PetscInt *closure = NULL; 1885 PetscInt Ncl; 1886 1887 PetscCall(DMPlexGetTransitiveClosure(*dm, p, PETSC_TRUE, &Ncl, &closure)); 1888 for (PetscInt cl = 0; cl < Ncl * 2; cl += 2) { 1889 if (closure[cl] >= vStart && closure[cl] < vEnd) { 1890 if (PetscUnlikely(PetscBTLookup(periodicVerts, closure[cl] - vStart))) { 1891 PetscCall(PetscBTSet(periodicCells[h], p - pStart)); 1892 break; 1893 } 1894 } 1895 } 1896 PetscCall(DMPlexRestoreTransitiveClosure(*dm, p, PETSC_TRUE, &Ncl, &closure)); 1897 } 1898 } 1899 } 1900 1901 /* Setup coordinate DM */ 1902 if (coordDim < 0) coordDim = dim; 1903 PetscCall(DMSetCoordinateDim(*dm, coordDim)); 1904 PetscCall(DMGetCoordinateDM(*dm, &cdm)); 1905 if (highOrder) { 1906 PetscFE fe; 1907 PetscBool continuity = periodic ? PETSC_FALSE : PETSC_TRUE; 1908 PetscDTNodeType nodeType = PETSCDTNODES_EQUISPACED; 1909 1910 if (isSimplex) continuity = PETSC_FALSE; /* XXX FIXME Requires DMPlexSetClosurePermutationLexicographic() */ 1911 1912 PetscCall(GmshCreateFE(comm, NULL, isSimplex, continuity, nodeType, dim, coordDim, order, &fe)); 1913 PetscCall(PetscFEViewFromOptions(fe, NULL, "-dm_plex_gmsh_fe_view")); 1914 PetscCall(DMSetField(cdm, 0, NULL, (PetscObject)fe)); 1915 PetscCall(PetscFEDestroy(&fe)); 1916 PetscCall(DMCreateDS(cdm)); 1917 } 1918 if (periodic) { 1919 PetscCall(DMClone(cdm, &cdmCell)); 1920 PetscCall(DMSetCellCoordinateDM(*dm, cdmCell)); 1921 } 1922 1923 /* Create coordinates */ 1924 if (highOrder) { 1925 PetscInt maxDof = GmshNumNodes_HEX(order) * coordDim; 1926 double *coords = mesh ? mesh->nodelist->xyz : NULL; 1927 PetscSection section; 1928 PetscScalar *cellCoords; 1929 1930 PetscCall(DMSetLocalSection(cdm, NULL)); 1931 PetscCall(DMGetLocalSection(cdm, &cs)); 1932 PetscCall(PetscSectionClone(cs, §ion)); 1933 PetscCall(DMPlexSetClosurePermutationTensor(cdm, 0, section)); /* XXX Implement DMPlexSetClosurePermutationLexicographic() */ 1934 1935 PetscCall(DMCreateLocalVector(cdm, &coordinates)); 1936 PetscCall(PetscMalloc1(maxDof, &cellCoords)); 1937 for (cell = 0; cell < numCells; ++cell) { 1938 GmshElement *elem = mesh->elements + cell; 1939 const int *lexorder = GmshCellMap[elem->cellType].lexorder(); 1940 int s = 0; 1941 for (n = 0; n < elem->numNodes; ++n) { 1942 while (lexorder[n + s] < 0) ++s; 1943 const PetscInt node = elem->nodes[lexorder[n + s]]; 1944 for (d = 0; d < coordDim; ++d) cellCoords[(n + s) * coordDim + d] = (PetscReal)coords[node * 3 + d]; 1945 } 1946 if (s) { 1947 /* For the coordinate mapping we weight vertices by -1/4 and edges by 1/2, which we get from Q_2 interpolation */ 1948 PetscReal quaCenterWeights[9] = {-0.25, 0.5, -0.25, 0.5, 0.0, 0.5, -0.25, 0.5, -0.25}; 1949 /* For the coordinate mapping we weight vertices by -1/4 and edges by 1/2, which we get from Q_2 interpolation */ 1950 PetscReal hexBottomWeights[27] = {-0.25, 0.5, -0.25, 0.5, 0.0, 0.5, -0.25, 0.5, -0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; 1951 PetscReal hexFrontWeights[27] = {-0.25, 0.5, -0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.25, 0.5, -0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; 1952 PetscReal hexLeftWeights[27] = {-0.25, 0.0, 0.0, 0.5, 0.0, 0.0, -0.25, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, -0.25, 0.0, 0.0, 0.5, 0.0, 0.0, -0.25, 0.0, 0.0}; 1953 PetscReal hexRightWeights[27] = {0.0, 0.0, -0.25, 0.0, 0.0, 0.5, 0.0, 0.0, -0.25, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, -0.25, 0.0, 0.0, 0.5, 0.0, 0.0, -0.25}; 1954 PetscReal hexBackWeights[27] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.25, 0.5, -0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.25, 0.5, -0.25}; 1955 PetscReal hexTopWeights[27] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.25, 0.5, -0.25, 0.5, 0.0, 0.5, -0.25, 0.5, -0.25}; 1956 PetscReal hexCenterWeights[27] = {-0.25, 0.25, -0.25, 0.25, 0.0, 0.25, -0.25, 0.25, -0.25, 0.25, 0.0, 0.25, 0.0, 0.0, 0.0, 0.25, 0.0, 0.25, -0.25, 0.25, -0.25, 0.25, 0.0, 0.25, -0.25, 0.25, -0.25}; 1957 PetscReal *sdWeights2[9] = {NULL, NULL, NULL, NULL, quaCenterWeights, NULL, NULL, NULL, NULL}; 1958 PetscReal *sdWeights3[27] = {NULL, NULL, NULL, NULL, hexBottomWeights, NULL, NULL, NULL, NULL, NULL, hexFrontWeights, NULL, hexLeftWeights, hexCenterWeights, hexRightWeights, NULL, hexBackWeights, NULL, 1959 NULL, NULL, NULL, NULL, hexTopWeights, NULL, NULL, NULL, NULL}; 1960 PetscReal **sdWeights[4] = {NULL, NULL, sdWeights2, sdWeights3}; 1961 1962 /* Missing entries in serendipity cell, only works for 8-node quad and 20-node hex */ 1963 for (n = 0; n < elem->numNodes + s; ++n) { 1964 if (lexorder[n] >= 0) continue; 1965 for (d = 0; d < coordDim; ++d) cellCoords[n * coordDim + d] = 0.0; 1966 for (int bn = 0; bn < elem->numNodes + s; ++bn) { 1967 if (lexorder[bn] < 0) continue; 1968 const PetscReal *weights = sdWeights[coordDim][n]; 1969 const PetscInt bnode = elem->nodes[lexorder[bn]]; 1970 for (d = 0; d < coordDim; ++d) cellCoords[n * coordDim + d] += weights[bn] * (PetscReal)coords[bnode * 3 + d]; 1971 } 1972 } 1973 } 1974 PetscCall(DMPlexVecSetClosure(cdm, section, coordinates, cell, cellCoords, INSERT_VALUES)); 1975 } 1976 PetscCall(PetscSectionDestroy(§ion)); 1977 PetscCall(PetscFree(cellCoords)); 1978 } else { 1979 PetscInt *nodeMap; 1980 double *coords = mesh ? mesh->nodelist->xyz : NULL; 1981 PetscScalar *pointCoords; 1982 1983 PetscCall(DMGetCoordinateSection(*dm, &cs)); 1984 PetscCall(PetscSectionSetNumFields(cs, 1)); 1985 PetscCall(PetscSectionSetFieldComponents(cs, 0, coordDim)); 1986 PetscCall(PetscSectionSetChart(cs, numCells, numCells + numVerts)); 1987 for (v = numCells; v < numCells + numVerts; ++v) { 1988 PetscCall(PetscSectionSetDof(cs, v, coordDim)); 1989 PetscCall(PetscSectionSetFieldDof(cs, v, 0, coordDim)); 1990 } 1991 PetscCall(PetscSectionSetUp(cs)); 1992 1993 /* We need to localize coordinates on cells */ 1994 if (periodic) { 1995 PetscInt newStart = PETSC_MAX_INT, newEnd = -1, pStart, pEnd; 1996 1997 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)cdmCell), &csCell)); 1998 PetscCall(PetscSectionSetNumFields(csCell, 1)); 1999 PetscCall(PetscSectionSetFieldComponents(csCell, 0, coordDim)); 2000 for (PetscInt h = 0; h <= maxHeight; h++) { 2001 PetscCall(DMPlexGetHeightStratum(cdmCell, h, &pStart, &pEnd)); 2002 newStart = PetscMin(newStart, pStart); 2003 newEnd = PetscMax(newEnd, pEnd); 2004 } 2005 PetscCall(PetscSectionSetChart(csCell, newStart, newEnd)); 2006 for (PetscInt h = 0; h <= maxHeight; h++) { 2007 PetscCall(DMPlexGetHeightStratum(cdmCell, h, &pStart, &pEnd)); 2008 for (PetscInt p = pStart; p < pEnd; ++p) { 2009 PetscInt *closure = NULL; 2010 PetscInt Ncl, Nv = 0; 2011 2012 if (PetscUnlikely(PetscBTLookup(periodicCells[h], p - pStart))) { 2013 PetscCall(DMPlexGetTransitiveClosure(*dm, p, PETSC_TRUE, &Ncl, &closure)); 2014 for (PetscInt cl = 0; cl < Ncl * 2; cl += 2) { 2015 if (closure[cl] >= vStart && closure[cl] < vEnd) ++Nv; 2016 } 2017 PetscCall(DMPlexRestoreTransitiveClosure(*dm, p, PETSC_TRUE, &Ncl, &closure)); 2018 PetscCall(PetscSectionSetDof(csCell, p, Nv * coordDim)); 2019 PetscCall(PetscSectionSetFieldDof(csCell, p, 0, Nv * coordDim)); 2020 } 2021 } 2022 } 2023 PetscCall(PetscSectionSetUp(csCell)); 2024 PetscCall(DMSetCellCoordinateSection(*dm, PETSC_DETERMINE, csCell)); 2025 } 2026 2027 PetscCall(DMCreateLocalVector(cdm, &coordinates)); 2028 PetscCall(VecGetArray(coordinates, &pointCoords)); 2029 PetscCall(PetscMalloc1(numVerts, &nodeMap)); 2030 for (n = 0; n < numNodes; n++) 2031 if (mesh->vertexMap[n] >= 0) nodeMap[mesh->vertexMap[n]] = n; 2032 for (v = 0; v < numVerts; ++v) { 2033 PetscInt off, node = nodeMap[v]; 2034 2035 PetscCall(PetscSectionGetOffset(cs, numCells + v, &off)); 2036 for (d = 0; d < coordDim; ++d) pointCoords[off + d] = (PetscReal)coords[node * 3 + d]; 2037 } 2038 PetscCall(VecRestoreArray(coordinates, &pointCoords)); 2039 2040 if (periodic) { 2041 PetscInt cStart, cEnd; 2042 2043 PetscCall(DMPlexGetHeightStratum(cdmCell, 0, &cStart, &cEnd)); 2044 PetscCall(DMCreateLocalVector(cdmCell, &coordinatesCell)); 2045 PetscCall(VecGetArray(coordinatesCell, &pointCoords)); 2046 for (PetscInt c = cStart; c < cEnd; ++c) { 2047 GmshElement *elem = mesh->elements + c - cStart; 2048 PetscInt *closure = NULL; 2049 PetscInt verts[8]; 2050 PetscInt Ncl, Nv = 0; 2051 2052 for (PetscInt v = 0; v < elem->numVerts; ++v) cone[v] = elem->nodes[v]; 2053 PetscCall(DMPlexReorderCell(cdmCell, c, cone)); 2054 PetscCall(DMPlexGetTransitiveClosure(cdmCell, c, PETSC_TRUE, &Ncl, &closure)); 2055 for (PetscInt cl = 0; cl < Ncl * 2; cl += 2) { 2056 if (closure[cl] >= vStart && closure[cl] < vEnd) verts[Nv++] = closure[cl]; 2057 } 2058 PetscCheck(Nv == elem->numVerts, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Number of vertices %" PetscInt_FMT " in closure does not match number of vertices %" PetscInt_FMT " in Gmsh cell", Nv, elem->numVerts); 2059 for (PetscInt cl = 0; cl < Ncl * 2; cl += 2) { 2060 const PetscInt point = closure[cl]; 2061 PetscInt hStart, h; 2062 2063 PetscCall(DMPlexGetPointHeight(cdmCell, point, &h)); 2064 if (h > maxHeight) continue; 2065 PetscCall(DMPlexGetHeightStratum(cdmCell, h, &hStart, NULL)); 2066 if (PetscUnlikely(PetscBTLookup(periodicCells[h], point - hStart))) { 2067 PetscInt *pclosure = NULL; 2068 PetscInt Npcl, off, v; 2069 2070 PetscCall(PetscSectionGetOffset(csCell, point, &off)); 2071 PetscCall(DMPlexGetTransitiveClosure(cdmCell, point, PETSC_TRUE, &Npcl, &pclosure)); 2072 for (PetscInt pcl = 0; pcl < Npcl * 2; pcl += 2) { 2073 if (pclosure[pcl] >= vStart && pclosure[pcl] < vEnd) { 2074 for (v = 0; v < Nv; ++v) 2075 if (verts[v] == pclosure[pcl]) break; 2076 PetscCheck(v < Nv, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find vertex %" PetscInt_FMT " in closure of cell %" PetscInt_FMT, pclosure[pcl], c); 2077 for (PetscInt d = 0; d < coordDim; ++d) pointCoords[off++] = (PetscReal)coords[cone[v] * 3 + d]; 2078 ++v; 2079 } 2080 } 2081 PetscCall(DMPlexRestoreTransitiveClosure(cdmCell, point, PETSC_TRUE, &Npcl, &pclosure)); 2082 } 2083 } 2084 PetscCall(DMPlexRestoreTransitiveClosure(cdmCell, c, PETSC_TRUE, &Ncl, &closure)); 2085 } 2086 PetscCall(VecSetBlockSize(coordinatesCell, coordDim)); 2087 PetscCall(VecRestoreArray(coordinatesCell, &pointCoords)); 2088 PetscCall(DMSetCellCoordinatesLocal(*dm, coordinatesCell)); 2089 PetscCall(VecDestroy(&coordinatesCell)); 2090 } 2091 PetscCall(PetscFree(nodeMap)); 2092 PetscCall(PetscSectionDestroy(&csCell)); 2093 PetscCall(DMDestroy(&cdmCell)); 2094 } 2095 2096 PetscCall(PetscObjectSetName((PetscObject)coordinates, "coordinates")); 2097 PetscCall(VecSetBlockSize(coordinates, coordDim)); 2098 PetscCall(DMSetCoordinatesLocal(*dm, coordinates)); 2099 PetscCall(VecDestroy(&coordinates)); 2100 2101 PetscCall(GmshMeshDestroy(&mesh)); 2102 PetscCall(PetscBTDestroy(&periodicVerts)); 2103 if (periodic) { 2104 for (PetscInt h = 0; h <= maxHeight; ++h) PetscCall(PetscBTDestroy(periodicCells + h)); 2105 PetscCall(PetscFree(periodicCells)); 2106 } 2107 2108 if (highOrder && project) { 2109 PetscFE fe; 2110 const char prefix[] = "dm_plex_gmsh_project_"; 2111 PetscBool continuity = periodic ? PETSC_FALSE : PETSC_TRUE; 2112 PetscDTNodeType nodeType = PETSCDTNODES_GAUSSJACOBI; 2113 2114 if (isSimplex) continuity = PETSC_FALSE; /* XXX FIXME Requires DMPlexSetClosurePermutationLexicographic() */ 2115 PetscCall(GmshCreateFE(comm, prefix, isSimplex, continuity, nodeType, dim, coordDim, order, &fe)); 2116 PetscCall(PetscFEViewFromOptions(fe, NULL, "-dm_plex_gmsh_project_fe_view")); 2117 PetscCall(DMSetCoordinateDisc(*dm, fe, PETSC_TRUE)); 2118 PetscCall(PetscFEDestroy(&fe)); 2119 } 2120 2121 PetscCall(PetscLogEventEnd(DMPLEX_CreateGmsh, *dm, NULL, NULL, NULL)); 2122 PetscFunctionReturn(PETSC_SUCCESS); 2123 } 2124