1 static char help[] = "Tests for parallel mesh loading and parallel topological interpolation\n\n"; 2 3 #include <petsc/private/dmpleximpl.h> 4 /* List of test meshes 5 6 Network 7 ------- 8 Test 0 (2 ranks): 9 10 network=0: 11 --------- 12 cell 0 cell 1 cell 2 nCells-1 (edge) 13 0 ------ 1 ------ 2 ------ 3 -- -- v -- -- nCells (vertex) 14 15 vertex distribution: 16 rank 0: 0 1 17 rank 1: 2 3 ... nCells 18 cell(edge) distribution: 19 rank 0: 0 1 20 rank 1: 2 ... nCells-1 21 22 network=1: 23 --------- 24 v2 25 ^ 26 | 27 cell 2 28 | 29 v0 --cell 0--> v3--cell 1--> v1 30 31 vertex distribution: 32 rank 0: 0 1 3 33 rank 1: 2 34 cell(edge) distribution: 35 rank 0: 0 1 36 rank 1: 2 37 38 example: 39 mpiexec -n 2 ./ex18 -distribute 1 -dim 1 -orig_dm_view -dist_dm_view -dist_dm_view -petscpartitioner_type parmetis -ncells 50 40 41 Triangle 42 -------- 43 Test 0 (2 ranks): 44 Two triangles sharing a face 45 46 2 47 / | \ 48 / | \ 49 / | \ 50 0 0 | 1 3 51 \ | / 52 \ | / 53 \ | / 54 1 55 56 vertex distribution: 57 rank 0: 0 1 58 rank 1: 2 3 59 cell distribution: 60 rank 0: 0 61 rank 1: 1 62 63 Test 1 (3 ranks): 64 Four triangles partitioned across 3 ranks 65 66 0 _______ 3 67 | \ / | 68 | \ 1 / | 69 | \ / | 70 | 0 2 2 | 71 | / \ | 72 | / 3 \ | 73 | / \ | 74 1 ------- 4 75 76 vertex distribution: 77 rank 0: 0 1 78 rank 1: 2 3 79 rank 2: 4 80 cell distribution: 81 rank 0: 0 82 rank 1: 1 83 rank 2: 2 3 84 85 Test 2 (3 ranks): 86 Four triangles partitioned across 3 ranks 87 88 1 _______ 3 89 | \ / | 90 | \ 1 / | 91 | \ / | 92 | 0 0 2 | 93 | / \ | 94 | / 3 \ | 95 | / \ | 96 2 ------- 4 97 98 vertex distribution: 99 rank 0: 0 1 100 rank 1: 2 3 101 rank 2: 4 102 cell distribution: 103 rank 0: 0 104 rank 1: 1 105 rank 2: 2 3 106 107 Tetrahedron 108 ----------- 109 Test 0: 110 Two tets sharing a face 111 112 cell 3 _______ cell 113 0 / | \ \ 1 114 / | \ \ 115 / | \ \ 116 0----|----4-----2 117 \ | / / 118 \ | / / 119 \ | / / 120 1------- 121 y 122 | x 123 |/ 124 *----z 125 126 vertex distribution: 127 rank 0: 0 1 128 rank 1: 2 3 4 129 cell distribution: 130 rank 0: 0 131 rank 1: 1 132 133 Quadrilateral 134 ------------- 135 Test 0 (2 ranks): 136 Two quads sharing a face 137 138 3-------2-------5 139 | | | 140 | 0 | 1 | 141 | | | 142 0-------1-------4 143 144 vertex distribution: 145 rank 0: 0 1 2 146 rank 1: 3 4 5 147 cell distribution: 148 rank 0: 0 149 rank 1: 1 150 151 TODO Test 1: 152 A quad and a triangle sharing a face 153 154 5-------4 155 | | \ 156 | 0 | \ 157 | | 1 \ 158 2-------3----6 159 160 Hexahedron 161 ---------- 162 Test 0 (2 ranks): 163 Two hexes sharing a face 164 165 cell 7-------------6-------------11 cell 166 0 /| /| /| 1 167 / | F1 / | F7 / | 168 / | / | / | 169 4-------------5-------------10 | 170 | | F4 | | F10 | | 171 | | | | | | 172 |F5 | |F3 | |F9 | 173 | | F2 | | F8 | | 174 | 3---------|---2---------|---9 175 | / | / | / 176 | / F0 | / F6 | / 177 |/ |/ |/ 178 0-------------1-------------8 179 180 vertex distribution: 181 rank 0: 0 1 2 3 4 5 182 rank 1: 6 7 8 9 10 11 183 cell distribution: 184 rank 0: 0 185 rank 1: 1 186 187 */ 188 189 typedef enum { 190 NONE, 191 CREATE, 192 AFTER_CREATE, 193 AFTER_DISTRIBUTE 194 } InterpType; 195 196 typedef struct { 197 PetscInt debug; /* The debugging level */ 198 PetscInt testNum; /* Indicates the mesh to create */ 199 PetscInt dim; /* The topological mesh dimension */ 200 PetscBool cellSimplex; /* Use simplices or hexes */ 201 PetscBool distribute; /* Distribute the mesh */ 202 InterpType interpolate; /* Interpolate the mesh before or after DMPlexDistribute() */ 203 PetscBool useGenerator; /* Construct mesh with a mesh generator */ 204 PetscBool testOrientIF; /* Test for different original interface orientations */ 205 PetscBool testHeavy; /* Run the heavy PointSF test */ 206 PetscBool customView; /* Show results of DMPlexIsInterpolated() etc. */ 207 PetscInt ornt[2]; /* Orientation of interface on rank 0 and rank 1 */ 208 PetscInt faces[3]; /* Number of faces per dimension for generator */ 209 PetscScalar coords[128]; 210 PetscReal coordsTol; 211 PetscInt ncoords; 212 PetscInt pointsToExpand[128]; 213 PetscInt nPointsToExpand; 214 PetscBool testExpandPointsEmpty; 215 char filename[PETSC_MAX_PATH_LEN]; /* Import mesh from file */ 216 } AppCtx; 217 218 struct _n_PortableBoundary { 219 Vec coordinates; 220 PetscInt depth; 221 PetscSection *sections; 222 }; 223 typedef struct _n_PortableBoundary *PortableBoundary; 224 225 #if defined(PETSC_USE_LOG) 226 static PetscLogStage stage[3]; 227 #endif 228 229 static PetscErrorCode DMPlexCheckPointSFHeavy(DM, PortableBoundary); 230 static PetscErrorCode DMPlexSetOrientInterface_Private(DM, PetscBool); 231 static PetscErrorCode DMPlexGetExpandedBoundary_Private(DM, PortableBoundary *); 232 static PetscErrorCode DMPlexExpandedConesToFaces_Private(DM, IS, PetscSection, IS *); 233 234 static PetscErrorCode PortableBoundaryDestroy(PortableBoundary *bnd) 235 { 236 PetscInt d; 237 238 PetscFunctionBegin; 239 if (!*bnd) PetscFunctionReturn(PETSC_SUCCESS); 240 PetscCall(VecDestroy(&(*bnd)->coordinates)); 241 for (d = 0; d < (*bnd)->depth; d++) PetscCall(PetscSectionDestroy(&(*bnd)->sections[d])); 242 PetscCall(PetscFree((*bnd)->sections)); 243 PetscCall(PetscFree(*bnd)); 244 PetscFunctionReturn(PETSC_SUCCESS); 245 } 246 247 static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options) 248 { 249 const char *interpTypes[4] = {"none", "create", "after_create", "after_distribute"}; 250 PetscInt interp = NONE, dim; 251 PetscBool flg1, flg2; 252 253 PetscFunctionBegin; 254 options->debug = 0; 255 options->testNum = 0; 256 options->dim = 2; 257 options->cellSimplex = PETSC_TRUE; 258 options->distribute = PETSC_FALSE; 259 options->interpolate = NONE; 260 options->useGenerator = PETSC_FALSE; 261 options->testOrientIF = PETSC_FALSE; 262 options->testHeavy = PETSC_TRUE; 263 options->customView = PETSC_FALSE; 264 options->testExpandPointsEmpty = PETSC_FALSE; 265 options->ornt[0] = 0; 266 options->ornt[1] = 0; 267 options->faces[0] = 2; 268 options->faces[1] = 2; 269 options->faces[2] = 2; 270 options->filename[0] = '\0'; 271 options->coordsTol = PETSC_DEFAULT; 272 273 PetscOptionsBegin(comm, "", "Meshing Interpolation Test Options", "DMPLEX"); 274 PetscCall(PetscOptionsBoundedInt("-debug", "The debugging level", "ex18.c", options->debug, &options->debug, NULL, 0)); 275 PetscCall(PetscOptionsBoundedInt("-testnum", "The mesh to create", "ex18.c", options->testNum, &options->testNum, NULL, 0)); 276 PetscCall(PetscOptionsBool("-cell_simplex", "Generate simplices if true, otherwise hexes", "ex18.c", options->cellSimplex, &options->cellSimplex, NULL)); 277 PetscCall(PetscOptionsBool("-distribute", "Distribute the mesh", "ex18.c", options->distribute, &options->distribute, NULL)); 278 PetscCall(PetscOptionsEList("-interpolate", "Type of mesh interpolation (none, create, after_create, after_distribute)", "ex18.c", interpTypes, 4, interpTypes[options->interpolate], &interp, NULL)); 279 options->interpolate = (InterpType)interp; 280 PetscCheck(options->distribute || options->interpolate != AFTER_DISTRIBUTE, comm, PETSC_ERR_SUP, "-interpolate after_distribute needs -distribute 1"); 281 PetscCall(PetscOptionsBool("-use_generator", "Use a mesh generator to build the mesh", "ex18.c", options->useGenerator, &options->useGenerator, NULL)); 282 options->ncoords = 128; 283 PetscCall(PetscOptionsScalarArray("-view_vertices_from_coords", "Print DAG points corresponding to vertices with given coordinates", "ex18.c", options->coords, &options->ncoords, NULL)); 284 PetscCall(PetscOptionsReal("-view_vertices_from_coords_tol", "Tolerance for -view_vertices_from_coords", "ex18.c", options->coordsTol, &options->coordsTol, NULL)); 285 options->nPointsToExpand = 128; 286 PetscCall(PetscOptionsIntArray("-test_expand_points", "Expand given array of DAG point using DMPlexGetConeRecursive() and print results", "ex18.c", options->pointsToExpand, &options->nPointsToExpand, NULL)); 287 if (options->nPointsToExpand) PetscCall(PetscOptionsBool("-test_expand_points_empty", "For -test_expand_points, rank 0 will have empty input array", "ex18.c", options->testExpandPointsEmpty, &options->testExpandPointsEmpty, NULL)); 288 PetscCall(PetscOptionsBool("-test_heavy", "Run the heavy PointSF test", "ex18.c", options->testHeavy, &options->testHeavy, NULL)); 289 PetscCall(PetscOptionsBool("-custom_view", "Custom DMPlex view", "ex18.c", options->customView, &options->customView, NULL)); 290 PetscCall(PetscOptionsRangeInt("-dim", "The topological mesh dimension", "ex18.c", options->dim, &options->dim, &flg1, 1, 3)); 291 dim = 3; 292 PetscCall(PetscOptionsIntArray("-faces", "Number of faces per dimension", "ex18.c", options->faces, &dim, &flg2)); 293 if (flg2) { 294 PetscCheck(!flg1 || dim == options->dim, comm, PETSC_ERR_ARG_OUTOFRANGE, "specified -dim %" PetscInt_FMT " is not equal to length %" PetscInt_FMT " of -faces (note that -dim can be omitted)", options->dim, dim); 295 options->dim = dim; 296 } 297 PetscCall(PetscOptionsString("-filename", "The mesh file", "ex18.c", options->filename, options->filename, sizeof(options->filename), NULL)); 298 PetscCall(PetscOptionsBoundedInt("-rotate_interface_0", "Rotation (relative orientation) of interface on rank 0; implies -interpolate create -distribute 0", "ex18.c", options->ornt[0], &options->ornt[0], &options->testOrientIF, 0)); 299 PetscCall(PetscOptionsBoundedInt("-rotate_interface_1", "Rotation (relative orientation) of interface on rank 1; implies -interpolate create -distribute 0", "ex18.c", options->ornt[1], &options->ornt[1], &flg2, 0)); 300 PetscCheck(flg2 == options->testOrientIF, comm, PETSC_ERR_ARG_OUTOFRANGE, "neither or both -rotate_interface_0 -rotate_interface_1 must be set"); 301 if (options->testOrientIF) { 302 PetscInt i; 303 for (i = 0; i < 2; i++) { 304 if (options->ornt[i] >= 10) options->ornt[i] = -(options->ornt[i] - 10); /* 11 12 13 become -1 -2 -3 */ 305 } 306 options->filename[0] = 0; 307 options->useGenerator = PETSC_FALSE; 308 options->dim = 3; 309 options->cellSimplex = PETSC_TRUE; 310 options->interpolate = CREATE; 311 options->distribute = PETSC_FALSE; 312 } 313 PetscOptionsEnd(); 314 PetscFunctionReturn(PETSC_SUCCESS); 315 } 316 317 static PetscErrorCode CreateMesh_1D(MPI_Comm comm, PetscBool interpolate, AppCtx *user, DM *dm) 318 { 319 PetscInt testNum = user->testNum; 320 PetscMPIInt rank, size; 321 PetscInt numCorners = 2, i; 322 PetscInt numCells, numVertices, network; 323 PetscInt *cells; 324 PetscReal *coords; 325 326 PetscFunctionBegin; 327 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 328 PetscCallMPI(MPI_Comm_size(comm, &size)); 329 PetscCheck(size <= 2, comm, PETSC_ERR_ARG_OUTOFRANGE, "Test mesh %" PetscInt_FMT " only for <=2 processes", testNum); 330 331 numCells = 3; 332 PetscCall(PetscOptionsGetInt(NULL, NULL, "-ncells", &numCells, NULL)); 333 PetscCheck(numCells >= 3, comm, PETSC_ERR_ARG_OUTOFRANGE, "Test ncells %" PetscInt_FMT " must >=3", numCells); 334 335 if (size == 1) { 336 numVertices = numCells + 1; 337 PetscCall(PetscMalloc2(2 * numCells, &cells, 2 * numVertices, &coords)); 338 for (i = 0; i < numCells; i++) { 339 cells[2 * i] = i; 340 cells[2 * i + 1] = i + 1; 341 coords[2 * i] = i; 342 coords[2 * i + 1] = i + 1; 343 } 344 345 PetscCall(DMPlexCreateFromCellListPetsc(comm, user->dim, numCells, numVertices, numCorners, PETSC_FALSE, cells, user->dim, coords, dm)); 346 PetscCall(PetscFree2(cells, coords)); 347 PetscFunctionReturn(PETSC_SUCCESS); 348 } 349 350 network = 0; 351 PetscCall(PetscOptionsGetInt(NULL, NULL, "-network_case", &network, NULL)); 352 if (network == 0) { 353 switch (rank) { 354 case 0: { 355 numCells = 2; 356 numVertices = numCells; 357 PetscCall(PetscMalloc2(2 * numCells, &cells, 2 * numCells, &coords)); 358 cells[0] = 0; 359 cells[1] = 1; 360 cells[2] = 1; 361 cells[3] = 2; 362 coords[0] = 0.; 363 coords[1] = 1.; 364 coords[2] = 1.; 365 coords[3] = 2.; 366 } break; 367 case 1: { 368 numCells -= 2; 369 numVertices = numCells + 1; 370 PetscCall(PetscMalloc2(2 * numCells, &cells, 2 * numCells, &coords)); 371 for (i = 0; i < numCells; i++) { 372 cells[2 * i] = 2 + i; 373 cells[2 * i + 1] = 2 + i + 1; 374 coords[2 * i] = 2 + i; 375 coords[2 * i + 1] = 2 + i + 1; 376 } 377 } break; 378 default: 379 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No test mesh for rank %d", rank); 380 } 381 } else { /* network_case = 1 */ 382 /* ----------------------- */ 383 switch (rank) { 384 case 0: { 385 numCells = 2; 386 numVertices = 3; 387 PetscCall(PetscMalloc2(2 * numCells, &cells, 2 * numCells, &coords)); 388 cells[0] = 0; 389 cells[1] = 3; 390 cells[2] = 3; 391 cells[3] = 1; 392 } break; 393 case 1: { 394 numCells = 1; 395 numVertices = 1; 396 PetscCall(PetscMalloc2(2 * numCells, &cells, 2 * numCells, &coords)); 397 cells[0] = 3; 398 cells[1] = 2; 399 } break; 400 default: 401 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No test mesh for rank %d", rank); 402 } 403 } 404 PetscCall(DMPlexCreateFromCellListParallelPetsc(comm, user->dim, numCells, numVertices, PETSC_DECIDE, numCorners, PETSC_FALSE, cells, user->dim, coords, NULL, NULL, dm)); 405 PetscCall(PetscFree2(cells, coords)); 406 PetscFunctionReturn(PETSC_SUCCESS); 407 } 408 409 static PetscErrorCode CreateSimplex_2D(MPI_Comm comm, PetscBool interpolate, AppCtx *user, DM *dm) 410 { 411 PetscInt testNum = user->testNum, p; 412 PetscMPIInt rank, size; 413 414 PetscFunctionBegin; 415 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 416 PetscCallMPI(MPI_Comm_size(comm, &size)); 417 switch (testNum) { 418 case 0: 419 PetscCheck(size == 2, comm, PETSC_ERR_ARG_OUTOFRANGE, "Test mesh %" PetscInt_FMT " only for 2 processes", testNum); 420 switch (rank) { 421 case 0: { 422 const PetscInt numCells = 1, numVertices = 2, numCorners = 3; 423 const PetscInt cells[3] = {0, 1, 2}; 424 PetscReal coords[4] = {-0.5, 0.5, 0.0, 0.0}; 425 PetscInt markerPoints[6] = {1, 1, 2, 1, 3, 1}; 426 427 PetscCall(DMPlexCreateFromCellListParallelPetsc(comm, user->dim, numCells, numVertices, PETSC_DECIDE, numCorners, interpolate, cells, user->dim, coords, NULL, NULL, dm)); 428 for (p = 0; p < 3; ++p) PetscCall(DMSetLabelValue(*dm, "marker", markerPoints[p * 2], markerPoints[p * 2 + 1])); 429 } break; 430 case 1: { 431 const PetscInt numCells = 1, numVertices = 2, numCorners = 3; 432 const PetscInt cells[3] = {1, 3, 2}; 433 PetscReal coords[4] = {0.0, 1.0, 0.5, 0.5}; 434 PetscInt markerPoints[6] = {1, 1, 2, 1, 3, 1}; 435 436 PetscCall(DMPlexCreateFromCellListParallelPetsc(comm, user->dim, numCells, numVertices, PETSC_DECIDE, numCorners, interpolate, cells, user->dim, coords, NULL, NULL, dm)); 437 for (p = 0; p < 3; ++p) PetscCall(DMSetLabelValue(*dm, "marker", markerPoints[p * 2], markerPoints[p * 2 + 1])); 438 } break; 439 default: 440 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No test mesh for rank %d", rank); 441 } 442 break; 443 case 1: 444 PetscCheck(size == 3, comm, PETSC_ERR_ARG_OUTOFRANGE, "Test mesh %" PetscInt_FMT " only for 3 processes", testNum); 445 switch (rank) { 446 case 0: { 447 const PetscInt numCells = 1, numVertices = 2, numCorners = 3; 448 const PetscInt cells[3] = {0, 1, 2}; 449 PetscReal coords[4] = {0.0, 1.0, 0.0, 0.0}; 450 PetscInt markerPoints[6] = {1, 1, 2, 1, 3, 1}; 451 452 PetscCall(DMPlexCreateFromCellListParallelPetsc(comm, user->dim, numCells, numVertices, PETSC_DECIDE, numCorners, interpolate, cells, user->dim, coords, NULL, NULL, dm)); 453 for (p = 0; p < 3; ++p) PetscCall(DMSetLabelValue(*dm, "marker", markerPoints[p * 2], markerPoints[p * 2 + 1])); 454 } break; 455 case 1: { 456 const PetscInt numCells = 1, numVertices = 2, numCorners = 3; 457 const PetscInt cells[3] = {0, 2, 3}; 458 PetscReal coords[4] = {0.5, 0.5, 1.0, 1.0}; 459 PetscInt markerPoints[6] = {1, 1, 2, 1, 3, 1}; 460 461 PetscCall(DMPlexCreateFromCellListParallelPetsc(comm, user->dim, numCells, numVertices, PETSC_DECIDE, numCorners, interpolate, cells, user->dim, coords, NULL, NULL, dm)); 462 for (p = 0; p < 3; ++p) PetscCall(DMSetLabelValue(*dm, "marker", markerPoints[p * 2], markerPoints[p * 2 + 1])); 463 } break; 464 case 2: { 465 const PetscInt numCells = 2, numVertices = 1, numCorners = 3; 466 const PetscInt cells[6] = {2, 4, 3, 2, 1, 4}; 467 PetscReal coords[2] = {1.0, 0.0}; 468 PetscInt markerPoints[10] = {2, 1, 3, 1, 4, 1, 5, 1, 6, 1}; 469 470 PetscCall(DMPlexCreateFromCellListParallelPetsc(comm, user->dim, numCells, numVertices, PETSC_DECIDE, numCorners, interpolate, cells, user->dim, coords, NULL, NULL, dm)); 471 for (p = 0; p < 3; ++p) PetscCall(DMSetLabelValue(*dm, "marker", markerPoints[p * 2], markerPoints[p * 2 + 1])); 472 } break; 473 default: 474 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No test mesh for rank %d", rank); 475 } 476 break; 477 case 2: 478 PetscCheck(size == 3, comm, PETSC_ERR_ARG_OUTOFRANGE, "Test mesh %" PetscInt_FMT " only for 3 processes", testNum); 479 switch (rank) { 480 case 0: { 481 const PetscInt numCells = 1, numVertices = 2, numCorners = 3; 482 const PetscInt cells[3] = {1, 2, 0}; 483 PetscReal coords[4] = {0.5, 0.5, 0.0, 1.0}; 484 PetscInt markerPoints[6] = {1, 1, 2, 1, 3, 1}; 485 486 PetscCall(DMPlexCreateFromCellListParallelPetsc(comm, user->dim, numCells, numVertices, PETSC_DECIDE, numCorners, interpolate, cells, user->dim, coords, NULL, NULL, dm)); 487 for (p = 0; p < 3; ++p) PetscCall(DMSetLabelValue(*dm, "marker", markerPoints[p * 2], markerPoints[p * 2 + 1])); 488 } break; 489 case 1: { 490 const PetscInt numCells = 1, numVertices = 2, numCorners = 3; 491 const PetscInt cells[3] = {1, 0, 3}; 492 PetscReal coords[4] = {0.0, 0.0, 1.0, 1.0}; 493 PetscInt markerPoints[6] = {1, 1, 2, 1, 3, 1}; 494 495 PetscCall(DMPlexCreateFromCellListParallelPetsc(comm, user->dim, numCells, numVertices, PETSC_DECIDE, numCorners, interpolate, cells, user->dim, coords, NULL, NULL, dm)); 496 for (p = 0; p < 3; ++p) PetscCall(DMSetLabelValue(*dm, "marker", markerPoints[p * 2], markerPoints[p * 2 + 1])); 497 } break; 498 case 2: { 499 const PetscInt numCells = 2, numVertices = 1, numCorners = 3; 500 const PetscInt cells[6] = {0, 4, 3, 0, 2, 4}; 501 PetscReal coords[2] = {1.0, 0.0}; 502 PetscInt markerPoints[10] = {2, 1, 3, 1, 4, 1, 5, 1, 6, 1}; 503 504 PetscCall(DMPlexCreateFromCellListParallelPetsc(comm, user->dim, numCells, numVertices, PETSC_DECIDE, numCorners, interpolate, cells, user->dim, coords, NULL, NULL, dm)); 505 for (p = 0; p < 3; ++p) PetscCall(DMSetLabelValue(*dm, "marker", markerPoints[p * 2], markerPoints[p * 2 + 1])); 506 } break; 507 default: 508 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No test mesh for rank %d", rank); 509 } 510 break; 511 default: 512 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "No test mesh %" PetscInt_FMT, testNum); 513 } 514 PetscFunctionReturn(PETSC_SUCCESS); 515 } 516 517 static PetscErrorCode CreateSimplex_3D(MPI_Comm comm, PetscBool interpolate, AppCtx *user, DM *dm) 518 { 519 PetscInt testNum = user->testNum, p; 520 PetscMPIInt rank, size; 521 522 PetscFunctionBegin; 523 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 524 PetscCallMPI(MPI_Comm_size(comm, &size)); 525 switch (testNum) { 526 case 0: 527 PetscCheck(size == 2, comm, PETSC_ERR_ARG_OUTOFRANGE, "Test mesh %" PetscInt_FMT " only for 2 processes", testNum); 528 switch (rank) { 529 case 0: { 530 const PetscInt numCells = 1, numVertices = 2, numCorners = 4; 531 const PetscInt cells[4] = {0, 2, 1, 3}; 532 PetscReal coords[6] = {0.0, 0.0, -0.5, 0.0, -0.5, 0.0}; 533 PetscInt markerPoints[8] = {1, 1, 2, 1, 3, 1, 4, 1}; 534 535 PetscCall(DMPlexCreateFromCellListParallelPetsc(comm, user->dim, numCells, numVertices, PETSC_DECIDE, numCorners, interpolate, cells, user->dim, coords, NULL, NULL, dm)); 536 for (p = 0; p < 4; ++p) PetscCall(DMSetLabelValue(*dm, "marker", markerPoints[p * 2], markerPoints[p * 2 + 1])); 537 } break; 538 case 1: { 539 const PetscInt numCells = 1, numVertices = 3, numCorners = 4; 540 const PetscInt cells[4] = {1, 2, 4, 3}; 541 PetscReal coords[9] = {1.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5}; 542 PetscInt markerPoints[8] = {1, 1, 2, 1, 3, 1, 4, 1}; 543 544 PetscCall(DMPlexCreateFromCellListParallelPetsc(comm, user->dim, numCells, numVertices, PETSC_DECIDE, numCorners, interpolate, cells, user->dim, coords, NULL, NULL, dm)); 545 for (p = 0; p < 4; ++p) PetscCall(DMSetLabelValue(*dm, "marker", markerPoints[p * 2], markerPoints[p * 2 + 1])); 546 } break; 547 default: 548 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No test mesh for rank %d", rank); 549 } 550 break; 551 default: 552 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "No test mesh %" PetscInt_FMT, testNum); 553 } 554 if (user->testOrientIF) { 555 PetscInt ifp[] = {8, 6}; 556 557 PetscCall(PetscObjectSetName((PetscObject)*dm, "Mesh before orientation")); 558 PetscCall(DMViewFromOptions(*dm, NULL, "-before_orientation_dm_view")); 559 /* rotate interface face ifp[rank] by given orientation ornt[rank] */ 560 PetscCall(DMPlexOrientPoint(*dm, ifp[rank], user->ornt[rank])); 561 PetscCall(DMViewFromOptions(*dm, NULL, "-before_orientation_dm_view")); 562 PetscCall(DMPlexCheckFaces(*dm, 0)); 563 PetscCall(DMPlexOrientInterface_Internal(*dm)); 564 PetscCall(PetscPrintf(comm, "Orientation test PASSED\n")); 565 } 566 PetscFunctionReturn(PETSC_SUCCESS); 567 } 568 569 static PetscErrorCode CreateQuad_2D(MPI_Comm comm, PetscBool interpolate, AppCtx *user, DM *dm) 570 { 571 PetscInt testNum = user->testNum, p; 572 PetscMPIInt rank, size; 573 574 PetscFunctionBegin; 575 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 576 PetscCallMPI(MPI_Comm_size(comm, &size)); 577 switch (testNum) { 578 case 0: 579 PetscCheck(size == 2, comm, PETSC_ERR_ARG_OUTOFRANGE, "Test mesh %" PetscInt_FMT " only for 2 processes", testNum); 580 switch (rank) { 581 case 0: { 582 const PetscInt numCells = 1, numVertices = 3, numCorners = 4; 583 const PetscInt cells[4] = {0, 1, 2, 3}; 584 PetscReal coords[6] = {-0.5, 0.0, 0.0, 0.0, 0.0, 1.0}; 585 PetscInt markerPoints[4 * 2] = {1, 1, 2, 1, 3, 1, 4, 1}; 586 587 PetscCall(DMPlexCreateFromCellListParallelPetsc(comm, user->dim, numCells, numVertices, PETSC_DECIDE, numCorners, interpolate, cells, user->dim, coords, NULL, NULL, dm)); 588 for (p = 0; p < 4; ++p) PetscCall(DMSetLabelValue(*dm, "marker", markerPoints[p * 2], markerPoints[p * 2 + 1])); 589 } break; 590 case 1: { 591 const PetscInt numCells = 1, numVertices = 3, numCorners = 4; 592 const PetscInt cells[4] = {1, 4, 5, 2}; 593 PetscReal coords[6] = {-0.5, 1.0, 0.5, 0.0, 0.5, 1.0}; 594 PetscInt markerPoints[4 * 2] = {1, 1, 2, 1, 3, 1, 4, 1}; 595 596 PetscCall(DMPlexCreateFromCellListParallelPetsc(comm, user->dim, numCells, numVertices, PETSC_DECIDE, numCorners, interpolate, cells, user->dim, coords, NULL, NULL, dm)); 597 for (p = 0; p < 4; ++p) PetscCall(DMSetLabelValue(*dm, "marker", markerPoints[p * 2], markerPoints[p * 2 + 1])); 598 } break; 599 default: 600 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No test mesh for rank %d", rank); 601 } 602 break; 603 default: 604 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "No test mesh %" PetscInt_FMT, testNum); 605 } 606 PetscFunctionReturn(PETSC_SUCCESS); 607 } 608 609 static PetscErrorCode CreateHex_3D(MPI_Comm comm, PetscBool interpolate, AppCtx *user, DM *dm) 610 { 611 PetscInt testNum = user->testNum, p; 612 PetscMPIInt rank, size; 613 614 PetscFunctionBegin; 615 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 616 PetscCallMPI(MPI_Comm_size(comm, &size)); 617 switch (testNum) { 618 case 0: 619 PetscCheck(size == 2, comm, PETSC_ERR_ARG_OUTOFRANGE, "Test mesh %" PetscInt_FMT " only for 2 processes", testNum); 620 switch (rank) { 621 case 0: { 622 const PetscInt numCells = 1, numVertices = 6, numCorners = 8; 623 const PetscInt cells[8] = {0, 3, 2, 1, 4, 5, 6, 7}; 624 PetscReal coords[6 * 3] = {-0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -0.5, 1.0, 0.0, -0.5, 0.0, 1.0, 0.0, 0.0, 1.0}; 625 PetscInt markerPoints[8 * 2] = {2, 1, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1}; 626 627 PetscCall(DMPlexCreateFromCellListParallelPetsc(comm, user->dim, numCells, numVertices, PETSC_DECIDE, numCorners, interpolate, cells, user->dim, coords, NULL, NULL, dm)); 628 for (p = 0; p < 4; ++p) PetscCall(DMSetLabelValue(*dm, "marker", markerPoints[p * 2], markerPoints[p * 2 + 1])); 629 } break; 630 case 1: { 631 const PetscInt numCells = 1, numVertices = 6, numCorners = 8; 632 const PetscInt cells[8] = {1, 2, 9, 8, 5, 10, 11, 6}; 633 PetscReal coords[6 * 3] = {0.0, 1.0, 1.0, -0.5, 1.0, 1.0, 0.5, 0.0, 0.0, 0.5, 1.0, 0.0, 0.5, 0.0, 1.0, 0.5, 1.0, 1.0}; 634 PetscInt markerPoints[8 * 2] = {2, 1, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, 9, 1}; 635 636 PetscCall(DMPlexCreateFromCellListParallelPetsc(comm, user->dim, numCells, numVertices, PETSC_DECIDE, numCorners, interpolate, cells, user->dim, coords, NULL, NULL, dm)); 637 for (p = 0; p < 4; ++p) PetscCall(DMSetLabelValue(*dm, "marker", markerPoints[p * 2], markerPoints[p * 2 + 1])); 638 } break; 639 default: 640 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No test mesh for rank %d", rank); 641 } 642 break; 643 default: 644 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "No test mesh %" PetscInt_FMT, testNum); 645 } 646 PetscFunctionReturn(PETSC_SUCCESS); 647 } 648 649 static PetscErrorCode CustomView(DM dm, PetscViewer v) 650 { 651 DMPlexInterpolatedFlag interpolated; 652 PetscBool distributed; 653 654 PetscFunctionBegin; 655 PetscCall(DMPlexIsDistributed(dm, &distributed)); 656 PetscCall(DMPlexIsInterpolatedCollective(dm, &interpolated)); 657 PetscCall(PetscViewerASCIIPrintf(v, "DMPlexIsDistributed: %s\n", PetscBools[distributed])); 658 PetscCall(PetscViewerASCIIPrintf(v, "DMPlexIsInterpolatedCollective: %s\n", DMPlexInterpolatedFlags[interpolated])); 659 PetscFunctionReturn(PETSC_SUCCESS); 660 } 661 662 static PetscErrorCode CreateMeshFromFile(MPI_Comm comm, AppCtx *user, DM *dm, DM *serialDM) 663 { 664 const char *filename = user->filename; 665 PetscBool testHeavy = user->testHeavy; 666 PetscBool interpCreate = user->interpolate == CREATE ? PETSC_TRUE : PETSC_FALSE; 667 PetscBool distributed = PETSC_FALSE; 668 669 PetscFunctionBegin; 670 *serialDM = NULL; 671 if (testHeavy && interpCreate) PetscCall(DMPlexSetOrientInterface_Private(NULL, PETSC_FALSE)); 672 PetscCall(PetscLogStagePush(stage[0])); 673 PetscCall(DMPlexCreateFromFile(comm, filename, "ex18_plex", interpCreate, dm)); /* with DMPlexOrientInterface_Internal() call skipped so that PointSF issues are left to DMPlexCheckPointSFHeavy() */ 674 PetscCall(PetscLogStagePop()); 675 if (testHeavy && interpCreate) PetscCall(DMPlexSetOrientInterface_Private(NULL, PETSC_TRUE)); 676 PetscCall(DMPlexIsDistributed(*dm, &distributed)); 677 PetscCall(PetscPrintf(comm, "DMPlexCreateFromFile produced %s mesh.\n", distributed ? "distributed" : "serial")); 678 if (testHeavy && distributed) { 679 PetscCall(PetscOptionsSetValue(NULL, "-dm_plex_hdf5_force_sequential", NULL)); 680 PetscCall(DMPlexCreateFromFile(comm, filename, "ex18_plex", interpCreate, serialDM)); 681 PetscCall(DMPlexIsDistributed(*serialDM, &distributed)); 682 PetscCheck(!distributed, comm, PETSC_ERR_PLIB, "unable to create a serial DM from file"); 683 } 684 PetscCall(DMGetDimension(*dm, &user->dim)); 685 PetscFunctionReturn(PETSC_SUCCESS); 686 } 687 688 static PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *user, DM *dm) 689 { 690 PetscPartitioner part; 691 PortableBoundary boundary = NULL; 692 DM serialDM = NULL; 693 PetscBool cellSimplex = user->cellSimplex; 694 PetscBool useGenerator = user->useGenerator; 695 PetscBool interpCreate = user->interpolate == CREATE ? PETSC_TRUE : PETSC_FALSE; 696 PetscBool interpSerial = user->interpolate == AFTER_CREATE ? PETSC_TRUE : PETSC_FALSE; 697 PetscBool interpParallel = user->interpolate == AFTER_DISTRIBUTE ? PETSC_TRUE : PETSC_FALSE; 698 PetscBool testHeavy = user->testHeavy; 699 PetscMPIInt rank; 700 701 PetscFunctionBegin; 702 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 703 if (user->filename[0]) { 704 PetscCall(CreateMeshFromFile(comm, user, dm, &serialDM)); 705 } else if (useGenerator) { 706 PetscCall(PetscLogStagePush(stage[0])); 707 PetscCall(DMPlexCreateBoxMesh(comm, user->dim, cellSimplex, user->faces, NULL, NULL, NULL, interpCreate, dm)); 708 PetscCall(PetscLogStagePop()); 709 } else { 710 PetscCall(PetscLogStagePush(stage[0])); 711 switch (user->dim) { 712 case 1: 713 PetscCall(CreateMesh_1D(comm, interpCreate, user, dm)); 714 break; 715 case 2: 716 if (cellSimplex) { 717 PetscCall(CreateSimplex_2D(comm, interpCreate, user, dm)); 718 } else { 719 PetscCall(CreateQuad_2D(comm, interpCreate, user, dm)); 720 } 721 break; 722 case 3: 723 if (cellSimplex) { 724 PetscCall(CreateSimplex_3D(comm, interpCreate, user, dm)); 725 } else { 726 PetscCall(CreateHex_3D(comm, interpCreate, user, dm)); 727 } 728 break; 729 default: 730 SETERRQ(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot make meshes for dimension %" PetscInt_FMT, user->dim); 731 } 732 PetscCall(PetscLogStagePop()); 733 } 734 PetscCheck(user->ncoords % user->dim == 0, comm, PETSC_ERR_ARG_OUTOFRANGE, "length of coordinates array %" PetscInt_FMT " must be divisible by spatial dimension %" PetscInt_FMT, user->ncoords, user->dim); 735 PetscCall(PetscObjectSetName((PetscObject)*dm, "Original Mesh")); 736 PetscCall(DMViewFromOptions(*dm, NULL, "-orig_dm_view")); 737 738 if (interpSerial) { 739 DM idm; 740 741 if (testHeavy) PetscCall(DMPlexSetOrientInterface_Private(*dm, PETSC_FALSE)); 742 PetscCall(PetscLogStagePush(stage[2])); 743 PetscCall(DMPlexInterpolate(*dm, &idm)); /* with DMPlexOrientInterface_Internal() call skipped so that PointSF issues are left to DMPlexCheckPointSFHeavy() */ 744 PetscCall(PetscLogStagePop()); 745 if (testHeavy) PetscCall(DMPlexSetOrientInterface_Private(*dm, PETSC_TRUE)); 746 PetscCall(DMDestroy(dm)); 747 *dm = idm; 748 PetscCall(PetscObjectSetName((PetscObject)*dm, "Interpolated Mesh")); 749 PetscCall(DMViewFromOptions(*dm, NULL, "-intp_dm_view")); 750 } 751 752 /* Set partitioner options */ 753 PetscCall(DMPlexGetPartitioner(*dm, &part)); 754 if (part) { 755 PetscCall(PetscPartitionerSetType(part, PETSCPARTITIONERSIMPLE)); 756 PetscCall(PetscPartitionerSetFromOptions(part)); 757 } 758 759 if (user->customView) PetscCall(CustomView(*dm, PETSC_VIEWER_STDOUT_(comm))); 760 if (testHeavy) { 761 PetscBool distributed; 762 763 PetscCall(DMPlexIsDistributed(*dm, &distributed)); 764 if (!serialDM && !distributed) { 765 serialDM = *dm; 766 PetscCall(PetscObjectReference((PetscObject)*dm)); 767 } 768 if (serialDM) PetscCall(DMPlexGetExpandedBoundary_Private(serialDM, &boundary)); 769 if (boundary) { 770 /* check DM which has been created in parallel and already interpolated */ 771 PetscCall(DMPlexCheckPointSFHeavy(*dm, boundary)); 772 } 773 /* Orient interface because it could be deliberately skipped above. It is idempotent. */ 774 PetscCall(DMPlexOrientInterface_Internal(*dm)); 775 } 776 if (user->distribute) { 777 DM pdm = NULL; 778 779 /* Redistribute mesh over processes using that partitioner */ 780 PetscCall(PetscLogStagePush(stage[1])); 781 PetscCall(DMPlexDistribute(*dm, 0, NULL, &pdm)); 782 PetscCall(PetscLogStagePop()); 783 if (pdm) { 784 PetscCall(DMDestroy(dm)); 785 *dm = pdm; 786 PetscCall(PetscObjectSetName((PetscObject)*dm, "Redistributed Mesh")); 787 PetscCall(DMViewFromOptions(*dm, NULL, "-dist_dm_view")); 788 } 789 790 if (interpParallel) { 791 DM idm; 792 793 if (testHeavy) PetscCall(DMPlexSetOrientInterface_Private(*dm, PETSC_FALSE)); 794 PetscCall(PetscLogStagePush(stage[2])); 795 PetscCall(DMPlexInterpolate(*dm, &idm)); /* with DMPlexOrientInterface_Internal() call skipped so that PointSF issues are left to DMPlexCheckPointSFHeavy() */ 796 PetscCall(PetscLogStagePop()); 797 if (testHeavy) PetscCall(DMPlexSetOrientInterface_Private(*dm, PETSC_TRUE)); 798 PetscCall(DMDestroy(dm)); 799 *dm = idm; 800 PetscCall(PetscObjectSetName((PetscObject)*dm, "Interpolated Redistributed Mesh")); 801 PetscCall(DMViewFromOptions(*dm, NULL, "-intp_dm_view")); 802 } 803 } 804 if (testHeavy) { 805 if (boundary) PetscCall(DMPlexCheckPointSFHeavy(*dm, boundary)); 806 /* Orient interface because it could be deliberately skipped above. It is idempotent. */ 807 PetscCall(DMPlexOrientInterface_Internal(*dm)); 808 } 809 810 PetscCall(PetscObjectSetName((PetscObject)*dm, "Parallel Mesh")); 811 PetscCall(DMPlexDistributeSetDefault(*dm, PETSC_FALSE)); 812 PetscCall(DMSetFromOptions(*dm)); 813 PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view")); 814 815 if (user->customView) PetscCall(CustomView(*dm, PETSC_VIEWER_STDOUT_(comm))); 816 PetscCall(DMDestroy(&serialDM)); 817 PetscCall(PortableBoundaryDestroy(&boundary)); 818 PetscFunctionReturn(PETSC_SUCCESS); 819 } 820 821 #define ps2d(number) ((double)PetscRealPart(number)) 822 static inline PetscErrorCode coord2str(char buf[], size_t len, PetscInt dim, const PetscScalar coords[], PetscReal tol) 823 { 824 PetscFunctionBegin; 825 PetscCheck(dim <= 3, PETSC_COMM_SELF, PETSC_ERR_SUP, "dim must be less than or equal 3"); 826 if (tol >= 1e-3) { 827 switch (dim) { 828 case 1: 829 PetscCall(PetscSNPrintf(buf, len, "(%12.3f)", ps2d(coords[0]))); 830 case 2: 831 PetscCall(PetscSNPrintf(buf, len, "(%12.3f, %12.3f)", ps2d(coords[0]), ps2d(coords[1]))); 832 case 3: 833 PetscCall(PetscSNPrintf(buf, len, "(%12.3f, %12.3f, %12.3f)", ps2d(coords[0]), ps2d(coords[1]), ps2d(coords[2]))); 834 } 835 } else { 836 switch (dim) { 837 case 1: 838 PetscCall(PetscSNPrintf(buf, len, "(%12.6f)", ps2d(coords[0]))); 839 case 2: 840 PetscCall(PetscSNPrintf(buf, len, "(%12.6f, %12.6f)", ps2d(coords[0]), ps2d(coords[1]))); 841 case 3: 842 PetscCall(PetscSNPrintf(buf, len, "(%12.6f, %12.6f, %12.6f)", ps2d(coords[0]), ps2d(coords[1]), ps2d(coords[2]))); 843 } 844 } 845 PetscFunctionReturn(PETSC_SUCCESS); 846 } 847 848 static PetscErrorCode ViewVerticesFromCoords(DM dm, Vec coordsVec, PetscReal tol, PetscViewer viewer) 849 { 850 PetscInt dim, i, npoints; 851 IS pointsIS; 852 const PetscInt *points; 853 const PetscScalar *coords; 854 char coordstr[128]; 855 MPI_Comm comm; 856 PetscMPIInt rank; 857 858 PetscFunctionBegin; 859 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 860 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 861 PetscCall(DMGetDimension(dm, &dim)); 862 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 863 PetscCall(DMPlexFindVertices(dm, coordsVec, tol, &pointsIS)); 864 PetscCall(ISGetIndices(pointsIS, &points)); 865 PetscCall(ISGetLocalSize(pointsIS, &npoints)); 866 PetscCall(VecGetArrayRead(coordsVec, &coords)); 867 for (i = 0; i < npoints; i++) { 868 PetscCall(coord2str(coordstr, sizeof(coordstr), dim, &coords[i * dim], tol)); 869 if (rank == 0 && i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "-----\n")); 870 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] %s --> points[%" PetscInt_FMT "] = %" PetscInt_FMT "\n", rank, coordstr, i, points[i])); 871 PetscCall(PetscViewerFlush(viewer)); 872 } 873 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 874 PetscCall(VecRestoreArrayRead(coordsVec, &coords)); 875 PetscCall(ISRestoreIndices(pointsIS, &points)); 876 PetscCall(ISDestroy(&pointsIS)); 877 PetscFunctionReturn(PETSC_SUCCESS); 878 } 879 880 static PetscErrorCode TestExpandPoints(DM dm, AppCtx *user) 881 { 882 IS is; 883 PetscSection *sects; 884 IS *iss; 885 PetscInt d, depth; 886 PetscMPIInt rank; 887 PetscViewer viewer = PETSC_VIEWER_STDOUT_WORLD, sviewer; 888 889 PetscFunctionBegin; 890 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 891 if (user->testExpandPointsEmpty && rank == 0) { 892 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 0, NULL, PETSC_USE_POINTER, &is)); 893 } else { 894 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, user->nPointsToExpand, user->pointsToExpand, PETSC_USE_POINTER, &is)); 895 } 896 PetscCall(DMPlexGetConeRecursive(dm, is, &depth, &iss, §s)); 897 PetscCall(PetscViewerGetSubViewer(viewer, PETSC_COMM_SELF, &sviewer)); 898 PetscCall(PetscViewerASCIIPrintf(sviewer, "[%d] ==========================\n", rank)); 899 for (d = depth - 1; d >= 0; d--) { 900 IS checkIS; 901 PetscBool flg; 902 903 PetscCall(PetscViewerASCIIPrintf(sviewer, "depth %" PetscInt_FMT " ---------------\n", d)); 904 PetscCall(PetscSectionView(sects[d], sviewer)); 905 PetscCall(ISView(iss[d], sviewer)); 906 /* check reverse operation */ 907 if (d < depth - 1) { 908 PetscCall(DMPlexExpandedConesToFaces_Private(dm, iss[d], sects[d], &checkIS)); 909 PetscCall(ISEqualUnsorted(checkIS, iss[d + 1], &flg)); 910 PetscCheck(flg, PetscObjectComm((PetscObject)checkIS), PETSC_ERR_PLIB, "DMPlexExpandedConesToFaces_Private produced wrong IS"); 911 PetscCall(ISDestroy(&checkIS)); 912 } 913 } 914 PetscCall(PetscViewerRestoreSubViewer(viewer, PETSC_COMM_SELF, &sviewer)); 915 PetscCall(PetscViewerFlush(viewer)); 916 PetscCall(DMPlexRestoreConeRecursive(dm, is, &depth, &iss, §s)); 917 PetscCall(ISDestroy(&is)); 918 PetscFunctionReturn(PETSC_SUCCESS); 919 } 920 921 static PetscErrorCode DMPlexExpandedConesToFaces_Private(DM dm, IS is, PetscSection section, IS *newis) 922 { 923 PetscInt n, n1, ncone, numCoveredPoints, o, p, q, start, end; 924 const PetscInt *coveredPoints; 925 const PetscInt *arr, *cone; 926 PetscInt *newarr; 927 928 PetscFunctionBegin; 929 PetscCall(ISGetLocalSize(is, &n)); 930 PetscCall(PetscSectionGetStorageSize(section, &n1)); 931 PetscCall(PetscSectionGetChart(section, &start, &end)); 932 PetscCheck(n == n1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "IS size = %" PetscInt_FMT " != %" PetscInt_FMT " = section storage size", n, n1); 933 PetscCall(ISGetIndices(is, &arr)); 934 PetscCall(PetscMalloc1(end - start, &newarr)); 935 for (q = start; q < end; q++) { 936 PetscCall(PetscSectionGetDof(section, q, &ncone)); 937 PetscCall(PetscSectionGetOffset(section, q, &o)); 938 cone = &arr[o]; 939 if (ncone == 1) { 940 numCoveredPoints = 1; 941 p = cone[0]; 942 } else { 943 PetscInt i; 944 p = PETSC_MAX_INT; 945 for (i = 0; i < ncone; i++) 946 if (cone[i] < 0) { 947 p = -1; 948 break; 949 } 950 if (p >= 0) { 951 PetscCall(DMPlexGetJoin(dm, ncone, cone, &numCoveredPoints, &coveredPoints)); 952 PetscCheck(numCoveredPoints <= 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "more than one covered points for section point %" PetscInt_FMT, q); 953 if (numCoveredPoints) p = coveredPoints[0]; 954 else p = -2; 955 PetscCall(DMPlexRestoreJoin(dm, ncone, cone, &numCoveredPoints, &coveredPoints)); 956 } 957 } 958 newarr[q - start] = p; 959 } 960 PetscCall(ISRestoreIndices(is, &arr)); 961 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, end - start, newarr, PETSC_OWN_POINTER, newis)); 962 PetscFunctionReturn(PETSC_SUCCESS); 963 } 964 965 static PetscErrorCode DMPlexExpandedVerticesToFaces_Private(DM dm, IS boundary_expanded_is, PetscInt depth, PetscSection sections[], IS *boundary_is) 966 { 967 PetscInt d; 968 IS is, newis; 969 970 PetscFunctionBegin; 971 is = boundary_expanded_is; 972 PetscCall(PetscObjectReference((PetscObject)is)); 973 for (d = 0; d < depth - 1; ++d) { 974 PetscCall(DMPlexExpandedConesToFaces_Private(dm, is, sections[d], &newis)); 975 PetscCall(ISDestroy(&is)); 976 is = newis; 977 } 978 *boundary_is = is; 979 PetscFunctionReturn(PETSC_SUCCESS); 980 } 981 982 #define CHKERRQI(incall, ierr) \ 983 if (ierr) incall = PETSC_FALSE; 984 985 static PetscErrorCode DMLabelViewFromOptionsOnComm_Private(DMLabel label, const char optionname[], MPI_Comm comm) 986 { 987 PetscViewer viewer; 988 PetscBool flg; 989 static PetscBool incall = PETSC_FALSE; 990 PetscViewerFormat format; 991 992 PetscFunctionBegin; 993 if (incall) PetscFunctionReturn(PETSC_SUCCESS); 994 incall = PETSC_TRUE; 995 CHKERRQI(incall, PetscOptionsGetViewer(comm, ((PetscObject)label)->options, ((PetscObject)label)->prefix, optionname, &viewer, &format, &flg)); 996 if (flg) { 997 CHKERRQI(incall, PetscViewerPushFormat(viewer, format)); 998 CHKERRQI(incall, DMLabelView(label, viewer)); 999 CHKERRQI(incall, PetscViewerPopFormat(viewer)); 1000 CHKERRQI(incall, PetscViewerDestroy(&viewer)); 1001 } 1002 incall = PETSC_FALSE; 1003 PetscFunctionReturn(PETSC_SUCCESS); 1004 } 1005 1006 /* TODO: this is hotfixing DMLabelGetStratumIS() - it should be fixed systematically instead */ 1007 static inline PetscErrorCode DMLabelGetStratumISOnComm_Private(DMLabel label, PetscInt value, MPI_Comm comm, IS *is) 1008 { 1009 IS tmpis; 1010 1011 PetscFunctionBegin; 1012 PetscCall(DMLabelGetStratumIS(label, value, &tmpis)); 1013 if (!tmpis) PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 0, NULL, PETSC_USE_POINTER, &tmpis)); 1014 PetscCall(ISOnComm(tmpis, comm, PETSC_COPY_VALUES, is)); 1015 PetscCall(ISDestroy(&tmpis)); 1016 PetscFunctionReturn(PETSC_SUCCESS); 1017 } 1018 1019 /* currently only for simple PetscSection without fields or constraints */ 1020 static PetscErrorCode PetscSectionReplicate_Private(MPI_Comm comm, PetscMPIInt rootrank, PetscSection sec0, PetscSection *secout) 1021 { 1022 PetscSection sec; 1023 PetscInt chart[2], p; 1024 PetscInt *dofarr; 1025 PetscMPIInt rank; 1026 1027 PetscFunctionBegin; 1028 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1029 if (rank == rootrank) PetscCall(PetscSectionGetChart(sec0, &chart[0], &chart[1])); 1030 PetscCallMPI(MPI_Bcast(chart, 2, MPIU_INT, rootrank, comm)); 1031 PetscCall(PetscMalloc1(chart[1] - chart[0], &dofarr)); 1032 if (rank == rootrank) { 1033 for (p = chart[0]; p < chart[1]; p++) PetscCall(PetscSectionGetDof(sec0, p, &dofarr[p - chart[0]])); 1034 } 1035 PetscCallMPI(MPI_Bcast(dofarr, chart[1] - chart[0], MPIU_INT, rootrank, comm)); 1036 PetscCall(PetscSectionCreate(comm, &sec)); 1037 PetscCall(PetscSectionSetChart(sec, chart[0], chart[1])); 1038 for (p = chart[0]; p < chart[1]; p++) PetscCall(PetscSectionSetDof(sec, p, dofarr[p - chart[0]])); 1039 PetscCall(PetscSectionSetUp(sec)); 1040 PetscCall(PetscFree(dofarr)); 1041 *secout = sec; 1042 PetscFunctionReturn(PETSC_SUCCESS); 1043 } 1044 1045 static PetscErrorCode DMPlexExpandedVerticesCoordinatesToFaces_Private(DM ipdm, PortableBoundary bnd, IS *face_is) 1046 { 1047 IS faces_expanded_is; 1048 1049 PetscFunctionBegin; 1050 PetscCall(DMPlexFindVertices(ipdm, bnd->coordinates, 0.0, &faces_expanded_is)); 1051 PetscCall(DMPlexExpandedVerticesToFaces_Private(ipdm, faces_expanded_is, bnd->depth, bnd->sections, face_is)); 1052 PetscCall(ISDestroy(&faces_expanded_is)); 1053 PetscFunctionReturn(PETSC_SUCCESS); 1054 } 1055 1056 /* hack disabling DMPlexOrientInterface() call in DMPlexInterpolate() via -dm_plex_interpolate_orient_interfaces option */ 1057 static PetscErrorCode DMPlexSetOrientInterface_Private(DM dm, PetscBool enable) 1058 { 1059 PetscOptions options = NULL; 1060 const char *prefix = NULL; 1061 const char opt[] = "-dm_plex_interpolate_orient_interfaces"; 1062 char prefix_opt[512]; 1063 PetscBool flg, set; 1064 static PetscBool wasSetTrue = PETSC_FALSE; 1065 1066 PetscFunctionBegin; 1067 if (dm) { 1068 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 1069 options = ((PetscObject)dm)->options; 1070 } 1071 PetscCall(PetscStrncpy(prefix_opt, "-", sizeof(prefix_opt))); 1072 PetscCall(PetscStrlcat(prefix_opt, prefix, sizeof(prefix_opt))); 1073 PetscCall(PetscStrlcat(prefix_opt, &opt[1], sizeof(prefix_opt))); 1074 PetscCall(PetscOptionsGetBool(options, prefix, opt, &flg, &set)); 1075 if (!enable) { 1076 if (set && flg) wasSetTrue = PETSC_TRUE; 1077 PetscCall(PetscOptionsSetValue(options, prefix_opt, "0")); 1078 } else if (set && !flg) { 1079 if (wasSetTrue) { 1080 PetscCall(PetscOptionsSetValue(options, prefix_opt, "1")); 1081 } else { 1082 /* default is PETSC_TRUE */ 1083 PetscCall(PetscOptionsClearValue(options, prefix_opt)); 1084 } 1085 wasSetTrue = PETSC_FALSE; 1086 } 1087 if (PetscDefined(USE_DEBUG)) { 1088 PetscCall(PetscOptionsGetBool(options, prefix, opt, &flg, &set)); 1089 PetscCheck(!set || flg == enable, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "PetscOptionsSetValue did not have the desired effect"); 1090 } 1091 PetscFunctionReturn(PETSC_SUCCESS); 1092 } 1093 1094 /* get coordinate description of the whole-domain boundary */ 1095 static PetscErrorCode DMPlexGetExpandedBoundary_Private(DM dm, PortableBoundary *boundary) 1096 { 1097 PortableBoundary bnd0, bnd; 1098 MPI_Comm comm; 1099 DM idm; 1100 DMLabel label; 1101 PetscInt d; 1102 const char boundaryName[] = "DMPlexDistributeInterpolateMarkInterface_boundary"; 1103 IS boundary_is; 1104 IS *boundary_expanded_iss; 1105 PetscMPIInt rootrank = 0; 1106 PetscMPIInt rank, size; 1107 PetscInt value = 1; 1108 DMPlexInterpolatedFlag intp; 1109 PetscBool flg; 1110 1111 PetscFunctionBegin; 1112 PetscCall(PetscNew(&bnd)); 1113 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1114 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 1115 PetscCallMPI(MPI_Comm_size(comm, &size)); 1116 PetscCall(DMPlexIsDistributed(dm, &flg)); 1117 PetscCheck(!flg, comm, PETSC_ERR_ARG_WRONG, "serial DM (all points on one rank) needed"); 1118 1119 /* interpolate serial DM if not yet interpolated */ 1120 PetscCall(DMPlexIsInterpolatedCollective(dm, &intp)); 1121 if (intp == DMPLEX_INTERPOLATED_FULL) { 1122 idm = dm; 1123 PetscCall(PetscObjectReference((PetscObject)dm)); 1124 } else { 1125 PetscCall(DMPlexInterpolate(dm, &idm)); 1126 PetscCall(DMViewFromOptions(idm, NULL, "-idm_view")); 1127 } 1128 1129 /* mark whole-domain boundary of the serial DM */ 1130 PetscCall(DMLabelCreate(PETSC_COMM_SELF, boundaryName, &label)); 1131 PetscCall(DMAddLabel(idm, label)); 1132 PetscCall(DMPlexMarkBoundaryFaces(idm, value, label)); 1133 PetscCall(DMLabelViewFromOptionsOnComm_Private(label, "-idm_boundary_view", comm)); 1134 PetscCall(DMLabelGetStratumIS(label, value, &boundary_is)); 1135 1136 /* translate to coordinates */ 1137 PetscCall(PetscNew(&bnd0)); 1138 PetscCall(DMGetCoordinatesLocalSetUp(idm)); 1139 if (rank == rootrank) { 1140 PetscCall(DMPlexGetConeRecursive(idm, boundary_is, &bnd0->depth, &boundary_expanded_iss, &bnd0->sections)); 1141 PetscCall(DMGetCoordinatesLocalTuple(dm, boundary_expanded_iss[0], NULL, &bnd0->coordinates)); 1142 /* self-check */ 1143 { 1144 IS is0; 1145 PetscCall(DMPlexExpandedVerticesCoordinatesToFaces_Private(idm, bnd0, &is0)); 1146 PetscCall(ISEqual(is0, boundary_is, &flg)); 1147 PetscCheck(flg, PETSC_COMM_SELF, PETSC_ERR_PLIB, "DMPlexExpandedVerticesCoordinatesToFaces_Private produced a wrong IS"); 1148 PetscCall(ISDestroy(&is0)); 1149 } 1150 } else { 1151 PetscCall(VecCreateSeq(PETSC_COMM_SELF, 0, &bnd0->coordinates)); 1152 } 1153 1154 { 1155 Vec tmp; 1156 VecScatter sc; 1157 IS xis; 1158 PetscInt n; 1159 1160 /* just convert seq vectors to mpi vector */ 1161 PetscCall(VecGetLocalSize(bnd0->coordinates, &n)); 1162 PetscCallMPI(MPI_Bcast(&n, 1, MPIU_INT, rootrank, comm)); 1163 if (rank == rootrank) { 1164 PetscCall(VecCreateMPI(comm, n, n, &tmp)); 1165 } else { 1166 PetscCall(VecCreateMPI(comm, 0, n, &tmp)); 1167 } 1168 PetscCall(VecCopy(bnd0->coordinates, tmp)); 1169 PetscCall(VecDestroy(&bnd0->coordinates)); 1170 bnd0->coordinates = tmp; 1171 1172 /* replicate coordinates from root rank to all ranks */ 1173 PetscCall(VecCreateMPI(comm, n, n * size, &bnd->coordinates)); 1174 PetscCall(ISCreateStride(comm, n, 0, 1, &xis)); 1175 PetscCall(VecScatterCreate(bnd0->coordinates, xis, bnd->coordinates, NULL, &sc)); 1176 PetscCall(VecScatterBegin(sc, bnd0->coordinates, bnd->coordinates, INSERT_VALUES, SCATTER_FORWARD)); 1177 PetscCall(VecScatterEnd(sc, bnd0->coordinates, bnd->coordinates, INSERT_VALUES, SCATTER_FORWARD)); 1178 PetscCall(VecScatterDestroy(&sc)); 1179 PetscCall(ISDestroy(&xis)); 1180 } 1181 bnd->depth = bnd0->depth; 1182 PetscCallMPI(MPI_Bcast(&bnd->depth, 1, MPIU_INT, rootrank, comm)); 1183 PetscCall(PetscMalloc1(bnd->depth, &bnd->sections)); 1184 for (d = 0; d < bnd->depth; d++) PetscCall(PetscSectionReplicate_Private(comm, rootrank, (rank == rootrank) ? bnd0->sections[d] : NULL, &bnd->sections[d])); 1185 1186 if (rank == rootrank) PetscCall(DMPlexRestoreConeRecursive(idm, boundary_is, &bnd0->depth, &boundary_expanded_iss, &bnd0->sections)); 1187 PetscCall(PortableBoundaryDestroy(&bnd0)); 1188 PetscCall(DMRemoveLabelBySelf(idm, &label, PETSC_TRUE)); 1189 PetscCall(DMLabelDestroy(&label)); 1190 PetscCall(ISDestroy(&boundary_is)); 1191 PetscCall(DMDestroy(&idm)); 1192 *boundary = bnd; 1193 PetscFunctionReturn(PETSC_SUCCESS); 1194 } 1195 1196 /* get faces of inter-partition interface */ 1197 static PetscErrorCode DMPlexGetInterfaceFaces_Private(DM ipdm, IS boundary_faces_is, IS *interface_faces_is) 1198 { 1199 MPI_Comm comm; 1200 DMLabel label; 1201 IS part_boundary_faces_is; 1202 const char partBoundaryName[] = "DMPlexDistributeInterpolateMarkInterface_partBoundary"; 1203 PetscInt value = 1; 1204 DMPlexInterpolatedFlag intp; 1205 1206 PetscFunctionBegin; 1207 PetscCall(PetscObjectGetComm((PetscObject)ipdm, &comm)); 1208 PetscCall(DMPlexIsInterpolatedCollective(ipdm, &intp)); 1209 PetscCheck(intp == DMPLEX_INTERPOLATED_FULL, comm, PETSC_ERR_ARG_WRONG, "only for fully interpolated DMPlex"); 1210 1211 /* get ipdm partition boundary (partBoundary) */ 1212 { 1213 PetscSF sf; 1214 1215 PetscCall(DMLabelCreate(PETSC_COMM_SELF, partBoundaryName, &label)); 1216 PetscCall(DMAddLabel(ipdm, label)); 1217 PetscCall(DMGetPointSF(ipdm, &sf)); 1218 PetscCall(DMSetPointSF(ipdm, NULL)); 1219 PetscCall(DMPlexMarkBoundaryFaces(ipdm, value, label)); 1220 PetscCall(DMSetPointSF(ipdm, sf)); 1221 PetscCall(DMLabelViewFromOptionsOnComm_Private(label, "-ipdm_part_boundary_view", comm)); 1222 PetscCall(DMLabelGetStratumISOnComm_Private(label, value, comm, &part_boundary_faces_is)); 1223 PetscCall(DMRemoveLabelBySelf(ipdm, &label, PETSC_TRUE)); 1224 PetscCall(DMLabelDestroy(&label)); 1225 } 1226 1227 /* remove ipdm whole-domain boundary (boundary_faces_is) from ipdm partition boundary (part_boundary_faces_is), resulting just in inter-partition interface */ 1228 PetscCall(ISDifference(part_boundary_faces_is, boundary_faces_is, interface_faces_is)); 1229 PetscCall(ISDestroy(&part_boundary_faces_is)); 1230 PetscFunctionReturn(PETSC_SUCCESS); 1231 } 1232 1233 /* compute inter-partition interface including edges and vertices */ 1234 static PetscErrorCode DMPlexComputeCompleteInterface_Private(DM ipdm, IS interface_faces_is, IS *interface_is) 1235 { 1236 DMLabel label; 1237 PetscInt value = 1; 1238 const char interfaceName[] = "DMPlexDistributeInterpolateMarkInterface_interface"; 1239 DMPlexInterpolatedFlag intp; 1240 MPI_Comm comm; 1241 1242 PetscFunctionBegin; 1243 PetscCall(PetscObjectGetComm((PetscObject)ipdm, &comm)); 1244 PetscCall(DMPlexIsInterpolatedCollective(ipdm, &intp)); 1245 PetscCheck(intp == DMPLEX_INTERPOLATED_FULL, comm, PETSC_ERR_ARG_WRONG, "only for fully interpolated DMPlex"); 1246 1247 PetscCall(DMLabelCreate(PETSC_COMM_SELF, interfaceName, &label)); 1248 PetscCall(DMAddLabel(ipdm, label)); 1249 PetscCall(DMLabelSetStratumIS(label, value, interface_faces_is)); 1250 PetscCall(DMLabelViewFromOptionsOnComm_Private(label, "-interface_faces_view", comm)); 1251 PetscCall(DMPlexLabelComplete(ipdm, label)); 1252 PetscCall(DMLabelViewFromOptionsOnComm_Private(label, "-interface_view", comm)); 1253 PetscCall(DMLabelGetStratumISOnComm_Private(label, value, comm, interface_is)); 1254 PetscCall(PetscObjectSetName((PetscObject)*interface_is, "interface_is")); 1255 PetscCall(ISViewFromOptions(*interface_is, NULL, "-interface_is_view")); 1256 PetscCall(DMRemoveLabelBySelf(ipdm, &label, PETSC_TRUE)); 1257 PetscCall(DMLabelDestroy(&label)); 1258 PetscFunctionReturn(PETSC_SUCCESS); 1259 } 1260 1261 static PetscErrorCode PointSFGetOutwardInterfacePoints(PetscSF sf, IS *is) 1262 { 1263 PetscInt n; 1264 const PetscInt *arr; 1265 1266 PetscFunctionBegin; 1267 PetscCall(PetscSFGetGraph(sf, NULL, &n, &arr, NULL)); 1268 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)sf), n, arr, PETSC_USE_POINTER, is)); 1269 PetscFunctionReturn(PETSC_SUCCESS); 1270 } 1271 1272 static PetscErrorCode PointSFGetInwardInterfacePoints(PetscSF sf, IS *is) 1273 { 1274 PetscInt n; 1275 const PetscInt *rootdegree; 1276 PetscInt *arr; 1277 1278 PetscFunctionBegin; 1279 PetscCall(PetscSFSetUp(sf)); 1280 PetscCall(PetscSFComputeDegreeBegin(sf, &rootdegree)); 1281 PetscCall(PetscSFComputeDegreeEnd(sf, &rootdegree)); 1282 PetscCall(PetscSFComputeMultiRootOriginalNumbering(sf, rootdegree, &n, &arr)); 1283 PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)sf), n, arr, PETSC_OWN_POINTER, is)); 1284 PetscFunctionReturn(PETSC_SUCCESS); 1285 } 1286 1287 static PetscErrorCode PointSFGetInterfacePoints_Private(PetscSF pointSF, IS *is) 1288 { 1289 IS pointSF_out_is, pointSF_in_is; 1290 1291 PetscFunctionBegin; 1292 PetscCall(PointSFGetOutwardInterfacePoints(pointSF, &pointSF_out_is)); 1293 PetscCall(PointSFGetInwardInterfacePoints(pointSF, &pointSF_in_is)); 1294 PetscCall(ISExpand(pointSF_out_is, pointSF_in_is, is)); 1295 PetscCall(ISDestroy(&pointSF_out_is)); 1296 PetscCall(ISDestroy(&pointSF_in_is)); 1297 PetscFunctionReturn(PETSC_SUCCESS); 1298 } 1299 1300 #define CHKERRMY(ierr) PetscCheck(!ierr, PETSC_COMM_SELF, PETSC_ERR_PLIB, "PointSF is wrong. Unable to show details!") 1301 1302 static PetscErrorCode ViewPointsWithType_Internal(DM dm, IS pointsIS, PetscViewer v) 1303 { 1304 DMLabel label; 1305 PetscSection coordsSection; 1306 Vec coordsVec; 1307 PetscScalar *coordsScalar; 1308 PetscInt coneSize, depth, dim, i, p, npoints; 1309 const PetscInt *points; 1310 1311 PetscFunctionBegin; 1312 PetscCall(DMGetDimension(dm, &dim)); 1313 PetscCall(DMGetCoordinateSection(dm, &coordsSection)); 1314 PetscCall(DMGetCoordinatesLocal(dm, &coordsVec)); 1315 PetscCall(VecGetArray(coordsVec, &coordsScalar)); 1316 PetscCall(ISGetLocalSize(pointsIS, &npoints)); 1317 PetscCall(ISGetIndices(pointsIS, &points)); 1318 PetscCall(DMPlexGetDepthLabel(dm, &label)); 1319 PetscCall(PetscViewerASCIIPushTab(v)); 1320 for (i = 0; i < npoints; i++) { 1321 p = points[i]; 1322 PetscCall(DMLabelGetValue(label, p, &depth)); 1323 if (!depth) { 1324 PetscInt n, o; 1325 char coordstr[128]; 1326 1327 PetscCall(PetscSectionGetDof(coordsSection, p, &n)); 1328 PetscCall(PetscSectionGetOffset(coordsSection, p, &o)); 1329 PetscCall(coord2str(coordstr, sizeof(coordstr), n, &coordsScalar[o], 1.0)); 1330 PetscCall(PetscViewerASCIISynchronizedPrintf(v, "vertex %" PetscInt_FMT " w/ coordinates %s\n", p, coordstr)); 1331 } else { 1332 char entityType[16]; 1333 1334 switch (depth) { 1335 case 1: 1336 PetscCall(PetscStrncpy(entityType, "edge", sizeof(entityType))); 1337 break; 1338 case 2: 1339 PetscCall(PetscStrncpy(entityType, "face", sizeof(entityType))); 1340 break; 1341 case 3: 1342 PetscCall(PetscStrncpy(entityType, "cell", sizeof(entityType))); 1343 break; 1344 default: 1345 SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Only for depth <= 3"); 1346 } 1347 if (depth == dim && dim < 3) PetscCall(PetscStrlcat(entityType, " (cell)", sizeof(entityType))); 1348 PetscCall(PetscViewerASCIISynchronizedPrintf(v, "%s %" PetscInt_FMT "\n", entityType, p)); 1349 } 1350 PetscCall(DMPlexGetConeSize(dm, p, &coneSize)); 1351 if (coneSize) { 1352 const PetscInt *cone; 1353 IS coneIS; 1354 1355 PetscCall(DMPlexGetCone(dm, p, &cone)); 1356 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, coneSize, cone, PETSC_USE_POINTER, &coneIS)); 1357 PetscCall(ViewPointsWithType_Internal(dm, coneIS, v)); 1358 PetscCall(ISDestroy(&coneIS)); 1359 } 1360 } 1361 PetscCall(PetscViewerASCIIPopTab(v)); 1362 PetscCall(VecRestoreArray(coordsVec, &coordsScalar)); 1363 PetscCall(ISRestoreIndices(pointsIS, &points)); 1364 PetscFunctionReturn(PETSC_SUCCESS); 1365 } 1366 1367 static PetscErrorCode ViewPointsWithType(DM dm, IS points, PetscViewer v) 1368 { 1369 PetscBool flg; 1370 PetscInt npoints; 1371 PetscMPIInt rank; 1372 1373 PetscFunctionBegin; 1374 PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERASCII, &flg)); 1375 PetscCheck(flg, PetscObjectComm((PetscObject)v), PETSC_ERR_SUP, "Only for ASCII viewer"); 1376 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)v), &rank)); 1377 PetscCall(PetscViewerASCIIPushSynchronized(v)); 1378 PetscCall(ISGetLocalSize(points, &npoints)); 1379 if (npoints) { 1380 PetscCall(PetscViewerASCIISynchronizedPrintf(v, "[%d] --------\n", rank)); 1381 PetscCall(ViewPointsWithType_Internal(dm, points, v)); 1382 } 1383 PetscCall(PetscViewerFlush(v)); 1384 PetscCall(PetscViewerASCIIPopSynchronized(v)); 1385 PetscFunctionReturn(PETSC_SUCCESS); 1386 } 1387 1388 static PetscErrorCode DMPlexComparePointSFWithInterface_Private(DM ipdm, IS interface_is) 1389 { 1390 PetscSF pointsf; 1391 IS pointsf_is; 1392 PetscBool flg; 1393 MPI_Comm comm; 1394 PetscMPIInt size; 1395 1396 PetscFunctionBegin; 1397 PetscCall(PetscObjectGetComm((PetscObject)ipdm, &comm)); 1398 PetscCallMPI(MPI_Comm_size(comm, &size)); 1399 PetscCall(DMGetPointSF(ipdm, &pointsf)); 1400 if (pointsf) { 1401 PetscInt nroots; 1402 PetscCall(PetscSFGetGraph(pointsf, &nroots, NULL, NULL, NULL)); 1403 if (nroots < 0) pointsf = NULL; /* uninitialized SF */ 1404 } 1405 if (!pointsf) { 1406 PetscInt N = 0; 1407 if (interface_is) PetscCall(ISGetSize(interface_is, &N)); 1408 PetscCheck(!N, comm, PETSC_ERR_PLIB, "interface_is should be NULL or empty for PointSF being NULL"); 1409 PetscFunctionReturn(PETSC_SUCCESS); 1410 } 1411 1412 /* get PointSF points as IS pointsf_is */ 1413 PetscCall(PointSFGetInterfacePoints_Private(pointsf, &pointsf_is)); 1414 1415 /* compare pointsf_is with interface_is */ 1416 PetscCall(ISEqual(interface_is, pointsf_is, &flg)); 1417 PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, &flg, 1, MPIU_BOOL, MPI_LAND, comm)); 1418 if (!flg) { 1419 IS pointsf_extra_is, pointsf_missing_is; 1420 PetscViewer errv = PETSC_VIEWER_STDERR_(comm); 1421 CHKERRMY(ISDifference(interface_is, pointsf_is, &pointsf_missing_is)); 1422 CHKERRMY(ISDifference(pointsf_is, interface_is, &pointsf_extra_is)); 1423 CHKERRMY(PetscViewerASCIIPrintf(errv, "Points missing in PointSF:\n")); 1424 CHKERRMY(ViewPointsWithType(ipdm, pointsf_missing_is, errv)); 1425 CHKERRMY(PetscViewerASCIIPrintf(errv, "Extra points in PointSF:\n")); 1426 CHKERRMY(ViewPointsWithType(ipdm, pointsf_extra_is, errv)); 1427 CHKERRMY(ISDestroy(&pointsf_extra_is)); 1428 CHKERRMY(ISDestroy(&pointsf_missing_is)); 1429 SETERRQ(comm, PETSC_ERR_PLIB, "PointSF is wrong! See details above."); 1430 } 1431 PetscCall(ISDestroy(&pointsf_is)); 1432 PetscFunctionReturn(PETSC_SUCCESS); 1433 } 1434 1435 /* remove faces & edges from label, leave just vertices */ 1436 static PetscErrorCode DMPlexISFilterVertices_Private(DM dm, IS points) 1437 { 1438 PetscInt vStart, vEnd; 1439 MPI_Comm comm; 1440 1441 PetscFunctionBegin; 1442 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1443 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1444 PetscCall(ISGeneralFilter(points, vStart, vEnd)); 1445 PetscFunctionReturn(PETSC_SUCCESS); 1446 } 1447 1448 /* 1449 DMPlexCheckPointSFHeavy - Thoroughly test that the PointSF after parallel DMPlexInterpolate() includes exactly all interface points. 1450 1451 Collective 1452 1453 Input Parameters: 1454 . dm - The DMPlex object 1455 1456 Notes: 1457 The input DMPlex must be serial (one partition has all points, the other partitions have no points). 1458 This is a heavy test which involves DMPlexInterpolate() if the input DM is not interpolated yet, and depends on having a representation of the whole-domain boundary (PortableBoundary), which can be obtained only by DMPlexGetExpandedBoundary_Private() (which involves DMPlexInterpolate() of a sequential DM). 1459 This is mainly intended for debugging/testing purposes. 1460 1461 Algorithm: 1462 1. boundary faces of the serial version of the whole mesh are found using DMPlexMarkBoundaryFaces() 1463 2. boundary faces are translated into vertices using DMPlexGetConeRecursive() and these are translated into coordinates - this description (aka PortableBoundary) is completely independent of partitioning and point numbering 1464 3. the mesh is distributed or loaded in parallel 1465 4. boundary faces of the distributed mesh are reconstructed from PortableBoundary using DMPlexFindVertices() 1466 5. partition boundary faces of the parallel mesh are found using DMPlexMarkBoundaryFaces() 1467 6. partition interfaces are computed as set difference of partition boundary faces minus the reconstructed boundary 1468 7. check that interface covered by PointSF (union of inward and outward points) is equal to the partition interface for each rank, otherwise print the difference and throw an error 1469 1470 Level: developer 1471 1472 .seealso: DMGetPointSF(), DMPlexCheckSymmetry(), DMPlexCheckSkeleton(), DMPlexCheckFaces() 1473 */ 1474 static PetscErrorCode DMPlexCheckPointSFHeavy(DM dm, PortableBoundary bnd) 1475 { 1476 DM ipdm = NULL; 1477 IS boundary_faces_is, interface_faces_is, interface_is; 1478 DMPlexInterpolatedFlag intp; 1479 MPI_Comm comm; 1480 1481 PetscFunctionBegin; 1482 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1483 1484 PetscCall(DMPlexIsInterpolatedCollective(dm, &intp)); 1485 if (intp == DMPLEX_INTERPOLATED_FULL) { 1486 ipdm = dm; 1487 } else { 1488 /* create temporary interpolated DM if input DM is not interpolated */ 1489 PetscCall(DMPlexSetOrientInterface_Private(dm, PETSC_FALSE)); 1490 PetscCall(DMPlexInterpolate(dm, &ipdm)); /* with DMPlexOrientInterface_Internal() call skipped so that PointSF issues are left to DMPlexComparePointSFWithInterface_Private() below */ 1491 PetscCall(DMPlexSetOrientInterface_Private(dm, PETSC_TRUE)); 1492 } 1493 PetscCall(DMViewFromOptions(ipdm, NULL, "-ipdm_view")); 1494 1495 /* recover ipdm whole-domain boundary faces from the expanded vertices coordinates */ 1496 PetscCall(DMPlexExpandedVerticesCoordinatesToFaces_Private(ipdm, bnd, &boundary_faces_is)); 1497 /* get inter-partition interface faces (interface_faces_is)*/ 1498 PetscCall(DMPlexGetInterfaceFaces_Private(ipdm, boundary_faces_is, &interface_faces_is)); 1499 /* compute inter-partition interface including edges and vertices (interface_is) */ 1500 PetscCall(DMPlexComputeCompleteInterface_Private(ipdm, interface_faces_is, &interface_is)); 1501 /* destroy immediate ISs */ 1502 PetscCall(ISDestroy(&boundary_faces_is)); 1503 PetscCall(ISDestroy(&interface_faces_is)); 1504 1505 /* for uninterpolated case, keep just vertices in interface */ 1506 if (!intp) { 1507 PetscCall(DMPlexISFilterVertices_Private(ipdm, interface_is)); 1508 PetscCall(DMDestroy(&ipdm)); 1509 } 1510 1511 /* compare PointSF with the boundary reconstructed from coordinates */ 1512 PetscCall(DMPlexComparePointSFWithInterface_Private(dm, interface_is)); 1513 PetscCall(PetscPrintf(comm, "DMPlexCheckPointSFHeavy PASSED\n")); 1514 PetscCall(ISDestroy(&interface_is)); 1515 PetscFunctionReturn(PETSC_SUCCESS); 1516 } 1517 1518 int main(int argc, char **argv) 1519 { 1520 DM dm; 1521 AppCtx user; 1522 1523 PetscFunctionBeginUser; 1524 PetscCall(PetscInitialize(&argc, &argv, NULL, help)); 1525 PetscCall(PetscLogStageRegister("create", &stage[0])); 1526 PetscCall(PetscLogStageRegister("distribute", &stage[1])); 1527 PetscCall(PetscLogStageRegister("interpolate", &stage[2])); 1528 PetscCall(ProcessOptions(PETSC_COMM_WORLD, &user)); 1529 PetscCall(CreateMesh(PETSC_COMM_WORLD, &user, &dm)); 1530 if (user.nPointsToExpand) PetscCall(TestExpandPoints(dm, &user)); 1531 if (user.ncoords) { 1532 Vec coords; 1533 1534 PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF, user.ncoords, user.ncoords, user.coords, &coords)); 1535 PetscCall(ViewVerticesFromCoords(dm, coords, user.coordsTol, PETSC_VIEWER_STDOUT_WORLD)); 1536 PetscCall(VecDestroy(&coords)); 1537 } 1538 PetscCall(DMDestroy(&dm)); 1539 PetscCall(PetscFinalize()); 1540 return 0; 1541 } 1542 1543 /*TEST 1544 1545 testset: 1546 nsize: 2 1547 args: -dm_view ascii::ascii_info_detail 1548 args: -dm_plex_check_all 1549 test: 1550 suffix: 1_tri_dist0 1551 args: -distribute 0 -interpolate {{none create}separate output} 1552 test: 1553 suffix: 1_tri_dist1 1554 args: -distribute 1 -interpolate {{none create after_distribute}separate output} 1555 test: 1556 suffix: 1_quad_dist0 1557 args: -cell_simplex 0 -distribute 0 -interpolate {{none create}separate output} 1558 test: 1559 suffix: 1_quad_dist1 1560 args: -cell_simplex 0 -distribute 1 -interpolate {{none create after_distribute}separate output} 1561 test: 1562 suffix: 1_1d_dist1 1563 args: -dim 1 -distribute 1 1564 1565 testset: 1566 nsize: 3 1567 args: -testnum 1 -interpolate create 1568 args: -dm_plex_check_all 1569 test: 1570 suffix: 2 1571 args: -dm_view ascii::ascii_info_detail 1572 test: 1573 suffix: 2a 1574 args: -dm_plex_check_cones_conform_on_interfaces_verbose 1575 test: 1576 suffix: 2b 1577 args: -test_expand_points 0,1,2,5,6 1578 test: 1579 suffix: 2c 1580 args: -test_expand_points 0,1,2,5,6 -test_expand_points_empty 1581 1582 testset: 1583 # the same as 1% for 3D 1584 nsize: 2 1585 args: -dim 3 -dm_view ascii::ascii_info_detail 1586 args: -dm_plex_check_all 1587 test: 1588 suffix: 4_tet_dist0 1589 args: -distribute 0 -interpolate {{none create}separate output} 1590 test: 1591 suffix: 4_tet_dist1 1592 args: -distribute 1 -interpolate {{none create after_distribute}separate output} 1593 test: 1594 suffix: 4_hex_dist0 1595 args: -cell_simplex 0 -distribute 0 -interpolate {{none create}separate output} 1596 test: 1597 suffix: 4_hex_dist1 1598 args: -cell_simplex 0 -distribute 1 -interpolate {{none create after_distribute}separate output} 1599 1600 test: 1601 # the same as 4_tet_dist0 but test different initial orientations 1602 suffix: 4_tet_test_orient 1603 nsize: 2 1604 args: -dim 3 -distribute 0 1605 args: -dm_plex_check_all 1606 args: -rotate_interface_0 {{0 1 2 11 12 13}} 1607 args: -rotate_interface_1 {{0 1 2 11 12 13}} 1608 1609 testset: 1610 requires: exodusii 1611 args: -filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/TwoQuads.exo 1612 args: -dm_view ascii::ascii_info_detail 1613 args: -dm_plex_check_all 1614 args: -custom_view 1615 test: 1616 suffix: 5_seq 1617 nsize: 1 1618 args: -distribute 0 -interpolate {{none create}separate output} 1619 test: 1620 # Detail viewing in a non-distributed mesh is broken because the DMLabelView() is collective, but the label is not shared 1621 suffix: 5_dist0 1622 nsize: 2 1623 args: -distribute 0 -interpolate {{none create}separate output} -dm_view 1624 test: 1625 suffix: 5_dist1 1626 nsize: 2 1627 args: -distribute 1 -interpolate {{none create after_distribute}separate output} 1628 1629 testset: 1630 nsize: {{1 2 4}} 1631 args: -use_generator 1632 args: -dm_plex_check_all 1633 args: -distribute -interpolate none 1634 test: 1635 suffix: 6_tri 1636 requires: triangle 1637 args: -faces {{2,2 1,3 7,4}} -cell_simplex 1 -dm_generator triangle 1638 test: 1639 suffix: 6_quad 1640 args: -faces {{2,2 1,3 7,4}} -cell_simplex 0 1641 test: 1642 suffix: 6_tet 1643 requires: ctetgen 1644 args: -faces {{2,2,2 1,3,5 3,4,7}} -cell_simplex 1 -dm_generator ctetgen 1645 test: 1646 suffix: 6_hex 1647 args: -faces {{2,2,2 1,3,5 3,4,7}} -cell_simplex 0 1648 testset: 1649 nsize: {{1 2 4}} 1650 args: -use_generator 1651 args: -dm_plex_check_all 1652 args: -distribute -interpolate create 1653 test: 1654 suffix: 6_int_tri 1655 requires: triangle 1656 args: -faces {{2,2 1,3 7,4}} -cell_simplex 1 -dm_generator triangle 1657 test: 1658 suffix: 6_int_quad 1659 args: -faces {{2,2 1,3 7,4}} -cell_simplex 0 1660 test: 1661 suffix: 6_int_tet 1662 requires: ctetgen 1663 args: -faces {{2,2,2 1,3,5 3,4,7}} -cell_simplex 1 -dm_generator ctetgen 1664 test: 1665 suffix: 6_int_hex 1666 args: -faces {{2,2,2 1,3,5 3,4,7}} -cell_simplex 0 1667 testset: 1668 nsize: {{2 4}} 1669 args: -use_generator 1670 args: -dm_plex_check_all 1671 args: -distribute -interpolate after_distribute 1672 test: 1673 suffix: 6_parint_tri 1674 requires: triangle 1675 args: -faces {{2,2 1,3 7,4}} -cell_simplex 1 -dm_generator triangle 1676 test: 1677 suffix: 6_parint_quad 1678 args: -faces {{2,2 1,3 7,4}} -cell_simplex 0 1679 test: 1680 suffix: 6_parint_tet 1681 requires: ctetgen 1682 args: -faces {{2,2,2 1,3,5 3,4,7}} -cell_simplex 1 -dm_generator ctetgen 1683 test: 1684 suffix: 6_parint_hex 1685 args: -faces {{2,2,2 1,3,5 3,4,7}} -cell_simplex 0 1686 1687 testset: # 7 EXODUS 1688 requires: exodusii 1689 args: -dm_plex_check_all 1690 args: -filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/blockcylinder-50.exo 1691 args: -distribute 1692 test: # seq load, simple partitioner 1693 suffix: 7_exo 1694 nsize: {{1 2 4 5}} 1695 args: -interpolate none 1696 test: # seq load, seq interpolation, simple partitioner 1697 suffix: 7_exo_int_simple 1698 nsize: {{1 2 4 5}} 1699 args: -interpolate create 1700 test: # seq load, seq interpolation, metis partitioner 1701 suffix: 7_exo_int_metis 1702 requires: parmetis 1703 nsize: {{2 4 5}} 1704 args: -interpolate create 1705 args: -petscpartitioner_type parmetis 1706 test: # seq load, simple partitioner, par interpolation 1707 suffix: 7_exo_simple_int 1708 nsize: {{2 4 5}} 1709 args: -interpolate after_distribute 1710 test: # seq load, metis partitioner, par interpolation 1711 suffix: 7_exo_metis_int 1712 requires: parmetis 1713 nsize: {{2 4 5}} 1714 args: -interpolate after_distribute 1715 args: -petscpartitioner_type parmetis 1716 1717 testset: # 7 HDF5 SEQUANTIAL LOAD 1718 requires: hdf5 !complex 1719 args: -dm_plex_check_all 1720 args: -filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/blockcylinder-50.h5 -dm_plex_create_from_hdf5_xdmf 1721 args: -dm_plex_hdf5_force_sequential 1722 args: -distribute 1723 test: # seq load, simple partitioner 1724 suffix: 7_seq_hdf5_simple 1725 nsize: {{1 2 4 5}} 1726 args: -interpolate none 1727 test: # seq load, seq interpolation, simple partitioner 1728 suffix: 7_seq_hdf5_int_simple 1729 nsize: {{1 2 4 5}} 1730 args: -interpolate after_create 1731 test: # seq load, seq interpolation, metis partitioner 1732 nsize: {{2 4 5}} 1733 suffix: 7_seq_hdf5_int_metis 1734 requires: parmetis 1735 args: -interpolate after_create 1736 args: -petscpartitioner_type parmetis 1737 test: # seq load, simple partitioner, par interpolation 1738 suffix: 7_seq_hdf5_simple_int 1739 nsize: {{2 4 5}} 1740 args: -interpolate after_distribute 1741 test: # seq load, metis partitioner, par interpolation 1742 nsize: {{2 4 5}} 1743 suffix: 7_seq_hdf5_metis_int 1744 requires: parmetis 1745 args: -interpolate after_distribute 1746 args: -petscpartitioner_type parmetis 1747 1748 testset: # 7 HDF5 PARALLEL LOAD 1749 requires: hdf5 !complex 1750 nsize: {{2 4 5}} 1751 args: -dm_plex_check_all 1752 args: -filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/blockcylinder-50.h5 -dm_plex_create_from_hdf5_xdmf 1753 test: # par load 1754 suffix: 7_par_hdf5 1755 args: -interpolate none 1756 test: # par load, par interpolation 1757 suffix: 7_par_hdf5_int 1758 args: -interpolate after_create 1759 test: # par load, parmetis repartitioner 1760 TODO: Parallel partitioning of uninterpolated meshes not supported 1761 suffix: 7_par_hdf5_parmetis 1762 requires: parmetis 1763 args: -distribute -petscpartitioner_type parmetis 1764 args: -interpolate none 1765 test: # par load, par interpolation, parmetis repartitioner 1766 suffix: 7_par_hdf5_int_parmetis 1767 requires: parmetis 1768 args: -distribute -petscpartitioner_type parmetis 1769 args: -interpolate after_create 1770 test: # par load, parmetis partitioner, par interpolation 1771 TODO: Parallel partitioning of uninterpolated meshes not supported 1772 suffix: 7_par_hdf5_parmetis_int 1773 requires: parmetis 1774 args: -distribute -petscpartitioner_type parmetis 1775 args: -interpolate after_distribute 1776 1777 test: 1778 suffix: 7_hdf5_hierarch 1779 requires: hdf5 ptscotch !complex 1780 nsize: {{2 3 4}separate output} 1781 args: -distribute 1782 args: -interpolate after_create 1783 args: -petscpartitioner_type matpartitioning -petscpartitioner_view ::ascii_info 1784 args: -mat_partitioning_type hierarch -mat_partitioning_hierarchical_nfineparts 2 1785 args: -mat_partitioning_hierarchical_coarseparttype ptscotch -mat_partitioning_hierarchical_fineparttype ptscotch 1786 1787 test: 1788 suffix: 8 1789 requires: hdf5 !complex 1790 nsize: 4 1791 args: -filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/blockcylinder-50.h5 -dm_plex_create_from_hdf5_xdmf 1792 args: -distribute 0 -interpolate after_create 1793 args: -view_vertices_from_coords 0.,1.,0.,-0.5,1.,0.,0.583,-0.644,0.,-2.,-2.,-2. -view_vertices_from_coords_tol 1e-3 1794 args: -dm_plex_check_all 1795 args: -custom_view 1796 1797 testset: # 9 HDF5 SEQUANTIAL LOAD 1798 requires: hdf5 !complex datafilespath 1799 args: -dm_plex_check_all 1800 args: -filename ${DATAFILESPATH}/meshes/cube-hexahedra-refined.h5 -dm_plex_create_from_hdf5_xdmf -dm_plex_hdf5_topology_path /cells -dm_plex_hdf5_geometry_path /coordinates 1801 args: -dm_plex_hdf5_force_sequential 1802 args: -distribute 1803 test: # seq load, simple partitioner 1804 suffix: 9_seq_hdf5_simple 1805 nsize: {{1 2 4 5}} 1806 args: -interpolate none 1807 test: # seq load, seq interpolation, simple partitioner 1808 suffix: 9_seq_hdf5_int_simple 1809 nsize: {{1 2 4 5}} 1810 args: -interpolate after_create 1811 test: # seq load, seq interpolation, metis partitioner 1812 nsize: {{2 4 5}} 1813 suffix: 9_seq_hdf5_int_metis 1814 requires: parmetis 1815 args: -interpolate after_create 1816 args: -petscpartitioner_type parmetis 1817 test: # seq load, simple partitioner, par interpolation 1818 suffix: 9_seq_hdf5_simple_int 1819 nsize: {{2 4 5}} 1820 args: -interpolate after_distribute 1821 test: # seq load, simple partitioner, par interpolation 1822 # This is like 9_seq_hdf5_simple_int but testing error output of DMPlexCheckPointSFHeavy(). 1823 # Once 9_seq_hdf5_simple_int gets fixed, this one gets broken. 1824 # We can then provide an intentionally broken mesh instead. 1825 TODO: This test is broken because PointSF is fixed. 1826 suffix: 9_seq_hdf5_simple_int_err 1827 nsize: 4 1828 args: -interpolate after_distribute 1829 filter: sed -e "/PETSC ERROR/,$$d" 1830 test: # seq load, metis partitioner, par interpolation 1831 nsize: {{2 4 5}} 1832 suffix: 9_seq_hdf5_metis_int 1833 requires: parmetis 1834 args: -interpolate after_distribute 1835 args: -petscpartitioner_type parmetis 1836 1837 testset: # 9 HDF5 PARALLEL LOAD 1838 requires: hdf5 !complex datafilespath 1839 nsize: {{2 4 5}} 1840 args: -dm_plex_check_all 1841 args: -filename ${DATAFILESPATH}/meshes/cube-hexahedra-refined.h5 -dm_plex_create_from_hdf5_xdmf -dm_plex_hdf5_topology_path /cells -dm_plex_hdf5_geometry_path /coordinates 1842 test: # par load 1843 suffix: 9_par_hdf5 1844 args: -interpolate none 1845 test: # par load, par interpolation 1846 suffix: 9_par_hdf5_int 1847 args: -interpolate after_create 1848 test: # par load, parmetis repartitioner 1849 TODO: Parallel partitioning of uninterpolated meshes not supported 1850 suffix: 9_par_hdf5_parmetis 1851 requires: parmetis 1852 args: -distribute -petscpartitioner_type parmetis 1853 args: -interpolate none 1854 test: # par load, par interpolation, parmetis repartitioner 1855 suffix: 9_par_hdf5_int_parmetis 1856 requires: parmetis 1857 args: -distribute -petscpartitioner_type parmetis 1858 args: -interpolate after_create 1859 test: # par load, parmetis partitioner, par interpolation 1860 TODO: Parallel partitioning of uninterpolated meshes not supported 1861 suffix: 9_par_hdf5_parmetis_int 1862 requires: parmetis 1863 args: -distribute -petscpartitioner_type parmetis 1864 args: -interpolate after_distribute 1865 1866 testset: # 10 HDF5 PARALLEL LOAD 1867 requires: hdf5 !complex datafilespath 1868 nsize: {{2 4 7}} 1869 args: -dm_plex_check_all 1870 args: -filename ${DATAFILESPATH}/meshes/cube-hexahedra-refined2.h5 -dm_plex_create_from_hdf5_xdmf -dm_plex_hdf5_topology_path /topo -dm_plex_hdf5_geometry_path /geom 1871 test: # par load, par interpolation 1872 suffix: 10_par_hdf5_int 1873 args: -interpolate after_create 1874 TEST*/ 1875