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