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