1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/dmlabelimpl.h> /*I "petscdmlabel.h" I*/ 3 #include <petscsf.h> 4 5 static PetscErrorCode DMPlexCellIsHybrid_Internal(DM dm, PetscInt p, PetscBool *isHybrid) 6 { 7 DMPolytopeType ct; 8 9 PetscFunctionBegin; 10 PetscCall(DMPlexGetCellType(dm, p, &ct)); 11 switch (ct) { 12 case DM_POLYTOPE_POINT_PRISM_TENSOR: 13 case DM_POLYTOPE_SEG_PRISM_TENSOR: 14 case DM_POLYTOPE_TRI_PRISM_TENSOR: 15 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 16 *isHybrid = PETSC_TRUE; 17 break; 18 default: 19 *isHybrid = PETSC_FALSE; 20 break; 21 } 22 PetscFunctionReturn(PETSC_SUCCESS); 23 } 24 25 static PetscErrorCode DMPlexGetTensorPrismBounds_Internal(DM dm, PetscInt dim, PetscInt *cStart, PetscInt *cEnd) 26 { 27 DMLabel ctLabel; 28 29 PetscFunctionBegin; 30 if (cStart) *cStart = -1; 31 if (cEnd) *cEnd = -1; 32 PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel)); 33 switch (dim) { 34 case 1: 35 PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_POINT_PRISM_TENSOR, cStart, cEnd)); 36 break; 37 case 2: 38 PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_SEG_PRISM_TENSOR, cStart, cEnd)); 39 break; 40 case 3: 41 PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_TRI_PRISM_TENSOR, cStart, cEnd)); 42 if (*cStart < 0) PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_QUAD_PRISM_TENSOR, cStart, cEnd)); 43 break; 44 default: 45 PetscFunctionReturn(PETSC_SUCCESS); 46 } 47 PetscFunctionReturn(PETSC_SUCCESS); 48 } 49 50 PetscErrorCode DMPlexMarkBoundaryFaces_Internal(DM dm, PetscInt val, PetscInt cellHeight, DMLabel label, PetscBool missing_only) 51 { 52 PetscInt depth, pStart, pEnd, fStart, fEnd, f, supportSize, nroots = -1, nleaves = -1, defval; 53 PetscSF sf; 54 const PetscSFNode *iremote = NULL; 55 const PetscInt *ilocal = NULL; 56 PetscInt *leafData; 57 58 PetscFunctionBegin; 59 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 60 PetscCall(DMPlexGetDepth(dm, &depth)); 61 if (depth >= cellHeight + 1) { 62 PetscCall(DMPlexGetHeightStratum(dm, cellHeight + 1, &fStart, &fEnd)); 63 } else { 64 /* Note DMPlexGetHeightStratum() returns fStart, fEnd = pStart, pEnd */ 65 /* if height > depth, which is not what we want here. */ 66 fStart = 0; 67 fEnd = 0; 68 } 69 PetscCall(DMLabelGetDefaultValue(label, &defval)); 70 PetscCall(PetscCalloc1(pEnd - pStart, &leafData)); 71 leafData = PetscSafePointerPlusOffset(leafData, -pStart); 72 PetscCall(DMGetPointSF(dm, &sf)); 73 if (sf) PetscCall(PetscSFGetGraph(sf, &nroots, &nleaves, &ilocal, &iremote)); 74 if (sf && nroots >= 0) { 75 PetscInt cStart, cEnd, c, i; 76 PetscInt *rootData, *rootData1, *cellOwners, hasTwoSupportCells = -2; 77 const PetscInt *support; 78 PetscMPIInt rank; 79 80 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 81 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 82 PetscCall(PetscCalloc3(pEnd - pStart, &rootData, pEnd - pStart, &rootData1, cEnd - cStart, &cellOwners)); 83 rootData -= pStart; 84 rootData1 -= pStart; 85 for (c = cStart; c < cEnd; ++c) cellOwners[c - cStart] = rank; 86 for (i = 0; i < nleaves; ++i) { 87 c = ilocal ? ilocal[i] : i; 88 if (c >= cStart && c < cEnd) cellOwners[c - cStart] = iremote[i].rank; 89 } 90 for (f = fStart; f < fEnd; ++f) { 91 PetscCall(DMPlexGetSupportSize(dm, f, &supportSize)); 92 if (supportSize == 1) { 93 PetscCall(DMPlexGetSupport(dm, f, &support)); 94 leafData[f] = cellOwners[support[0] - cStart]; 95 } else { 96 /* TODO: When using DMForest, we could have a parent facet (a coarse facet) */ 97 /* supportSize of which alone does not tell us if it is an interior */ 98 /* facet or an exterior facet. Those facets can be identified by checking */ 99 /* if they are in the parent tree. We should probably skip those parent */ 100 /* facets here, which will allow for including the following check, and */ 101 /* see if they are exterior facets or not afterwards by checking if the */ 102 /* children are exterior or not. */ 103 /* PetscCheck(supportSize == 2, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid facet support size (%" PetscInt_FMT ") on facet (%" PetscInt_FMT ")", supportSize, f); */ 104 leafData[f] = hasTwoSupportCells; /* some negative PetscInt */ 105 } 106 rootData[f] = leafData[f]; 107 rootData1[f] = leafData[f]; 108 } 109 PetscCall(PetscSFReduceBegin(sf, MPIU_INT, leafData, rootData, MPI_MIN)); 110 PetscCall(PetscSFReduceBegin(sf, MPIU_INT, leafData, rootData1, MPI_MAX)); 111 PetscCall(PetscSFReduceEnd(sf, MPIU_INT, leafData, rootData, MPI_MIN)); 112 PetscCall(PetscSFReduceEnd(sf, MPIU_INT, leafData, rootData1, MPI_MAX)); 113 for (f = fStart; f < fEnd; ++f) { 114 /* Store global support size of f. */ 115 /* Facet f is an interior facet if and only if one of the following two is satisfied: */ 116 /* 1. supportSize is 2 on some rank. */ 117 /* 2. supportSize is 1 on any rank that can see f, but f is on a partition boundary; */ 118 /* i.e., rootData[f] < rootData1[f]. */ 119 rootData[f] = (rootData[f] == hasTwoSupportCells || (rootData[f] < rootData1[f])) ? 2 : 1; 120 leafData[f] = rootData[f]; 121 } 122 PetscCall(PetscSFBcastBegin(sf, MPIU_INT, rootData, leafData, MPI_REPLACE)); 123 PetscCall(PetscSFBcastEnd(sf, MPIU_INT, rootData, leafData, MPI_REPLACE)); 124 rootData += pStart; 125 rootData1 += pStart; 126 PetscCall(PetscFree3(rootData, rootData1, cellOwners)); 127 } else { 128 for (f = fStart; f < fEnd; ++f) { 129 PetscCall(DMPlexGetSupportSize(dm, f, &supportSize)); 130 leafData[f] = supportSize; 131 } 132 } 133 for (f = fStart; f < fEnd; ++f) { 134 if (leafData[f] == 1) { 135 if (val < 0) { 136 PetscInt *closure = NULL; 137 PetscInt clSize, cl, cval; 138 139 PetscAssert(!missing_only, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not implemented"); 140 PetscCall(DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &clSize, &closure)); 141 for (cl = 0; cl < clSize * 2; cl += 2) { 142 PetscCall(DMLabelGetValue(label, closure[cl], &cval)); 143 if (cval < 0) continue; 144 PetscCall(DMLabelSetValue(label, f, cval)); 145 break; 146 } 147 if (cl == clSize * 2) PetscCall(DMLabelSetValue(label, f, 1)); 148 PetscCall(DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &clSize, &closure)); 149 } else { 150 if (missing_only) { 151 PetscInt fval; 152 PetscCall(DMLabelGetValue(label, f, &fval)); 153 if (fval != defval) PetscCall(DMLabelClearValue(label, f, fval)); 154 else PetscCall(DMLabelSetValue(label, f, val)); 155 } else { 156 PetscCall(DMLabelSetValue(label, f, val)); 157 } 158 } 159 } else { 160 /* TODO: See the above comment on DMForest */ 161 /* PetscCheck(leafData[f] == 2, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid facet support size (%" PetscInt_FMT ") on facet (%" PetscInt_FMT ")", leafData[f], f); */ 162 } 163 } 164 leafData = PetscSafePointerPlusOffset(leafData, pStart); 165 PetscCall(PetscFree(leafData)); 166 PetscFunctionReturn(PETSC_SUCCESS); 167 } 168 169 /*@ 170 DMPlexMarkBoundaryFaces - Mark all faces on the boundary 171 172 Collective 173 174 Input Parameters: 175 + dm - The original `DM` 176 - val - The marker value, or `PETSC_DETERMINE` to use some value in the closure (or 1 if none are found) 177 178 Output Parameter: 179 . label - The `DMLabel` marking boundary faces with the given value 180 181 Level: developer 182 183 Note: 184 This function will use the point `PetscSF` from the input `DM` and the ownership of the support cells to exclude points on the partition boundary from being marked. If you also wish to mark the partition boundary, you can use `DMSetPointSF()` to temporarily set it to `NULL`, and then reset it to the original object after the call. 185 186 In DMForest there can be facets support sizes of which alone can not determine whether they are on the boundary. Currently, this function is not guaranteed to produce the correct result in such case. 187 188 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMLabelCreate()`, `DMCreateLabel()` 189 @*/ 190 PetscErrorCode DMPlexMarkBoundaryFaces(DM dm, PetscInt val, DMLabel label) 191 { 192 DM plex; 193 DMPlexInterpolatedFlag flg; 194 195 PetscFunctionBegin; 196 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 197 PetscCall(DMConvert(dm, DMPLEX, &plex)); 198 PetscCall(DMPlexIsInterpolated(plex, &flg)); 199 PetscCheck(flg == DMPLEX_INTERPOLATED_FULL, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "DM is not fully interpolated on this rank"); 200 PetscCall(DMPlexMarkBoundaryFaces_Internal(plex, val, 0, label, PETSC_FALSE)); 201 PetscCall(DMDestroy(&plex)); 202 PetscFunctionReturn(PETSC_SUCCESS); 203 } 204 205 static PetscErrorCode DMPlexLabelComplete_Internal(DM dm, DMLabel label, PetscBool completeCells) 206 { 207 IS valueIS; 208 PetscSF sfPoint; 209 const PetscInt *values; 210 PetscInt numValues, v, cStart, cEnd, nroots; 211 212 PetscFunctionBegin; 213 PetscCall(DMLabelGetNumValues(label, &numValues)); 214 PetscCall(DMLabelGetValueIS(label, &valueIS)); 215 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 216 PetscCall(ISGetIndices(valueIS, &values)); 217 for (v = 0; v < numValues; ++v) { 218 IS pointIS; 219 const PetscInt *points; 220 PetscInt numPoints, p; 221 222 PetscCall(DMLabelGetStratumSize(label, values[v], &numPoints)); 223 PetscCall(DMLabelGetStratumIS(label, values[v], &pointIS)); 224 PetscCall(ISGetIndices(pointIS, &points)); 225 for (p = 0; p < numPoints; ++p) { 226 PetscInt q = points[p]; 227 PetscInt *closure = NULL; 228 PetscInt closureSize, c; 229 230 if (cStart <= q && q < cEnd && !completeCells) { /* skip cells */ 231 continue; 232 } 233 PetscCall(DMPlexGetTransitiveClosure(dm, q, PETSC_TRUE, &closureSize, &closure)); 234 for (c = 0; c < closureSize * 2; c += 2) PetscCall(DMLabelSetValue(label, closure[c], values[v])); 235 PetscCall(DMPlexRestoreTransitiveClosure(dm, q, PETSC_TRUE, &closureSize, &closure)); 236 } 237 PetscCall(ISRestoreIndices(pointIS, &points)); 238 PetscCall(ISDestroy(&pointIS)); 239 } 240 PetscCall(ISRestoreIndices(valueIS, &values)); 241 PetscCall(ISDestroy(&valueIS)); 242 PetscCall(DMGetPointSF(dm, &sfPoint)); 243 PetscCall(PetscSFGetGraph(sfPoint, &nroots, NULL, NULL, NULL)); 244 if (nroots >= 0) { 245 DMLabel lblRoots, lblLeaves; 246 IS valueIS, pointIS; 247 const PetscInt *values; 248 PetscInt numValues, v; 249 250 /* Pull point contributions from remote leaves into local roots */ 251 PetscCall(DMLabelGather(label, sfPoint, &lblLeaves)); 252 PetscCall(DMLabelGetValueIS(lblLeaves, &valueIS)); 253 PetscCall(ISGetLocalSize(valueIS, &numValues)); 254 PetscCall(ISGetIndices(valueIS, &values)); 255 for (v = 0; v < numValues; ++v) { 256 const PetscInt value = values[v]; 257 258 PetscCall(DMLabelGetStratumIS(lblLeaves, value, &pointIS)); 259 PetscCall(DMLabelInsertIS(label, pointIS, value)); 260 PetscCall(ISDestroy(&pointIS)); 261 } 262 PetscCall(ISRestoreIndices(valueIS, &values)); 263 PetscCall(ISDestroy(&valueIS)); 264 PetscCall(DMLabelDestroy(&lblLeaves)); 265 /* Push point contributions from roots into remote leaves */ 266 PetscCall(DMLabelDistribute(label, sfPoint, &lblRoots)); 267 PetscCall(DMLabelGetValueIS(lblRoots, &valueIS)); 268 PetscCall(ISGetLocalSize(valueIS, &numValues)); 269 PetscCall(ISGetIndices(valueIS, &values)); 270 for (v = 0; v < numValues; ++v) { 271 const PetscInt value = values[v]; 272 273 PetscCall(DMLabelGetStratumIS(lblRoots, value, &pointIS)); 274 PetscCall(DMLabelInsertIS(label, pointIS, value)); 275 PetscCall(ISDestroy(&pointIS)); 276 } 277 PetscCall(ISRestoreIndices(valueIS, &values)); 278 PetscCall(ISDestroy(&valueIS)); 279 PetscCall(DMLabelDestroy(&lblRoots)); 280 } 281 PetscFunctionReturn(PETSC_SUCCESS); 282 } 283 284 /*@ 285 DMPlexLabelComplete - Starting with a label marking points on a surface, we add the transitive closure to the surface 286 287 Input Parameters: 288 + dm - The `DM` 289 - label - A `DMLabel` marking the surface points 290 291 Output Parameter: 292 . label - A `DMLabel` marking all surface points in the transitive closure 293 294 Level: developer 295 296 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexLabelCohesiveComplete()` 297 @*/ 298 PetscErrorCode DMPlexLabelComplete(DM dm, DMLabel label) 299 { 300 PetscFunctionBegin; 301 PetscCall(DMPlexLabelComplete_Internal(dm, label, PETSC_TRUE)); 302 PetscFunctionReturn(PETSC_SUCCESS); 303 } 304 305 /*@ 306 DMPlexLabelAddCells - Starting with a label marking points on a surface, we add a cell for each point 307 308 Input Parameters: 309 + dm - The `DM` 310 - label - A `DMLabel` marking the surface points 311 312 Output Parameter: 313 . label - A `DMLabel` incorporating cells 314 315 Level: developer 316 317 Note: 318 The cells allow FEM boundary conditions to be applied using the cell geometry 319 320 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexLabelAddFaceCells()`, `DMPlexLabelComplete()`, `DMPlexLabelCohesiveComplete()` 321 @*/ 322 PetscErrorCode DMPlexLabelAddCells(DM dm, DMLabel label) 323 { 324 IS valueIS; 325 const PetscInt *values; 326 PetscInt numValues, v, csStart, csEnd, chStart, chEnd; 327 328 PetscFunctionBegin; 329 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &csStart, &csEnd)); 330 PetscCall(DMPlexGetHeightStratum(dm, 0, &chStart, &chEnd)); 331 PetscCall(DMLabelGetNumValues(label, &numValues)); 332 PetscCall(DMLabelGetValueIS(label, &valueIS)); 333 PetscCall(ISGetIndices(valueIS, &values)); 334 for (v = 0; v < numValues; ++v) { 335 IS pointIS; 336 const PetscInt *points; 337 PetscInt numPoints, p; 338 339 PetscCall(DMLabelGetStratumSize(label, values[v], &numPoints)); 340 PetscCall(DMLabelGetStratumIS(label, values[v], &pointIS)); 341 PetscCall(ISGetIndices(pointIS, &points)); 342 for (p = 0; p < numPoints; ++p) { 343 const PetscInt point = points[p]; 344 PetscInt *closure = NULL; 345 PetscInt closureSize, cl, h, cStart, cEnd; 346 DMPolytopeType ct; 347 348 // If the point is a hybrid, allow hybrid cells 349 PetscCall(DMPlexGetCellType(dm, point, &ct)); 350 PetscCall(DMPlexGetPointHeight(dm, point, &h)); 351 if (DMPolytopeTypeIsHybrid(ct)) { 352 cStart = chStart; 353 cEnd = chEnd; 354 } else { 355 cStart = csStart; 356 cEnd = csEnd; 357 } 358 359 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closure)); 360 for (cl = closureSize - 1; cl > 0; --cl) { 361 const PetscInt cell = closure[cl * 2]; 362 if (cell >= cStart && cell < cEnd) { 363 PetscCall(DMLabelSetValue(label, cell, values[v])); 364 break; 365 } 366 } 367 PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closure)); 368 } 369 PetscCall(ISRestoreIndices(pointIS, &points)); 370 PetscCall(ISDestroy(&pointIS)); 371 } 372 PetscCall(ISRestoreIndices(valueIS, &values)); 373 PetscCall(ISDestroy(&valueIS)); 374 PetscFunctionReturn(PETSC_SUCCESS); 375 } 376 377 /*@ 378 DMPlexLabelAddFaceCells - Starting with a label marking faces on a surface, we add a cell for each face 379 380 Input Parameters: 381 + dm - The `DM` 382 - label - A `DMLabel` marking the surface points 383 384 Output Parameter: 385 . label - A `DMLabel` incorporating cells 386 387 Level: developer 388 389 Note: 390 The cells allow FEM boundary conditions to be applied using the cell geometry 391 392 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexLabelAddCells()`, `DMPlexLabelComplete()`, `DMPlexLabelCohesiveComplete()` 393 @*/ 394 PetscErrorCode DMPlexLabelAddFaceCells(DM dm, DMLabel label) 395 { 396 IS valueIS; 397 const PetscInt *values; 398 PetscInt numValues, v, cStart, cEnd, fStart, fEnd; 399 400 PetscFunctionBegin; 401 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 402 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 403 PetscCall(DMLabelGetNumValues(label, &numValues)); 404 PetscCall(DMLabelGetValueIS(label, &valueIS)); 405 PetscCall(ISGetIndices(valueIS, &values)); 406 for (v = 0; v < numValues; ++v) { 407 IS pointIS; 408 const PetscInt *points; 409 PetscInt numPoints, p; 410 411 PetscCall(DMLabelGetStratumSize(label, values[v], &numPoints)); 412 PetscCall(DMLabelGetStratumIS(label, values[v], &pointIS)); 413 PetscCall(ISGetIndices(pointIS, &points)); 414 for (p = 0; p < numPoints; ++p) { 415 const PetscInt face = points[p]; 416 PetscInt *closure = NULL; 417 PetscInt closureSize, cl; 418 419 if ((face < fStart) || (face >= fEnd)) continue; 420 PetscCall(DMPlexGetTransitiveClosure(dm, face, PETSC_FALSE, &closureSize, &closure)); 421 for (cl = closureSize - 1; cl > 0; --cl) { 422 const PetscInt cell = closure[cl * 2]; 423 if (cell >= cStart && cell < cEnd) { 424 PetscCall(DMLabelSetValue(label, cell, values[v])); 425 break; 426 } 427 } 428 PetscCall(DMPlexRestoreTransitiveClosure(dm, face, PETSC_FALSE, &closureSize, &closure)); 429 } 430 PetscCall(ISRestoreIndices(pointIS, &points)); 431 PetscCall(ISDestroy(&pointIS)); 432 } 433 PetscCall(ISRestoreIndices(valueIS, &values)); 434 PetscCall(ISDestroy(&valueIS)); 435 PetscFunctionReturn(PETSC_SUCCESS); 436 } 437 438 /*@ 439 DMPlexLabelClearCells - Remove cells from a label 440 441 Input Parameters: 442 + dm - The `DM` 443 - label - A `DMLabel` marking surface points and their adjacent cells 444 445 Output Parameter: 446 . label - A `DMLabel` without cells 447 448 Level: developer 449 450 Note: 451 This undoes `DMPlexLabelAddCells()` or `DMPlexLabelAddFaceCells()` 452 453 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexLabelComplete()`, `DMPlexLabelCohesiveComplete()`, `DMPlexLabelAddCells()` 454 @*/ 455 PetscErrorCode DMPlexLabelClearCells(DM dm, DMLabel label) 456 { 457 IS valueIS; 458 const PetscInt *values; 459 PetscInt numValues, v, cStart, cEnd; 460 461 PetscFunctionBegin; 462 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 463 PetscCall(DMLabelGetNumValues(label, &numValues)); 464 PetscCall(DMLabelGetValueIS(label, &valueIS)); 465 PetscCall(ISGetIndices(valueIS, &values)); 466 for (v = 0; v < numValues; ++v) { 467 IS pointIS; 468 const PetscInt *points; 469 PetscInt numPoints, p; 470 471 PetscCall(DMLabelGetStratumSize(label, values[v], &numPoints)); 472 PetscCall(DMLabelGetStratumIS(label, values[v], &pointIS)); 473 PetscCall(ISGetIndices(pointIS, &points)); 474 for (p = 0; p < numPoints; ++p) { 475 PetscInt point = points[p]; 476 477 if (point >= cStart && point < cEnd) PetscCall(DMLabelClearValue(label, point, values[v])); 478 } 479 PetscCall(ISRestoreIndices(pointIS, &points)); 480 PetscCall(ISDestroy(&pointIS)); 481 } 482 PetscCall(ISRestoreIndices(valueIS, &values)); 483 PetscCall(ISDestroy(&valueIS)); 484 PetscFunctionReturn(PETSC_SUCCESS); 485 } 486 487 /* take (oldEnd, added) pairs, ordered by height and convert them to (oldstart, newstart) pairs, ordered by ascending 488 * index (skipping first, which is (0,0)) */ 489 static inline PetscErrorCode DMPlexShiftPointSetUp_Internal(PetscInt depth, PetscInt depthShift[]) 490 { 491 PetscInt d, off = 0; 492 493 PetscFunctionBegin; 494 /* sort by (oldend): yes this is an O(n^2) sort, we expect depth <= 3 */ 495 for (d = 0; d < depth; d++) { 496 PetscInt firstd = d; 497 PetscInt firstStart = depthShift[2 * d]; 498 PetscInt e; 499 500 for (e = d + 1; e <= depth; e++) { 501 if (depthShift[2 * e] < firstStart) { 502 firstd = e; 503 firstStart = depthShift[2 * d]; 504 } 505 } 506 if (firstd != d) { 507 PetscInt swap[2]; 508 509 e = firstd; 510 swap[0] = depthShift[2 * d]; 511 swap[1] = depthShift[2 * d + 1]; 512 depthShift[2 * d] = depthShift[2 * e]; 513 depthShift[2 * d + 1] = depthShift[2 * e + 1]; 514 depthShift[2 * e] = swap[0]; 515 depthShift[2 * e + 1] = swap[1]; 516 } 517 } 518 /* convert (oldstart, added) to (oldstart, newstart) */ 519 for (d = 0; d <= depth; d++) { 520 off += depthShift[2 * d + 1]; 521 depthShift[2 * d + 1] = depthShift[2 * d] + off; 522 } 523 PetscFunctionReturn(PETSC_SUCCESS); 524 } 525 526 /* depthShift is a list of (old, new) pairs */ 527 static inline PetscInt DMPlexShiftPoint_Internal(PetscInt p, PetscInt depth, PetscInt depthShift[]) 528 { 529 PetscInt d; 530 PetscInt newOff = 0; 531 532 for (d = 0; d <= depth; d++) { 533 if (p < depthShift[2 * d]) return p + newOff; 534 else newOff = depthShift[2 * d + 1] - depthShift[2 * d]; 535 } 536 return p + newOff; 537 } 538 539 /* depthShift is a list of (old, new) pairs */ 540 static inline PetscInt DMPlexShiftPointInverse_Internal(PetscInt p, PetscInt depth, PetscInt depthShift[]) 541 { 542 PetscInt d; 543 PetscInt newOff = 0; 544 545 for (d = 0; d <= depth; d++) { 546 if (p < depthShift[2 * d + 1]) return p + newOff; 547 else newOff = depthShift[2 * d] - depthShift[2 * d + 1]; 548 } 549 return p + newOff; 550 } 551 552 static PetscErrorCode DMPlexShiftSizes_Internal(DM dm, PetscInt depthShift[], DM dmNew) 553 { 554 PetscInt depth = 0, d, pStart, pEnd, p; 555 DMLabel depthLabel; 556 557 PetscFunctionBegin; 558 PetscCall(DMPlexGetDepth(dm, &depth)); 559 if (depth < 0) PetscFunctionReturn(PETSC_SUCCESS); 560 /* Step 1: Expand chart */ 561 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 562 pEnd = DMPlexShiftPoint_Internal(pEnd, depth, depthShift); 563 PetscCall(DMPlexSetChart(dmNew, pStart, pEnd)); 564 PetscCall(DMCreateLabel(dmNew, "depth")); 565 PetscCall(DMPlexGetDepthLabel(dmNew, &depthLabel)); 566 PetscCall(DMCreateLabel(dmNew, "celltype")); 567 /* Step 2: Set cone and support sizes */ 568 for (d = 0; d <= depth; ++d) { 569 PetscInt pStartNew, pEndNew; 570 IS pIS; 571 572 PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd)); 573 pStartNew = DMPlexShiftPoint_Internal(pStart, depth, depthShift); 574 pEndNew = DMPlexShiftPoint_Internal(pEnd, depth, depthShift); 575 PetscCall(ISCreateStride(PETSC_COMM_SELF, pEndNew - pStartNew, pStartNew, 1, &pIS)); 576 PetscCall(DMLabelSetStratumIS(depthLabel, d, pIS)); 577 PetscCall(ISDestroy(&pIS)); 578 for (p = pStart; p < pEnd; ++p) { 579 PetscInt newp = DMPlexShiftPoint_Internal(p, depth, depthShift); 580 PetscInt size; 581 DMPolytopeType ct; 582 583 PetscCall(DMPlexGetConeSize(dm, p, &size)); 584 PetscCall(DMPlexSetConeSize(dmNew, newp, size)); 585 PetscCall(DMPlexGetSupportSize(dm, p, &size)); 586 PetscCall(DMPlexSetSupportSize(dmNew, newp, size)); 587 PetscCall(DMPlexGetCellType(dm, p, &ct)); 588 PetscCall(DMPlexSetCellType(dmNew, newp, ct)); 589 } 590 } 591 PetscFunctionReturn(PETSC_SUCCESS); 592 } 593 594 static PetscErrorCode DMPlexShiftPoints_Internal(DM dm, PetscInt depthShift[], DM dmNew) 595 { 596 PetscInt *newpoints; 597 PetscInt depth = 0, maxConeSize, maxSupportSize, maxConeSizeNew, maxSupportSizeNew, pStart, pEnd, p; 598 599 PetscFunctionBegin; 600 PetscCall(DMPlexGetDepth(dm, &depth)); 601 if (depth < 0) PetscFunctionReturn(PETSC_SUCCESS); 602 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 603 PetscCall(DMPlexGetMaxSizes(dmNew, &maxConeSizeNew, &maxSupportSizeNew)); 604 PetscCall(PetscMalloc1(PetscMax(PetscMax(maxConeSize, maxSupportSize), PetscMax(maxConeSizeNew, maxSupportSizeNew)), &newpoints)); 605 /* Step 5: Set cones and supports */ 606 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 607 for (p = pStart; p < pEnd; ++p) { 608 const PetscInt *points = NULL, *orientations = NULL; 609 PetscInt size, sizeNew, i, newp = DMPlexShiftPoint_Internal(p, depth, depthShift); 610 611 PetscCall(DMPlexGetConeSize(dm, p, &size)); 612 PetscCall(DMPlexGetCone(dm, p, &points)); 613 PetscCall(DMPlexGetConeOrientation(dm, p, &orientations)); 614 for (i = 0; i < size; ++i) newpoints[i] = DMPlexShiftPoint_Internal(points[i], depth, depthShift); 615 PetscCall(DMPlexSetCone(dmNew, newp, newpoints)); 616 PetscCall(DMPlexSetConeOrientation(dmNew, newp, orientations)); 617 PetscCall(DMPlexGetSupportSize(dm, p, &size)); 618 PetscCall(DMPlexGetSupportSize(dmNew, newp, &sizeNew)); 619 PetscCall(DMPlexGetSupport(dm, p, &points)); 620 for (i = 0; i < size; ++i) newpoints[i] = DMPlexShiftPoint_Internal(points[i], depth, depthShift); 621 for (i = size; i < sizeNew; ++i) newpoints[i] = 0; 622 PetscCall(DMPlexSetSupport(dmNew, newp, newpoints)); 623 } 624 PetscCall(PetscFree(newpoints)); 625 PetscFunctionReturn(PETSC_SUCCESS); 626 } 627 628 static PetscErrorCode DMPlexShiftCoordinates_Internal(DM dm, PetscInt depthShift[], DM dmNew) 629 { 630 PetscSection coordSection, newCoordSection; 631 Vec coordinates, newCoordinates; 632 PetscScalar *coords, *newCoords; 633 PetscInt coordSize, sStart, sEnd; 634 PetscInt dim, depth = 0, cStart, cEnd, cStartNew, cEndNew, c, vStart, vEnd, vStartNew, vEndNew, v; 635 PetscBool hasCells; 636 637 PetscFunctionBegin; 638 PetscCall(DMGetCoordinateDim(dm, &dim)); 639 PetscCall(DMSetCoordinateDim(dmNew, dim)); 640 PetscCall(DMPlexGetDepth(dm, &depth)); 641 /* Step 8: Convert coordinates */ 642 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 643 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 644 PetscCall(DMPlexGetDepthStratum(dmNew, 0, &vStartNew, &vEndNew)); 645 PetscCall(DMPlexGetHeightStratum(dmNew, 0, &cStartNew, &cEndNew)); 646 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 647 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &newCoordSection)); 648 PetscCall(PetscSectionSetNumFields(newCoordSection, 1)); 649 PetscCall(PetscSectionSetFieldComponents(newCoordSection, 0, dim)); 650 PetscCall(PetscSectionGetChart(coordSection, &sStart, &sEnd)); 651 hasCells = sStart == cStart ? PETSC_TRUE : PETSC_FALSE; 652 PetscCall(PetscSectionSetChart(newCoordSection, hasCells ? cStartNew : vStartNew, vEndNew)); 653 if (hasCells) { 654 for (c = cStart; c < cEnd; ++c) { 655 PetscInt cNew = DMPlexShiftPoint_Internal(c, depth, depthShift), dof; 656 657 PetscCall(PetscSectionGetDof(coordSection, c, &dof)); 658 PetscCall(PetscSectionSetDof(newCoordSection, cNew, dof)); 659 PetscCall(PetscSectionSetFieldDof(newCoordSection, cNew, 0, dof)); 660 } 661 } 662 for (v = vStartNew; v < vEndNew; ++v) { 663 PetscCall(PetscSectionSetDof(newCoordSection, v, dim)); 664 PetscCall(PetscSectionSetFieldDof(newCoordSection, v, 0, dim)); 665 } 666 PetscCall(PetscSectionSetUp(newCoordSection)); 667 PetscCall(DMSetCoordinateSection(dmNew, PETSC_DETERMINE, newCoordSection)); 668 PetscCall(PetscSectionGetStorageSize(newCoordSection, &coordSize)); 669 PetscCall(VecCreate(PETSC_COMM_SELF, &newCoordinates)); 670 PetscCall(PetscObjectSetName((PetscObject)newCoordinates, "coordinates")); 671 PetscCall(VecSetSizes(newCoordinates, coordSize, PETSC_DETERMINE)); 672 PetscCall(VecSetBlockSize(newCoordinates, dim)); 673 PetscCall(VecSetType(newCoordinates, VECSTANDARD)); 674 PetscCall(DMSetCoordinatesLocal(dmNew, newCoordinates)); 675 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 676 PetscCall(VecGetArray(coordinates, &coords)); 677 PetscCall(VecGetArray(newCoordinates, &newCoords)); 678 if (hasCells) { 679 for (c = cStart; c < cEnd; ++c) { 680 PetscInt cNew = DMPlexShiftPoint_Internal(c, depth, depthShift), dof, off, noff, d; 681 682 PetscCall(PetscSectionGetDof(coordSection, c, &dof)); 683 PetscCall(PetscSectionGetOffset(coordSection, c, &off)); 684 PetscCall(PetscSectionGetOffset(newCoordSection, cNew, &noff)); 685 for (d = 0; d < dof; ++d) newCoords[noff + d] = coords[off + d]; 686 } 687 } 688 for (v = vStart; v < vEnd; ++v) { 689 PetscInt dof, off, noff, d; 690 691 PetscCall(PetscSectionGetDof(coordSection, v, &dof)); 692 PetscCall(PetscSectionGetOffset(coordSection, v, &off)); 693 PetscCall(PetscSectionGetOffset(newCoordSection, DMPlexShiftPoint_Internal(v, depth, depthShift), &noff)); 694 for (d = 0; d < dof; ++d) newCoords[noff + d] = coords[off + d]; 695 } 696 PetscCall(VecRestoreArray(coordinates, &coords)); 697 PetscCall(VecRestoreArray(newCoordinates, &newCoords)); 698 PetscCall(VecDestroy(&newCoordinates)); 699 PetscCall(PetscSectionDestroy(&newCoordSection)); 700 PetscFunctionReturn(PETSC_SUCCESS); 701 } 702 703 static PetscErrorCode DMPlexShiftSF_Single(DM dm, PetscInt depthShift[], PetscSF sf, PetscSF sfNew) 704 { 705 const PetscSFNode *remotePoints; 706 PetscSFNode *gremotePoints; 707 const PetscInt *localPoints; 708 PetscInt *glocalPoints, *newLocation, *newRemoteLocation; 709 PetscInt numRoots, numLeaves, l, pStart, pEnd, depth = 0, totShift = 0; 710 711 PetscFunctionBegin; 712 PetscCall(DMPlexGetDepth(dm, &depth)); 713 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 714 PetscCall(PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints)); 715 totShift = DMPlexShiftPoint_Internal(pEnd, depth, depthShift) - pEnd; 716 if (numRoots >= 0) { 717 PetscCall(PetscMalloc2(numRoots, &newLocation, pEnd - pStart, &newRemoteLocation)); 718 for (l = 0; l < numRoots; ++l) newLocation[l] = DMPlexShiftPoint_Internal(l, depth, depthShift); 719 PetscCall(PetscSFBcastBegin(sf, MPIU_INT, newLocation, newRemoteLocation, MPI_REPLACE)); 720 PetscCall(PetscSFBcastEnd(sf, MPIU_INT, newLocation, newRemoteLocation, MPI_REPLACE)); 721 PetscCall(PetscMalloc1(numLeaves, &glocalPoints)); 722 PetscCall(PetscMalloc1(numLeaves, &gremotePoints)); 723 for (l = 0; l < numLeaves; ++l) { 724 glocalPoints[l] = DMPlexShiftPoint_Internal(localPoints[l], depth, depthShift); 725 gremotePoints[l].rank = remotePoints[l].rank; 726 gremotePoints[l].index = newRemoteLocation[localPoints[l]]; 727 } 728 PetscCall(PetscFree2(newLocation, newRemoteLocation)); 729 PetscCall(PetscSFSetGraph(sfNew, numRoots + totShift, numLeaves, glocalPoints, PETSC_OWN_POINTER, gremotePoints, PETSC_OWN_POINTER)); 730 } 731 PetscFunctionReturn(PETSC_SUCCESS); 732 } 733 734 static PetscErrorCode DMPlexShiftSF_Internal(DM dm, PetscInt depthShift[], DM dmNew) 735 { 736 PetscSF sfPoint, sfPointNew; 737 PetscBool useNatural; 738 739 PetscFunctionBegin; 740 /* Step 9: Convert pointSF */ 741 PetscCall(DMGetPointSF(dm, &sfPoint)); 742 PetscCall(DMGetPointSF(dmNew, &sfPointNew)); 743 PetscCall(DMPlexShiftSF_Single(dm, depthShift, sfPoint, sfPointNew)); 744 /* Step 9b: Convert naturalSF */ 745 PetscCall(DMGetUseNatural(dm, &useNatural)); 746 if (useNatural) { 747 PetscSF sfNat, sfNatNew; 748 749 PetscCall(DMSetUseNatural(dmNew, useNatural)); 750 PetscCall(DMGetNaturalSF(dm, &sfNat)); 751 PetscCall(DMGetNaturalSF(dmNew, &sfNatNew)); 752 PetscCall(DMPlexShiftSF_Single(dm, depthShift, sfNat, sfNatNew)); 753 } 754 PetscFunctionReturn(PETSC_SUCCESS); 755 } 756 757 static PetscErrorCode DMPlexShiftLabels_Internal(DM dm, PetscInt depthShift[], DM dmNew) 758 { 759 PetscInt depth = 0, numLabels, l; 760 761 PetscFunctionBegin; 762 PetscCall(DMPlexGetDepth(dm, &depth)); 763 /* Step 10: Convert labels */ 764 PetscCall(DMGetNumLabels(dm, &numLabels)); 765 for (l = 0; l < numLabels; ++l) { 766 DMLabel label, newlabel; 767 const char *lname; 768 PetscBool isDepth, isDim; 769 IS valueIS; 770 const PetscInt *values; 771 PetscInt numValues, val; 772 773 PetscCall(DMGetLabelName(dm, l, &lname)); 774 PetscCall(PetscStrcmp(lname, "depth", &isDepth)); 775 if (isDepth) continue; 776 PetscCall(PetscStrcmp(lname, "dim", &isDim)); 777 if (isDim) continue; 778 PetscCall(DMCreateLabel(dmNew, lname)); 779 PetscCall(DMGetLabel(dm, lname, &label)); 780 PetscCall(DMGetLabel(dmNew, lname, &newlabel)); 781 PetscCall(DMLabelGetDefaultValue(label, &val)); 782 PetscCall(DMLabelSetDefaultValue(newlabel, val)); 783 PetscCall(DMLabelGetValueIS(label, &valueIS)); 784 PetscCall(ISGetLocalSize(valueIS, &numValues)); 785 PetscCall(ISGetIndices(valueIS, &values)); 786 for (val = 0; val < numValues; ++val) { 787 IS pointIS; 788 const PetscInt *points; 789 PetscInt numPoints, p; 790 791 PetscCall(DMLabelGetStratumIS(label, values[val], &pointIS)); 792 PetscCall(ISGetLocalSize(pointIS, &numPoints)); 793 PetscCall(ISGetIndices(pointIS, &points)); 794 for (p = 0; p < numPoints; ++p) { 795 const PetscInt newpoint = DMPlexShiftPoint_Internal(points[p], depth, depthShift); 796 797 PetscCall(DMLabelSetValue(newlabel, newpoint, values[val])); 798 } 799 PetscCall(ISRestoreIndices(pointIS, &points)); 800 PetscCall(ISDestroy(&pointIS)); 801 } 802 PetscCall(ISRestoreIndices(valueIS, &values)); 803 PetscCall(ISDestroy(&valueIS)); 804 } 805 PetscFunctionReturn(PETSC_SUCCESS); 806 } 807 808 static PetscErrorCode DMPlexCreateVTKLabel_Internal(DM dm, PetscBool createGhostLabel, DM dmNew) 809 { 810 PetscSF sfPoint; 811 DMLabel vtkLabel, ghostLabel = NULL; 812 const PetscSFNode *leafRemote; 813 const PetscInt *leafLocal; 814 PetscInt cellHeight, cStart, cEnd, c, fStart, fEnd, f, numLeaves, l; 815 PetscMPIInt rank; 816 817 PetscFunctionBegin; 818 /* Step 11: Make label for output (vtk) and to mark ghost points (ghost) */ 819 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 820 PetscCall(DMGetPointSF(dm, &sfPoint)); 821 PetscCall(DMPlexGetVTKCellHeight(dmNew, &cellHeight)); 822 PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd)); 823 PetscCall(PetscSFGetGraph(sfPoint, NULL, &numLeaves, &leafLocal, &leafRemote)); 824 PetscCall(DMCreateLabel(dmNew, "vtk")); 825 PetscCall(DMGetLabel(dmNew, "vtk", &vtkLabel)); 826 if (createGhostLabel) { 827 PetscCall(DMCreateLabel(dmNew, "ghost")); 828 PetscCall(DMGetLabel(dmNew, "ghost", &ghostLabel)); 829 } 830 for (l = 0, c = cStart; l < numLeaves && c < cEnd; ++l, ++c) { 831 for (; c < leafLocal[l] && c < cEnd; ++c) PetscCall(DMLabelSetValue(vtkLabel, c, 1)); 832 if (leafLocal[l] >= cEnd) break; 833 if (leafRemote[l].rank == rank) PetscCall(DMLabelSetValue(vtkLabel, c, 1)); 834 else if (ghostLabel) PetscCall(DMLabelSetValue(ghostLabel, c, 2)); 835 } 836 for (; c < cEnd; ++c) PetscCall(DMLabelSetValue(vtkLabel, c, 1)); 837 if (ghostLabel) { 838 PetscCall(DMPlexGetHeightStratum(dmNew, 1, &fStart, &fEnd)); 839 for (f = fStart; f < fEnd; ++f) { 840 PetscInt numCells; 841 842 PetscCall(DMPlexGetSupportSize(dmNew, f, &numCells)); 843 if (numCells < 2) { 844 PetscCall(DMLabelSetValue(ghostLabel, f, 1)); 845 } else { 846 const PetscInt *cells = NULL; 847 PetscInt vA, vB; 848 849 PetscCall(DMPlexGetSupport(dmNew, f, &cells)); 850 PetscCall(DMLabelGetValue(vtkLabel, cells[0], &vA)); 851 PetscCall(DMLabelGetValue(vtkLabel, cells[1], &vB)); 852 if (vA != 1 && vB != 1) PetscCall(DMLabelSetValue(ghostLabel, f, 1)); 853 } 854 } 855 } 856 PetscFunctionReturn(PETSC_SUCCESS); 857 } 858 859 static PetscErrorCode DMPlexShiftTree_Internal(DM dm, PetscInt depthShift[], DM dmNew) 860 { 861 DM refTree; 862 PetscSection pSec; 863 PetscInt *parents, *childIDs; 864 865 PetscFunctionBegin; 866 PetscCall(DMPlexGetReferenceTree(dm, &refTree)); 867 PetscCall(DMPlexSetReferenceTree(dmNew, refTree)); 868 PetscCall(DMPlexGetTree(dm, &pSec, &parents, &childIDs, NULL, NULL)); 869 if (pSec) { 870 PetscInt p, pStart, pEnd, *parentsShifted, pStartShifted, pEndShifted, depth; 871 PetscInt *childIDsShifted; 872 PetscSection pSecShifted; 873 874 PetscCall(PetscSectionGetChart(pSec, &pStart, &pEnd)); 875 PetscCall(DMPlexGetDepth(dm, &depth)); 876 pStartShifted = DMPlexShiftPoint_Internal(pStart, depth, depthShift); 877 pEndShifted = DMPlexShiftPoint_Internal(pEnd, depth, depthShift); 878 PetscCall(PetscMalloc2(pEndShifted - pStartShifted, &parentsShifted, pEndShifted - pStartShifted, &childIDsShifted)); 879 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dmNew), &pSecShifted)); 880 PetscCall(PetscSectionSetChart(pSecShifted, pStartShifted, pEndShifted)); 881 for (p = pStartShifted; p < pEndShifted; p++) { 882 /* start off assuming no children */ 883 PetscCall(PetscSectionSetDof(pSecShifted, p, 0)); 884 } 885 for (p = pStart; p < pEnd; p++) { 886 PetscInt dof; 887 PetscInt pNew = DMPlexShiftPoint_Internal(p, depth, depthShift); 888 889 PetscCall(PetscSectionGetDof(pSec, p, &dof)); 890 PetscCall(PetscSectionSetDof(pSecShifted, pNew, dof)); 891 } 892 PetscCall(PetscSectionSetUp(pSecShifted)); 893 for (p = pStart; p < pEnd; p++) { 894 PetscInt dof; 895 PetscInt pNew = DMPlexShiftPoint_Internal(p, depth, depthShift); 896 897 PetscCall(PetscSectionGetDof(pSec, p, &dof)); 898 if (dof) { 899 PetscInt off, offNew; 900 901 PetscCall(PetscSectionGetOffset(pSec, p, &off)); 902 PetscCall(PetscSectionGetOffset(pSecShifted, pNew, &offNew)); 903 parentsShifted[offNew] = DMPlexShiftPoint_Internal(parents[off], depth, depthShift); 904 childIDsShifted[offNew] = childIDs[off]; 905 } 906 } 907 PetscCall(DMPlexSetTree(dmNew, pSecShifted, parentsShifted, childIDsShifted)); 908 PetscCall(PetscFree2(parentsShifted, childIDsShifted)); 909 PetscCall(PetscSectionDestroy(&pSecShifted)); 910 } 911 PetscFunctionReturn(PETSC_SUCCESS); 912 } 913 914 static PetscErrorCode DMPlexConstructGhostCells_Internal(DM dm, DMLabel label, PetscInt *numGhostCells, DM gdm) 915 { 916 PetscSF sf; 917 IS valueIS; 918 const PetscInt *values, *leaves; 919 PetscInt *depthShift; 920 PetscInt d, depth = 0, nleaves, loc, Ng, numFS, fs, fStart, fEnd, ghostCell, cEnd, c; 921 const PetscReal *maxCell, *Lstart, *L; 922 923 PetscFunctionBegin; 924 PetscCall(DMGetPointSF(dm, &sf)); 925 PetscCall(PetscSFGetGraph(sf, NULL, &nleaves, &leaves, NULL)); 926 nleaves = PetscMax(0, nleaves); 927 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 928 /* Count ghost cells */ 929 PetscCall(DMLabelGetValueIS(label, &valueIS)); 930 PetscCall(ISGetLocalSize(valueIS, &numFS)); 931 PetscCall(ISGetIndices(valueIS, &values)); 932 Ng = 0; 933 for (fs = 0; fs < numFS; ++fs) { 934 IS faceIS; 935 const PetscInt *faces; 936 PetscInt numFaces, f, numBdFaces = 0; 937 938 PetscCall(DMLabelGetStratumIS(label, values[fs], &faceIS)); 939 PetscCall(ISGetLocalSize(faceIS, &numFaces)); 940 PetscCall(ISGetIndices(faceIS, &faces)); 941 for (f = 0; f < numFaces; ++f) { 942 PetscInt numChildren; 943 944 PetscCall(PetscFindInt(faces[f], nleaves, leaves, &loc)); 945 PetscCall(DMPlexGetTreeChildren(dm, faces[f], &numChildren, NULL)); 946 /* non-local and ancestors points don't get to register ghosts */ 947 if (loc >= 0 || numChildren) continue; 948 if (faces[f] >= fStart && faces[f] < fEnd) ++numBdFaces; 949 } 950 Ng += numBdFaces; 951 PetscCall(ISRestoreIndices(faceIS, &faces)); 952 PetscCall(ISDestroy(&faceIS)); 953 } 954 PetscCall(DMPlexGetDepth(dm, &depth)); 955 PetscCall(PetscMalloc1(2 * (depth + 1), &depthShift)); 956 for (d = 0; d <= depth; d++) { 957 PetscInt dEnd; 958 959 PetscCall(DMPlexGetDepthStratum(dm, d, NULL, &dEnd)); 960 depthShift[2 * d] = dEnd; 961 depthShift[2 * d + 1] = 0; 962 } 963 if (depth >= 0) depthShift[2 * depth + 1] = Ng; 964 PetscCall(DMPlexShiftPointSetUp_Internal(depth, depthShift)); 965 PetscCall(DMPlexShiftSizes_Internal(dm, depthShift, gdm)); 966 /* Step 3: Set cone/support sizes for new points */ 967 PetscCall(DMPlexGetHeightStratum(dm, 0, NULL, &cEnd)); 968 for (c = cEnd; c < cEnd + Ng; ++c) PetscCall(DMPlexSetConeSize(gdm, c, 1)); 969 for (fs = 0; fs < numFS; ++fs) { 970 IS faceIS; 971 const PetscInt *faces; 972 PetscInt numFaces, f; 973 974 PetscCall(DMLabelGetStratumIS(label, values[fs], &faceIS)); 975 PetscCall(ISGetLocalSize(faceIS, &numFaces)); 976 PetscCall(ISGetIndices(faceIS, &faces)); 977 for (f = 0; f < numFaces; ++f) { 978 PetscInt size, numChildren; 979 980 PetscCall(PetscFindInt(faces[f], nleaves, leaves, &loc)); 981 PetscCall(DMPlexGetTreeChildren(dm, faces[f], &numChildren, NULL)); 982 if (loc >= 0 || numChildren) continue; 983 if ((faces[f] < fStart) || (faces[f] >= fEnd)) continue; 984 PetscCall(DMPlexGetSupportSize(dm, faces[f], &size)); 985 PetscCheck(size == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "DM has boundary face %" PetscInt_FMT " with %" PetscInt_FMT " support cells", faces[f], size); 986 PetscCall(DMPlexSetSupportSize(gdm, faces[f] + Ng, 2)); 987 } 988 PetscCall(ISRestoreIndices(faceIS, &faces)); 989 PetscCall(ISDestroy(&faceIS)); 990 } 991 /* Step 4: Setup ghosted DM */ 992 PetscCall(DMSetUp(gdm)); 993 PetscCall(DMPlexShiftPoints_Internal(dm, depthShift, gdm)); 994 /* Step 6: Set cones and supports for new points */ 995 ghostCell = cEnd; 996 for (fs = 0; fs < numFS; ++fs) { 997 IS faceIS; 998 const PetscInt *faces; 999 PetscInt numFaces, f; 1000 1001 PetscCall(DMLabelGetStratumIS(label, values[fs], &faceIS)); 1002 PetscCall(ISGetLocalSize(faceIS, &numFaces)); 1003 PetscCall(ISGetIndices(faceIS, &faces)); 1004 for (f = 0; f < numFaces; ++f) { 1005 PetscInt newFace = faces[f] + Ng, numChildren; 1006 1007 PetscCall(PetscFindInt(faces[f], nleaves, leaves, &loc)); 1008 PetscCall(DMPlexGetTreeChildren(dm, faces[f], &numChildren, NULL)); 1009 if (loc >= 0 || numChildren) continue; 1010 if ((faces[f] < fStart) || (faces[f] >= fEnd)) continue; 1011 PetscCall(DMPlexSetCone(gdm, ghostCell, &newFace)); 1012 PetscCall(DMPlexInsertSupport(gdm, newFace, 1, ghostCell)); 1013 ++ghostCell; 1014 } 1015 PetscCall(ISRestoreIndices(faceIS, &faces)); 1016 PetscCall(ISDestroy(&faceIS)); 1017 } 1018 PetscCall(ISRestoreIndices(valueIS, &values)); 1019 PetscCall(ISDestroy(&valueIS)); 1020 PetscCall(DMPlexShiftCoordinates_Internal(dm, depthShift, gdm)); 1021 PetscCall(DMPlexShiftSF_Internal(dm, depthShift, gdm)); 1022 PetscCall(DMPlexShiftLabels_Internal(dm, depthShift, gdm)); 1023 PetscCall(DMPlexCreateVTKLabel_Internal(dm, PETSC_TRUE, gdm)); 1024 PetscCall(DMPlexShiftTree_Internal(dm, depthShift, gdm)); 1025 PetscCall(PetscFree(depthShift)); 1026 for (c = cEnd; c < cEnd + Ng; ++c) PetscCall(DMPlexSetCellType(gdm, c, DM_POLYTOPE_FV_GHOST)); 1027 /* Step 7: Periodicity */ 1028 PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L)); 1029 PetscCall(DMSetPeriodicity(gdm, maxCell, Lstart, L)); 1030 if (numGhostCells) *numGhostCells = Ng; 1031 PetscFunctionReturn(PETSC_SUCCESS); 1032 } 1033 1034 /*@ 1035 DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face 1036 1037 Collective 1038 1039 Input Parameters: 1040 + dm - The original `DM` 1041 - labelName - The label specifying the boundary faces, or "Face Sets" if this is `NULL` 1042 1043 Output Parameters: 1044 + numGhostCells - The number of ghost cells added to the `DM` 1045 - dmGhosted - The new `DM` 1046 1047 Level: developer 1048 1049 Note: 1050 If no label exists of that name, one will be created marking all boundary faces 1051 1052 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()` 1053 @*/ 1054 PetscErrorCode DMPlexConstructGhostCells(DM dm, const char labelName[], PetscInt *numGhostCells, DM *dmGhosted) 1055 { 1056 DM gdm; 1057 DMLabel label; 1058 const char *name = labelName ? labelName : "Face Sets"; 1059 PetscInt dim, Ng = 0; 1060 PetscBool useCone, useClosure; 1061 1062 PetscFunctionBegin; 1063 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1064 if (numGhostCells) PetscAssertPointer(numGhostCells, 3); 1065 PetscAssertPointer(dmGhosted, 4); 1066 PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &gdm)); 1067 PetscCall(DMSetType(gdm, DMPLEX)); 1068 PetscCall(DMGetDimension(dm, &dim)); 1069 PetscCall(DMSetDimension(gdm, dim)); 1070 PetscCall(DMGetBasicAdjacency(dm, &useCone, &useClosure)); 1071 PetscCall(DMSetBasicAdjacency(gdm, useCone, useClosure)); 1072 PetscCall(DMGetLabel(dm, name, &label)); 1073 if (!label) { 1074 /* Get label for boundary faces */ 1075 PetscCall(DMCreateLabel(dm, name)); 1076 PetscCall(DMGetLabel(dm, name, &label)); 1077 PetscCall(DMPlexMarkBoundaryFaces(dm, 1, label)); 1078 } 1079 PetscCall(DMPlexConstructGhostCells_Internal(dm, label, &Ng, gdm)); 1080 PetscCall(DMCopyDisc(dm, gdm)); 1081 PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_TRUE, gdm)); 1082 gdm->setfromoptionscalled = dm->setfromoptionscalled; 1083 if (numGhostCells) *numGhostCells = Ng; 1084 *dmGhosted = gdm; 1085 PetscFunctionReturn(PETSC_SUCCESS); 1086 } 1087 1088 static PetscErrorCode DivideCells_Private(DM dm, DMLabel label, DMPlexPointQueue queue) 1089 { 1090 PetscInt dim, d, shift = 100, *pStart, *pEnd; 1091 1092 PetscFunctionBegin; 1093 PetscCall(DMGetDimension(dm, &dim)); 1094 PetscCall(PetscMalloc2(dim, &pStart, dim, &pEnd)); 1095 for (d = 0; d < dim; ++d) PetscCall(DMPlexGetDepthStratum(dm, d, &pStart[d], &pEnd[d])); 1096 while (!DMPlexPointQueueEmpty(queue)) { 1097 PetscInt cell = -1; 1098 PetscInt *closure = NULL; 1099 PetscInt closureSize, cl, cval; 1100 1101 PetscCall(DMPlexPointQueueDequeue(queue, &cell)); 1102 PetscCall(DMLabelGetValue(label, cell, &cval)); 1103 PetscCall(DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure)); 1104 /* Mark points in the cell closure that touch the fault */ 1105 for (d = 0; d < dim; ++d) { 1106 for (cl = 0; cl < closureSize * 2; cl += 2) { 1107 const PetscInt clp = closure[cl]; 1108 PetscInt clval; 1109 1110 if ((clp < pStart[d]) || (clp >= pEnd[d])) continue; 1111 PetscCall(DMLabelGetValue(label, clp, &clval)); 1112 if (clval == -1) { 1113 const PetscInt *cone; 1114 PetscInt coneSize, c; 1115 1116 /* If a cone point touches the fault, then this point touches the fault */ 1117 PetscCall(DMPlexGetCone(dm, clp, &cone)); 1118 PetscCall(DMPlexGetConeSize(dm, clp, &coneSize)); 1119 for (c = 0; c < coneSize; ++c) { 1120 PetscInt cpval; 1121 1122 PetscCall(DMLabelGetValue(label, cone[c], &cpval)); 1123 if (cpval != -1) { 1124 PetscInt dep; 1125 1126 PetscCall(DMPlexGetPointDepth(dm, clp, &dep)); 1127 clval = cval < 0 ? -(shift + dep) : shift + dep; 1128 PetscCall(DMLabelSetValue(label, clp, clval)); 1129 break; 1130 } 1131 } 1132 } 1133 /* Mark neighbor cells through marked faces (these cells must also touch the fault) */ 1134 if (d == dim - 1 && clval != -1) { 1135 const PetscInt *support; 1136 PetscInt supportSize, s, nval; 1137 1138 PetscCall(DMPlexGetSupport(dm, clp, &support)); 1139 PetscCall(DMPlexGetSupportSize(dm, clp, &supportSize)); 1140 for (s = 0; s < supportSize; ++s) { 1141 PetscCall(DMLabelGetValue(label, support[s], &nval)); 1142 if (nval == -1) { 1143 PetscCall(DMLabelSetValue(label, support[s], clval < 0 ? clval - 1 : clval + 1)); 1144 PetscCall(DMPlexPointQueueEnqueue(queue, support[s])); 1145 } 1146 } 1147 } 1148 } 1149 } 1150 PetscCall(DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure)); 1151 } 1152 PetscCall(PetscFree2(pStart, pEnd)); 1153 PetscFunctionReturn(PETSC_SUCCESS); 1154 } 1155 1156 typedef struct { 1157 DM dm; 1158 DMPlexPointQueue queue; 1159 } PointDivision; 1160 1161 static PetscErrorCode divideCell(DMLabel label, PetscInt p, PetscInt val, void *ctx) 1162 { 1163 PointDivision *div = (PointDivision *)ctx; 1164 PetscInt cval = val < 0 ? val - 1 : val + 1; 1165 const PetscInt *support; 1166 PetscInt supportSize, s; 1167 1168 PetscFunctionBegin; 1169 PetscCall(DMPlexGetSupport(div->dm, p, &support)); 1170 PetscCall(DMPlexGetSupportSize(div->dm, p, &supportSize)); 1171 for (s = 0; s < supportSize; ++s) { 1172 PetscCall(DMLabelSetValue(label, support[s], cval)); 1173 PetscCall(DMPlexPointQueueEnqueue(div->queue, support[s])); 1174 } 1175 PetscFunctionReturn(PETSC_SUCCESS); 1176 } 1177 1178 /* Mark cells by label propagation */ 1179 static PetscErrorCode DMPlexLabelFaultHalo(DM dm, DMLabel faultLabel) 1180 { 1181 DMPlexPointQueue queue = NULL; 1182 PointDivision div; 1183 PetscSF pointSF; 1184 IS pointIS; 1185 const PetscInt *points; 1186 PetscBool empty; 1187 PetscInt dim, shift = 100, n, i; 1188 1189 PetscFunctionBegin; 1190 PetscCall(DMGetDimension(dm, &dim)); 1191 PetscCall(DMPlexPointQueueCreate(1024, &queue)); 1192 div.dm = dm; 1193 div.queue = queue; 1194 /* Enqueue cells on fault */ 1195 PetscCall(DMLabelGetStratumIS(faultLabel, shift + dim, &pointIS)); 1196 if (pointIS) { 1197 PetscCall(ISGetLocalSize(pointIS, &n)); 1198 PetscCall(ISGetIndices(pointIS, &points)); 1199 for (i = 0; i < n; ++i) PetscCall(DMPlexPointQueueEnqueue(queue, points[i])); 1200 PetscCall(ISRestoreIndices(pointIS, &points)); 1201 PetscCall(ISDestroy(&pointIS)); 1202 } 1203 PetscCall(DMLabelGetStratumIS(faultLabel, -(shift + dim), &pointIS)); 1204 if (pointIS) { 1205 PetscCall(ISGetLocalSize(pointIS, &n)); 1206 PetscCall(ISGetIndices(pointIS, &points)); 1207 for (i = 0; i < n; ++i) PetscCall(DMPlexPointQueueEnqueue(queue, points[i])); 1208 PetscCall(ISRestoreIndices(pointIS, &points)); 1209 PetscCall(ISDestroy(&pointIS)); 1210 } 1211 1212 PetscCall(DMGetPointSF(dm, &pointSF)); 1213 PetscCall(DMLabelPropagateBegin(faultLabel, pointSF)); 1214 /* While edge queue is not empty: */ 1215 PetscCall(DMPlexPointQueueEmptyCollective((PetscObject)dm, queue, &empty)); 1216 while (!empty) { 1217 PetscCall(DivideCells_Private(dm, faultLabel, queue)); 1218 PetscCall(DMLabelPropagatePush(faultLabel, pointSF, divideCell, &div)); 1219 PetscCall(DMPlexPointQueueEmptyCollective((PetscObject)dm, queue, &empty)); 1220 } 1221 PetscCall(DMLabelPropagateEnd(faultLabel, pointSF)); 1222 PetscCall(DMPlexPointQueueDestroy(&queue)); 1223 PetscFunctionReturn(PETSC_SUCCESS); 1224 } 1225 1226 /* 1227 We are adding three kinds of points here: 1228 Replicated: Copies of points which exist in the mesh, such as vertices identified across a fault 1229 Non-replicated: Points which exist on the fault, but are not replicated 1230 Ghost: These are shared fault faces which are not owned by this process. These do not produce hybrid cells and do not replicate 1231 Hybrid: Entirely new points, such as cohesive cells 1232 1233 When creating subsequent cohesive cells, we shift the old hybrid cells to the end of the numbering at 1234 each depth so that the new split/hybrid points can be inserted as a block. 1235 */ 1236 static PetscErrorCode DMPlexConstructCohesiveCells_Internal(DM dm, DMLabel label, DMLabel splitLabel, DM sdm) 1237 { 1238 MPI_Comm comm; 1239 IS valueIS; 1240 PetscInt numSP = 0; /* The number of depths for which we have replicated points */ 1241 const PetscInt *values; /* List of depths for which we have replicated points */ 1242 IS *splitIS; 1243 IS *unsplitIS; 1244 IS ghostIS; 1245 PetscInt *numSplitPoints; /* The number of replicated points at each depth */ 1246 PetscInt *numUnsplitPoints; /* The number of non-replicated points at each depth which still give rise to hybrid points */ 1247 PetscInt *numHybridPoints; /* The number of new hybrid points at each depth */ 1248 PetscInt *numHybridPointsOld; /* The number of existing hybrid points at each depth */ 1249 PetscInt numGhostPoints; /* The number of unowned, shared fault faces */ 1250 const PetscInt **splitPoints; /* Replicated points for each depth */ 1251 const PetscInt **unsplitPoints; /* Non-replicated points for each depth */ 1252 const PetscInt *ghostPoints; /* Ghost fault faces */ 1253 PetscSection coordSection; 1254 Vec coordinates; 1255 PetscScalar *coords; 1256 PetscInt *depthMax; /* The first hybrid point at each depth in the original mesh */ 1257 PetscInt *depthEnd; /* The point limit at each depth in the original mesh */ 1258 PetscInt *depthShift; /* Number of replicated+hybrid points at each depth */ 1259 PetscInt *pMaxNew; /* The first replicated point at each depth in the new mesh, hybrids come after this */ 1260 PetscInt *coneNew, *coneONew, *supportNew; 1261 PetscInt shift = 100, shift2 = 200, depth = 0, dep, dim, d, sp, maxConeSize, maxSupportSize, maxConeSizeNew, maxSupportSizeNew, numLabels, vStart, vEnd, pEnd, p, v; 1262 1263 PetscFunctionBegin; 1264 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 1265 PetscCall(DMGetDimension(dm, &dim)); 1266 PetscCall(DMPlexGetDepth(dm, &depth)); 1267 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1268 /* We do not want this label automatically computed, instead we compute it here */ 1269 PetscCall(DMCreateLabel(sdm, "celltype")); 1270 /* Count split points and add cohesive cells */ 1271 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 1272 PetscCall(PetscMalloc5(depth + 1, &depthMax, depth + 1, &depthEnd, 2 * (depth + 1), &depthShift, depth + 1, &pMaxNew, depth + 1, &numHybridPointsOld)); 1273 PetscCall(PetscMalloc7(depth + 1, &splitIS, depth + 1, &unsplitIS, depth + 1, &numSplitPoints, depth + 1, &numUnsplitPoints, depth + 1, &numHybridPoints, depth + 1, &splitPoints, depth + 1, &unsplitPoints)); 1274 for (d = 0; d <= depth; ++d) { 1275 PetscCall(DMPlexGetDepthStratum(dm, d, NULL, &pMaxNew[d])); 1276 PetscCall(DMPlexGetTensorPrismBounds_Internal(dm, d, &depthMax[d], NULL)); 1277 depthEnd[d] = pMaxNew[d]; 1278 depthMax[d] = depthMax[d] < 0 ? depthEnd[d] : depthMax[d]; 1279 numSplitPoints[d] = 0; 1280 numUnsplitPoints[d] = 0; 1281 numHybridPoints[d] = 0; 1282 numHybridPointsOld[d] = depthMax[d] < 0 ? 0 : depthEnd[d] - depthMax[d]; 1283 splitPoints[d] = NULL; 1284 unsplitPoints[d] = NULL; 1285 splitIS[d] = NULL; 1286 unsplitIS[d] = NULL; 1287 /* we are shifting the existing hybrid points with the stratum behind them, so 1288 * the split comes at the end of the normal points, i.e., at depthMax[d] */ 1289 depthShift[2 * d] = depthMax[d]; 1290 depthShift[2 * d + 1] = 0; 1291 } 1292 numGhostPoints = 0; 1293 ghostPoints = NULL; 1294 if (label) { 1295 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1296 PetscCall(ISGetLocalSize(valueIS, &numSP)); 1297 PetscCall(ISGetIndices(valueIS, &values)); 1298 } 1299 for (sp = 0; sp < numSP; ++sp) { 1300 const PetscInt dep = values[sp]; 1301 1302 if ((dep < 0) || (dep > depth)) continue; 1303 PetscCall(DMLabelGetStratumIS(label, dep, &splitIS[dep])); 1304 if (splitIS[dep]) { 1305 PetscCall(ISGetLocalSize(splitIS[dep], &numSplitPoints[dep])); 1306 PetscCall(ISGetIndices(splitIS[dep], &splitPoints[dep])); 1307 } 1308 PetscCall(DMLabelGetStratumIS(label, shift2 + dep, &unsplitIS[dep])); 1309 if (unsplitIS[dep]) { 1310 PetscCall(ISGetLocalSize(unsplitIS[dep], &numUnsplitPoints[dep])); 1311 PetscCall(ISGetIndices(unsplitIS[dep], &unsplitPoints[dep])); 1312 } 1313 } 1314 PetscCall(DMLabelGetStratumIS(label, shift2 + dim - 1, &ghostIS)); 1315 if (ghostIS) { 1316 PetscCall(ISGetLocalSize(ghostIS, &numGhostPoints)); 1317 PetscCall(ISGetIndices(ghostIS, &ghostPoints)); 1318 } 1319 /* Calculate number of hybrid points */ 1320 for (d = 1; d <= depth; ++d) numHybridPoints[d] = numSplitPoints[d - 1] + numUnsplitPoints[d - 1]; /* There is a hybrid cell/face/edge for every split face/edge/vertex */ 1321 for (d = 0; d <= depth; ++d) depthShift[2 * d + 1] = numSplitPoints[d] + numHybridPoints[d]; 1322 PetscCall(DMPlexShiftPointSetUp_Internal(depth, depthShift)); 1323 /* the end of the points in this stratum that come before the new points: 1324 * shifting pMaxNew[d] gets the new start of the next stratum, then count back the old hybrid points and the newly 1325 * added points */ 1326 for (d = 0; d <= depth; ++d) pMaxNew[d] = DMPlexShiftPoint_Internal(pMaxNew[d], depth, depthShift) - (numHybridPointsOld[d] + numSplitPoints[d] + numHybridPoints[d]); 1327 PetscCall(DMPlexShiftSizes_Internal(dm, depthShift, sdm)); 1328 /* Step 3: Set cone/support sizes for new points */ 1329 for (dep = 0; dep <= depth; ++dep) { 1330 for (p = 0; p < numSplitPoints[dep]; ++p) { 1331 const PetscInt oldp = splitPoints[dep][p]; 1332 const PetscInt newp = DMPlexShiftPoint_Internal(oldp, depth, depthShift) /*oldp + depthOffset[dep]*/; 1333 const PetscInt splitp = p + pMaxNew[dep]; 1334 const PetscInt *support; 1335 DMPolytopeType ct; 1336 PetscInt coneSize, supportSize, qf, qn, qp, e; 1337 1338 PetscCall(DMPlexGetConeSize(dm, oldp, &coneSize)); 1339 PetscCall(DMPlexSetConeSize(sdm, splitp, coneSize)); 1340 PetscCall(DMPlexGetSupportSize(dm, oldp, &supportSize)); 1341 PetscCall(DMPlexSetSupportSize(sdm, splitp, supportSize)); 1342 PetscCall(DMPlexGetCellType(dm, oldp, &ct)); 1343 PetscCall(DMPlexSetCellType(sdm, splitp, ct)); 1344 if (dep == depth - 1) { 1345 const PetscInt hybcell = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1]; 1346 1347 /* Add cohesive cells, they are prisms */ 1348 PetscCall(DMPlexSetConeSize(sdm, hybcell, 2 + coneSize)); 1349 switch (coneSize) { 1350 case 2: 1351 PetscCall(DMPlexSetCellType(sdm, hybcell, DM_POLYTOPE_SEG_PRISM_TENSOR)); 1352 break; 1353 case 3: 1354 PetscCall(DMPlexSetCellType(sdm, hybcell, DM_POLYTOPE_TRI_PRISM_TENSOR)); 1355 break; 1356 case 4: 1357 PetscCall(DMPlexSetCellType(sdm, hybcell, DM_POLYTOPE_QUAD_PRISM_TENSOR)); 1358 break; 1359 } 1360 /* Shared fault faces with only one support cell now have two with the cohesive cell */ 1361 /* TODO Check thaat oldp has rootdegree == 1 */ 1362 if (supportSize == 1) { 1363 const PetscInt *support; 1364 PetscInt val; 1365 1366 PetscCall(DMPlexGetSupport(dm, oldp, &support)); 1367 PetscCall(DMLabelGetValue(label, support[0], &val)); 1368 if (val < 0) PetscCall(DMPlexSetSupportSize(sdm, splitp, 2)); 1369 else PetscCall(DMPlexSetSupportSize(sdm, newp, 2)); 1370 } 1371 } else if (dep == 0) { 1372 const PetscInt hybedge = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1]; 1373 1374 PetscCall(DMPlexGetSupport(dm, oldp, &support)); 1375 for (e = 0, qn = 0, qp = 0, qf = 0; e < supportSize; ++e) { 1376 PetscInt val; 1377 1378 PetscCall(DMLabelGetValue(label, support[e], &val)); 1379 if (val == 1) ++qf; 1380 if ((val == 1) || (val == (shift + 1))) ++qn; 1381 if ((val == 1) || (val == -(shift + 1))) ++qp; 1382 } 1383 /* Split old vertex: Edges into original vertex and new cohesive edge */ 1384 PetscCall(DMPlexSetSupportSize(sdm, newp, qn + 1)); 1385 /* Split new vertex: Edges into split vertex and new cohesive edge */ 1386 PetscCall(DMPlexSetSupportSize(sdm, splitp, qp + 1)); 1387 /* Add hybrid edge */ 1388 PetscCall(DMPlexSetConeSize(sdm, hybedge, 2)); 1389 PetscCall(DMPlexSetSupportSize(sdm, hybedge, qf)); 1390 PetscCall(DMPlexSetCellType(sdm, hybedge, DM_POLYTOPE_POINT_PRISM_TENSOR)); 1391 } else if (dep == dim - 2) { 1392 const PetscInt hybface = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1]; 1393 1394 PetscCall(DMPlexGetSupport(dm, oldp, &support)); 1395 for (e = 0, qn = 0, qp = 0, qf = 0; e < supportSize; ++e) { 1396 PetscInt val; 1397 1398 PetscCall(DMLabelGetValue(label, support[e], &val)); 1399 if (val == dim - 1) ++qf; 1400 if ((val == dim - 1) || (val == (shift + dim - 1))) ++qn; 1401 if ((val == dim - 1) || (val == -(shift + dim - 1))) ++qp; 1402 } 1403 /* Split old edge: Faces into original edge and cohesive face (positive side?) */ 1404 PetscCall(DMPlexSetSupportSize(sdm, newp, qn + 1)); 1405 /* Split new edge: Faces into split edge and cohesive face (negative side?) */ 1406 PetscCall(DMPlexSetSupportSize(sdm, splitp, qp + 1)); 1407 /* Add hybrid face */ 1408 PetscCall(DMPlexSetConeSize(sdm, hybface, 4)); 1409 PetscCall(DMPlexSetSupportSize(sdm, hybface, qf)); 1410 PetscCall(DMPlexSetCellType(sdm, hybface, DM_POLYTOPE_SEG_PRISM_TENSOR)); 1411 } 1412 } 1413 } 1414 for (dep = 0; dep <= depth; ++dep) { 1415 for (p = 0; p < numUnsplitPoints[dep]; ++p) { 1416 const PetscInt oldp = unsplitPoints[dep][p]; 1417 const PetscInt newp = DMPlexShiftPoint_Internal(oldp, depth, depthShift) /*oldp + depthOffset[dep]*/; 1418 const PetscInt *support; 1419 PetscInt coneSize, supportSize, qf, e, s; 1420 1421 PetscCall(DMPlexGetConeSize(dm, oldp, &coneSize)); 1422 PetscCall(DMPlexGetSupportSize(dm, oldp, &supportSize)); 1423 PetscCall(DMPlexGetSupport(dm, oldp, &support)); 1424 if (dep == 0) { 1425 const PetscInt hybedge = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1] + numSplitPoints[dep]; 1426 1427 /* Unsplit vertex: Edges into original vertex, split edges, and new cohesive edge twice */ 1428 for (s = 0, qf = 0; s < supportSize; ++s, ++qf) { 1429 PetscCall(PetscFindInt(support[s], numSplitPoints[dep + 1], splitPoints[dep + 1], &e)); 1430 if (e >= 0) ++qf; 1431 } 1432 PetscCall(DMPlexSetSupportSize(sdm, newp, qf + 2)); 1433 /* Add hybrid edge */ 1434 PetscCall(DMPlexSetConeSize(sdm, hybedge, 2)); 1435 for (e = 0, qf = 0; e < supportSize; ++e) { 1436 PetscInt val; 1437 1438 PetscCall(DMLabelGetValue(label, support[e], &val)); 1439 /* Split and unsplit edges produce hybrid faces */ 1440 if (val == 1) ++qf; 1441 if (val == (shift2 + 1)) ++qf; 1442 } 1443 PetscCall(DMPlexSetSupportSize(sdm, hybedge, qf)); 1444 PetscCall(DMPlexSetCellType(sdm, hybedge, DM_POLYTOPE_POINT_PRISM_TENSOR)); 1445 } else if (dep == dim - 2) { 1446 const PetscInt hybface = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1] + numSplitPoints[dep]; 1447 PetscInt val; 1448 1449 for (e = 0, qf = 0; e < supportSize; ++e) { 1450 PetscCall(DMLabelGetValue(label, support[e], &val)); 1451 if (val == dim - 1) qf += 2; 1452 else ++qf; 1453 } 1454 /* Unsplit edge: Faces into original edge, split face, and cohesive face twice */ 1455 PetscCall(DMPlexSetSupportSize(sdm, newp, qf + 2)); 1456 /* Add hybrid face */ 1457 for (e = 0, qf = 0; e < supportSize; ++e) { 1458 PetscCall(DMLabelGetValue(label, support[e], &val)); 1459 if (val == dim - 1) ++qf; 1460 } 1461 PetscCall(DMPlexSetConeSize(sdm, hybface, 4)); 1462 PetscCall(DMPlexSetSupportSize(sdm, hybface, qf)); 1463 PetscCall(DMPlexSetCellType(sdm, hybface, DM_POLYTOPE_SEG_PRISM_TENSOR)); 1464 } 1465 } 1466 } 1467 /* Step 4: Setup split DM */ 1468 PetscCall(DMSetUp(sdm)); 1469 PetscCall(DMPlexShiftPoints_Internal(dm, depthShift, sdm)); 1470 PetscCall(DMPlexGetMaxSizes(sdm, &maxConeSizeNew, &maxSupportSizeNew)); 1471 PetscCall(PetscMalloc3(PetscMax(maxConeSize, maxConeSizeNew) * 3, &coneNew, PetscMax(maxConeSize, maxConeSizeNew) * 3, &coneONew, PetscMax(maxSupportSize, maxSupportSizeNew), &supportNew)); 1472 /* Step 6: Set cones and supports for new points */ 1473 for (dep = 0; dep <= depth; ++dep) { 1474 for (p = 0; p < numSplitPoints[dep]; ++p) { 1475 const PetscInt oldp = splitPoints[dep][p]; 1476 const PetscInt newp = DMPlexShiftPoint_Internal(oldp, depth, depthShift) /*oldp + depthOffset[dep]*/; 1477 const PetscInt splitp = p + pMaxNew[dep]; 1478 const PetscInt *cone, *support, *ornt; 1479 DMPolytopeType ct; 1480 PetscInt coneSize, supportSize, q, qf, qn, qp, v, e, s; 1481 1482 PetscCall(DMPlexGetCellType(dm, oldp, &ct)); 1483 PetscCall(DMPlexGetConeSize(dm, oldp, &coneSize)); 1484 PetscCall(DMPlexGetCone(dm, oldp, &cone)); 1485 PetscCall(DMPlexGetConeOrientation(dm, oldp, &ornt)); 1486 PetscCall(DMPlexGetSupportSize(dm, oldp, &supportSize)); 1487 PetscCall(DMPlexGetSupport(dm, oldp, &support)); 1488 if (dep == depth - 1) { 1489 PetscBool hasUnsplit = PETSC_FALSE; 1490 const PetscInt hybcell = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1]; 1491 const PetscInt *supportF; 1492 1493 coneONew[0] = coneONew[1] = -1000; 1494 /* Split face: copy in old face to new face to start */ 1495 PetscCall(DMPlexGetSupport(sdm, newp, &supportF)); 1496 PetscCall(DMPlexSetSupport(sdm, splitp, supportF)); 1497 /* Split old face: old vertices/edges in cone so no change */ 1498 /* Split new face: new vertices/edges in cone */ 1499 for (q = 0; q < coneSize; ++q) { 1500 PetscCall(PetscFindInt(cone[q], numSplitPoints[dep - 1], splitPoints[dep - 1], &v)); 1501 if (v < 0) { 1502 PetscCall(PetscFindInt(cone[q], numUnsplitPoints[dep - 1], unsplitPoints[dep - 1], &v)); 1503 PetscCheck(v >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate point %" PetscInt_FMT " in split or unsplit points of depth %" PetscInt_FMT, cone[q], dep - 1); 1504 coneNew[2 + q] = DMPlexShiftPoint_Internal(cone[q], depth, depthShift) /*cone[q] + depthOffset[dep-1]*/; 1505 hasUnsplit = PETSC_TRUE; 1506 } else { 1507 coneNew[2 + q] = v + pMaxNew[dep - 1]; 1508 if (dep > 1) { 1509 const PetscInt *econe; 1510 PetscInt econeSize, r, vs, vu; 1511 1512 PetscCall(DMPlexGetConeSize(dm, cone[q], &econeSize)); 1513 PetscCall(DMPlexGetCone(dm, cone[q], &econe)); 1514 for (r = 0; r < econeSize; ++r) { 1515 PetscCall(PetscFindInt(econe[r], numSplitPoints[dep - 2], splitPoints[dep - 2], &vs)); 1516 PetscCall(PetscFindInt(econe[r], numUnsplitPoints[dep - 2], unsplitPoints[dep - 2], &vu)); 1517 if (vs >= 0) continue; 1518 PetscCheck(vu >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate point %" PetscInt_FMT " in split or unsplit points of depth %" PetscInt_FMT, econe[r], dep - 2); 1519 hasUnsplit = PETSC_TRUE; 1520 } 1521 } 1522 } 1523 } 1524 PetscCall(DMPlexSetCone(sdm, splitp, &coneNew[2])); 1525 PetscCall(DMPlexSetConeOrientation(sdm, splitp, ornt)); 1526 /* Face support */ 1527 PetscInt vals[2]; 1528 1529 PetscCall(DMLabelGetValue(label, support[0], &vals[0])); 1530 if (supportSize > 1) PetscCall(DMLabelGetValue(label, support[1], &vals[1])); 1531 else vals[1] = -vals[0]; 1532 PetscCheck(vals[0] * vals[1] < 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid support labels %" PetscInt_FMT " %" PetscInt_FMT, vals[0], vals[1]); 1533 1534 for (s = 0; s < 2; ++s) { 1535 if (s >= supportSize) { 1536 if (vals[s] < 0) { 1537 /* Ghost old face: Replace negative side cell with cohesive cell */ 1538 PetscCall(DMPlexInsertSupport(sdm, newp, s, hybcell)); 1539 } else { 1540 /* Ghost new face: Replace positive side cell with cohesive cell */ 1541 PetscCall(DMPlexInsertSupport(sdm, splitp, s, hybcell)); 1542 } 1543 } else { 1544 if (vals[s] < 0) { 1545 /* Split old face: Replace negative side cell with cohesive cell */ 1546 PetscCall(DMPlexInsertSupport(sdm, newp, s, hybcell)); 1547 } else { 1548 /* Split new face: Replace positive side cell with cohesive cell */ 1549 PetscCall(DMPlexInsertSupport(sdm, splitp, s, hybcell)); 1550 } 1551 } 1552 } 1553 /* Get orientation for cohesive face using the positive side cell */ 1554 { 1555 const PetscInt *ncone, *nconeO; 1556 PetscInt nconeSize, nc, ocell; 1557 PetscBool flip = PETSC_FALSE; 1558 1559 if (supportSize > 1) { 1560 ocell = vals[0] < 0 ? support[1] : support[0]; 1561 } else { 1562 ocell = support[0]; 1563 flip = vals[0] < 0 ? PETSC_TRUE : PETSC_FALSE; 1564 } 1565 PetscCall(DMPlexGetConeSize(dm, ocell, &nconeSize)); 1566 PetscCall(DMPlexGetCone(dm, ocell, &ncone)); 1567 PetscCall(DMPlexGetConeOrientation(dm, ocell, &nconeO)); 1568 for (nc = 0; nc < nconeSize; ++nc) { 1569 if (ncone[nc] == oldp) { 1570 coneONew[0] = flip ? -(nconeO[nc] + 1) : nconeO[nc]; 1571 break; 1572 } 1573 } 1574 PetscCheck(nc < nconeSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate face %" PetscInt_FMT " in neighboring cell %" PetscInt_FMT, oldp, ocell); 1575 } 1576 /* Cohesive cell: Old and new split face, then new cohesive faces */ 1577 { 1578 const PetscInt No = DMPolytopeTypeGetNumArrangements(ct) / 2; 1579 PetscCheck(coneONew[0] >= -No && coneONew[0] < No, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid %s orientation %" PetscInt_FMT, DMPolytopeTypes[ct], coneONew[0]); 1580 } 1581 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, coneONew[0]); 1582 1583 coneNew[0] = newp; /* Extracted negative side orientation above */ 1584 coneNew[1] = splitp; 1585 coneONew[1] = coneONew[0]; 1586 for (q = 0; q < coneSize; ++q) { 1587 /* Hybrid faces must follow order from oriented end face */ 1588 const PetscInt qa = arr[q * 2 + 0]; 1589 const PetscInt qo = arr[q * 2 + 1]; 1590 DMPolytopeType ft = dep == 2 ? DM_POLYTOPE_SEGMENT : DM_POLYTOPE_POINT; 1591 1592 PetscCall(PetscFindInt(cone[qa], numSplitPoints[dep - 1], splitPoints[dep - 1], &v)); 1593 if (v < 0) { 1594 PetscCall(PetscFindInt(cone[qa], numUnsplitPoints[dep - 1], unsplitPoints[dep - 1], &v)); 1595 coneNew[2 + q] = v + pMaxNew[dep] + numSplitPoints[dep] + numSplitPoints[dep - 1]; 1596 } else { 1597 coneNew[2 + q] = v + pMaxNew[dep] + numSplitPoints[dep]; 1598 } 1599 coneONew[2 + q] = DMPolytopeTypeComposeOrientation(ft, qo, ornt[qa]); 1600 } 1601 PetscCall(DMPlexSetCone(sdm, hybcell, coneNew)); 1602 PetscCall(DMPlexSetConeOrientation(sdm, hybcell, coneONew)); 1603 /* Label the hybrid cells on the boundary of the split */ 1604 if (hasUnsplit) PetscCall(DMLabelSetValue(label, -hybcell, dim)); 1605 } else if (dep == 0) { 1606 const PetscInt hybedge = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1]; 1607 1608 /* Split old vertex: Edges in old split faces and new cohesive edge */ 1609 for (e = 0, qn = 0; e < supportSize; ++e) { 1610 PetscInt val; 1611 1612 PetscCall(DMLabelGetValue(label, support[e], &val)); 1613 if ((val == 1) || (val == (shift + 1))) supportNew[qn++] = DMPlexShiftPoint_Internal(support[e], depth, depthShift) /*support[e] + depthOffset[dep+1]*/; 1614 } 1615 supportNew[qn] = hybedge; 1616 PetscCall(DMPlexSetSupport(sdm, newp, supportNew)); 1617 /* Split new vertex: Edges in new split faces and new cohesive edge */ 1618 for (e = 0, qp = 0; e < supportSize; ++e) { 1619 PetscInt val, edge; 1620 1621 PetscCall(DMLabelGetValue(label, support[e], &val)); 1622 if (val == 1) { 1623 PetscCall(PetscFindInt(support[e], numSplitPoints[dep + 1], splitPoints[dep + 1], &edge)); 1624 PetscCheck(edge >= 0, comm, PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " is not a split edge", support[e]); 1625 supportNew[qp++] = edge + pMaxNew[dep + 1]; 1626 } else if (val == -(shift + 1)) { 1627 supportNew[qp++] = DMPlexShiftPoint_Internal(support[e], depth, depthShift) /*support[e] + depthOffset[dep+1]*/; 1628 } 1629 } 1630 supportNew[qp] = hybedge; 1631 PetscCall(DMPlexSetSupport(sdm, splitp, supportNew)); 1632 /* Hybrid edge: Old and new split vertex */ 1633 coneNew[0] = newp; 1634 coneNew[1] = splitp; 1635 PetscCall(DMPlexSetCone(sdm, hybedge, coneNew)); 1636 for (e = 0, qf = 0; e < supportSize; ++e) { 1637 PetscInt val, edge; 1638 1639 PetscCall(DMLabelGetValue(label, support[e], &val)); 1640 if (val == 1) { 1641 PetscCall(PetscFindInt(support[e], numSplitPoints[dep + 1], splitPoints[dep + 1], &edge)); 1642 PetscCheck(edge >= 0, comm, PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " is not a split edge", support[e]); 1643 supportNew[qf++] = edge + pMaxNew[dep + 2] + numSplitPoints[dep + 2]; 1644 } 1645 } 1646 PetscCall(DMPlexSetSupport(sdm, hybedge, supportNew)); 1647 } else if (dep == dim - 2) { 1648 const PetscInt hybface = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1]; 1649 1650 /* Split old edge: old vertices in cone so no change */ 1651 /* Split new edge: new vertices in cone */ 1652 for (q = 0; q < coneSize; ++q) { 1653 PetscCall(PetscFindInt(cone[q], numSplitPoints[dep - 1], splitPoints[dep - 1], &v)); 1654 if (v < 0) { 1655 PetscCall(PetscFindInt(cone[q], numUnsplitPoints[dep - 1], unsplitPoints[dep - 1], &v)); 1656 PetscCheck(v >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate point %" PetscInt_FMT " in split or unsplit points of depth %" PetscInt_FMT, cone[q], dep - 1); 1657 coneNew[q] = DMPlexShiftPoint_Internal(cone[q], depth, depthShift) /*cone[q] + depthOffset[dep-1]*/; 1658 } else { 1659 coneNew[q] = v + pMaxNew[dep - 1]; 1660 } 1661 } 1662 PetscCall(DMPlexSetCone(sdm, splitp, coneNew)); 1663 /* Split old edge: Faces in positive side cells and old split faces */ 1664 for (e = 0, q = 0; e < supportSize; ++e) { 1665 PetscInt val; 1666 1667 PetscCall(DMLabelGetValue(label, support[e], &val)); 1668 if (val == dim - 1) { 1669 supportNew[q++] = DMPlexShiftPoint_Internal(support[e], depth, depthShift) /*support[e] + depthOffset[dep+1]*/; 1670 } else if (val == (shift + dim - 1)) { 1671 supportNew[q++] = DMPlexShiftPoint_Internal(support[e], depth, depthShift) /*support[e] + depthOffset[dep+1]*/; 1672 } 1673 } 1674 supportNew[q++] = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1]; 1675 PetscCall(DMPlexSetSupport(sdm, newp, supportNew)); 1676 /* Split new edge: Faces in negative side cells and new split faces */ 1677 for (e = 0, q = 0; e < supportSize; ++e) { 1678 PetscInt val, face; 1679 1680 PetscCall(DMLabelGetValue(label, support[e], &val)); 1681 if (val == dim - 1) { 1682 PetscCall(PetscFindInt(support[e], numSplitPoints[dep + 1], splitPoints[dep + 1], &face)); 1683 PetscCheck(face >= 0, comm, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " is not a split face", support[e]); 1684 supportNew[q++] = face + pMaxNew[dep + 1]; 1685 } else if (val == -(shift + dim - 1)) { 1686 supportNew[q++] = DMPlexShiftPoint_Internal(support[e], depth, depthShift) /*support[e] + depthOffset[dep+1]*/; 1687 } 1688 } 1689 supportNew[q++] = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1]; 1690 PetscCall(DMPlexSetSupport(sdm, splitp, supportNew)); 1691 /* Hybrid face */ 1692 coneNew[0] = newp; 1693 coneNew[1] = splitp; 1694 for (v = 0; v < coneSize; ++v) { 1695 PetscInt vertex; 1696 PetscCall(PetscFindInt(cone[v], numSplitPoints[dep - 1], splitPoints[dep - 1], &vertex)); 1697 if (vertex < 0) { 1698 PetscCall(PetscFindInt(cone[v], numUnsplitPoints[dep - 1], unsplitPoints[dep - 1], &vertex)); 1699 PetscCheck(vertex >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate point %" PetscInt_FMT " in split or unsplit points of depth %" PetscInt_FMT, cone[v], dep - 1); 1700 coneNew[2 + v] = vertex + pMaxNew[dep] + numSplitPoints[dep] + numSplitPoints[dep - 1]; 1701 } else { 1702 coneNew[2 + v] = vertex + pMaxNew[dep] + numSplitPoints[dep]; 1703 } 1704 } 1705 PetscCall(DMPlexSetCone(sdm, hybface, coneNew)); 1706 for (e = 0, qf = 0; e < supportSize; ++e) { 1707 PetscInt val, face; 1708 1709 PetscCall(DMLabelGetValue(label, support[e], &val)); 1710 if (val == dim - 1) { 1711 PetscCall(PetscFindInt(support[e], numSplitPoints[dep + 1], splitPoints[dep + 1], &face)); 1712 PetscCheck(face >= 0, comm, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " is not a split face", support[e]); 1713 supportNew[qf++] = face + pMaxNew[dep + 2] + numSplitPoints[dep + 2]; 1714 } 1715 } 1716 PetscCall(DMPlexSetSupport(sdm, hybface, supportNew)); 1717 } 1718 } 1719 } 1720 for (dep = 0; dep <= depth; ++dep) { 1721 for (p = 0; p < numUnsplitPoints[dep]; ++p) { 1722 const PetscInt oldp = unsplitPoints[dep][p]; 1723 const PetscInt newp = DMPlexShiftPoint_Internal(oldp, depth, depthShift) /*oldp + depthOffset[dep]*/; 1724 const PetscInt *cone, *support; 1725 PetscInt coneSize, supportSize, supportSizeNew, q, qf, e, f, s; 1726 1727 PetscCall(DMPlexGetConeSize(dm, oldp, &coneSize)); 1728 PetscCall(DMPlexGetCone(dm, oldp, &cone)); 1729 PetscCall(DMPlexGetSupportSize(dm, oldp, &supportSize)); 1730 PetscCall(DMPlexGetSupport(dm, oldp, &support)); 1731 if (dep == 0) { 1732 const PetscInt hybedge = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1] + numSplitPoints[dep]; 1733 1734 /* Unsplit vertex */ 1735 PetscCall(DMPlexGetSupportSize(sdm, newp, &supportSizeNew)); 1736 for (s = 0, q = 0; s < supportSize; ++s) { 1737 supportNew[q++] = DMPlexShiftPoint_Internal(support[s], depth, depthShift) /*support[s] + depthOffset[dep+1]*/; 1738 PetscCall(PetscFindInt(support[s], numSplitPoints[dep + 1], splitPoints[dep + 1], &e)); 1739 if (e >= 0) supportNew[q++] = e + pMaxNew[dep + 1]; 1740 } 1741 supportNew[q++] = hybedge; 1742 supportNew[q++] = hybedge; 1743 PetscCheck(q == supportSizeNew, comm, PETSC_ERR_ARG_WRONG, "Support size %" PetscInt_FMT " != %" PetscInt_FMT " for vertex %" PetscInt_FMT, q, supportSizeNew, newp); 1744 PetscCall(DMPlexSetSupport(sdm, newp, supportNew)); 1745 /* Hybrid edge */ 1746 coneNew[0] = newp; 1747 coneNew[1] = newp; 1748 PetscCall(DMPlexSetCone(sdm, hybedge, coneNew)); 1749 for (e = 0, qf = 0; e < supportSize; ++e) { 1750 PetscInt val, edge; 1751 1752 PetscCall(DMLabelGetValue(label, support[e], &val)); 1753 if (val == 1) { 1754 PetscCall(PetscFindInt(support[e], numSplitPoints[dep + 1], splitPoints[dep + 1], &edge)); 1755 PetscCheck(edge >= 0, comm, PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " is not a split edge", support[e]); 1756 supportNew[qf++] = edge + pMaxNew[dep + 2] + numSplitPoints[dep + 2]; 1757 } else if (val == (shift2 + 1)) { 1758 PetscCall(PetscFindInt(support[e], numUnsplitPoints[dep + 1], unsplitPoints[dep + 1], &edge)); 1759 PetscCheck(edge >= 0, comm, PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " is not a unsplit edge", support[e]); 1760 supportNew[qf++] = edge + pMaxNew[dep + 2] + numSplitPoints[dep + 2] + numSplitPoints[dep + 1]; 1761 } 1762 } 1763 PetscCall(DMPlexSetSupport(sdm, hybedge, supportNew)); 1764 } else if (dep == dim - 2) { 1765 const PetscInt hybface = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1] + numSplitPoints[dep]; 1766 1767 /* Unsplit edge: Faces into original edge, split face, and hybrid face twice */ 1768 for (f = 0, qf = 0; f < supportSize; ++f) { 1769 PetscInt val, face; 1770 1771 PetscCall(DMLabelGetValue(label, support[f], &val)); 1772 if (val == dim - 1) { 1773 PetscCall(PetscFindInt(support[f], numSplitPoints[dep + 1], splitPoints[dep + 1], &face)); 1774 PetscCheck(face >= 0, comm, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " is not a split face", support[f]); 1775 supportNew[qf++] = DMPlexShiftPoint_Internal(support[f], depth, depthShift) /*support[f] + depthOffset[dep+1]*/; 1776 supportNew[qf++] = face + pMaxNew[dep + 1]; 1777 } else { 1778 supportNew[qf++] = DMPlexShiftPoint_Internal(support[f], depth, depthShift) /*support[f] + depthOffset[dep+1]*/; 1779 } 1780 } 1781 supportNew[qf++] = hybface; 1782 supportNew[qf++] = hybface; 1783 PetscCall(DMPlexGetSupportSize(sdm, newp, &supportSizeNew)); 1784 PetscCheck(qf == supportSizeNew, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Support size for unsplit edge %" PetscInt_FMT " is %" PetscInt_FMT " != %" PetscInt_FMT, newp, qf, supportSizeNew); 1785 PetscCall(DMPlexSetSupport(sdm, newp, supportNew)); 1786 /* Add hybrid face */ 1787 coneNew[0] = newp; 1788 coneNew[1] = newp; 1789 PetscCall(PetscFindInt(cone[0], numUnsplitPoints[dep - 1], unsplitPoints[dep - 1], &v)); 1790 PetscCheck(v >= 0, comm, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is not an unsplit vertex", cone[0]); 1791 coneNew[2] = v + pMaxNew[dep] + numSplitPoints[dep] + numSplitPoints[dep - 1]; 1792 PetscCall(PetscFindInt(cone[1], numUnsplitPoints[dep - 1], unsplitPoints[dep - 1], &v)); 1793 PetscCheck(v >= 0, comm, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is not an unsplit vertex", cone[1]); 1794 coneNew[3] = v + pMaxNew[dep] + numSplitPoints[dep] + numSplitPoints[dep - 1]; 1795 PetscCall(DMPlexSetCone(sdm, hybface, coneNew)); 1796 for (f = 0, qf = 0; f < supportSize; ++f) { 1797 PetscInt val, face; 1798 1799 PetscCall(DMLabelGetValue(label, support[f], &val)); 1800 if (val == dim - 1) { 1801 PetscCall(PetscFindInt(support[f], numSplitPoints[dep + 1], splitPoints[dep + 1], &face)); 1802 supportNew[qf++] = face + pMaxNew[dep + 2] + numSplitPoints[dep + 2]; 1803 } 1804 } 1805 PetscCall(DMPlexGetSupportSize(sdm, hybface, &supportSizeNew)); 1806 PetscCheck(qf == supportSizeNew, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Support size for hybrid face %" PetscInt_FMT " is %" PetscInt_FMT " != %" PetscInt_FMT, hybface, qf, supportSizeNew); 1807 PetscCall(DMPlexSetSupport(sdm, hybface, supportNew)); 1808 } 1809 } 1810 } 1811 /* Step 6b: Replace split points in negative side cones */ 1812 for (sp = 0; sp < numSP; ++sp) { 1813 PetscInt dep = values[sp]; 1814 IS pIS; 1815 PetscInt numPoints; 1816 const PetscInt *points; 1817 1818 if (dep >= 0) continue; 1819 PetscCall(DMLabelGetStratumIS(label, dep, &pIS)); 1820 if (!pIS) continue; 1821 dep = -dep - shift; 1822 PetscCall(ISGetLocalSize(pIS, &numPoints)); 1823 PetscCall(ISGetIndices(pIS, &points)); 1824 for (p = 0; p < numPoints; ++p) { 1825 const PetscInt oldp = points[p]; 1826 const PetscInt newp = DMPlexShiftPoint_Internal(oldp, depth, depthShift) /*depthOffset[dep] + oldp*/; 1827 const PetscInt *cone; 1828 PetscInt coneSize, c; 1829 /* PetscBool replaced = PETSC_FALSE; */ 1830 1831 /* Negative edge: replace split vertex */ 1832 /* Negative cell: replace split face */ 1833 PetscCall(DMPlexGetConeSize(sdm, newp, &coneSize)); 1834 PetscCall(DMPlexGetCone(sdm, newp, &cone)); 1835 for (c = 0; c < coneSize; ++c) { 1836 const PetscInt coldp = DMPlexShiftPointInverse_Internal(cone[c], depth, depthShift); 1837 PetscInt csplitp, cp, val; 1838 1839 PetscCall(DMLabelGetValue(label, coldp, &val)); 1840 if (val == dep - 1) { 1841 PetscCall(PetscFindInt(coldp, numSplitPoints[dep - 1], splitPoints[dep - 1], &cp)); 1842 PetscCheck(cp >= 0, comm, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT " is not a split point of dimension %" PetscInt_FMT, oldp, dep - 1); 1843 csplitp = pMaxNew[dep - 1] + cp; 1844 PetscCall(DMPlexInsertCone(sdm, newp, c, csplitp)); 1845 /* replaced = PETSC_TRUE; */ 1846 } 1847 } 1848 /* Cells with only a vertex or edge on the submesh have no replacement */ 1849 /* PetscCheck(replaced,comm, PETSC_ERR_ARG_WRONG, "The cone of point %d does not contain split points", oldp); */ 1850 } 1851 PetscCall(ISRestoreIndices(pIS, &points)); 1852 PetscCall(ISDestroy(&pIS)); 1853 } 1854 PetscCall(DMPlexReorderCohesiveSupports(sdm)); 1855 /* Step 7: Coordinates */ 1856 PetscCall(DMPlexShiftCoordinates_Internal(dm, depthShift, sdm)); 1857 PetscCall(DMGetCoordinateSection(sdm, &coordSection)); 1858 PetscCall(DMGetCoordinatesLocal(sdm, &coordinates)); 1859 PetscCall(VecGetArray(coordinates, &coords)); 1860 for (v = 0; v < (numSplitPoints ? numSplitPoints[0] : 0); ++v) { 1861 const PetscInt newp = DMPlexShiftPoint_Internal(splitPoints[0][v], depth, depthShift) /*depthOffset[0] + splitPoints[0][v]*/; 1862 const PetscInt splitp = pMaxNew[0] + v; 1863 PetscInt dof, off, soff, d; 1864 1865 PetscCall(PetscSectionGetDof(coordSection, newp, &dof)); 1866 PetscCall(PetscSectionGetOffset(coordSection, newp, &off)); 1867 PetscCall(PetscSectionGetOffset(coordSection, splitp, &soff)); 1868 for (d = 0; d < dof; ++d) coords[soff + d] = coords[off + d]; 1869 } 1870 PetscCall(VecRestoreArray(coordinates, &coords)); 1871 /* Step 8: SF, if I can figure this out we can split the mesh in parallel */ 1872 PetscCall(DMPlexShiftSF_Internal(dm, depthShift, sdm)); 1873 /* TODO We need to associate the ghost points with the correct replica */ 1874 /* Step 9: Labels */ 1875 PetscCall(DMPlexShiftLabels_Internal(dm, depthShift, sdm)); 1876 PetscCall(DMPlexCreateVTKLabel_Internal(dm, PETSC_FALSE, sdm)); 1877 PetscCall(DMGetNumLabels(sdm, &numLabels)); 1878 for (dep = 0; dep <= depth; ++dep) { 1879 for (p = 0; p < numSplitPoints[dep]; ++p) { 1880 const PetscInt newp = DMPlexShiftPoint_Internal(splitPoints[dep][p], depth, depthShift) /*depthOffset[dep] + splitPoints[dep][p]*/; 1881 const PetscInt splitp = pMaxNew[dep] + p; 1882 PetscInt l; 1883 1884 if (splitLabel) { 1885 const PetscInt val = 100 + dep; 1886 1887 PetscCall(DMLabelSetValue(splitLabel, newp, val)); 1888 PetscCall(DMLabelSetValue(splitLabel, splitp, -val)); 1889 } 1890 for (l = 0; l < numLabels; ++l) { 1891 DMLabel mlabel; 1892 const char *lname; 1893 PetscInt val; 1894 PetscBool isDepth; 1895 1896 PetscCall(DMGetLabelName(sdm, l, &lname)); 1897 PetscCall(PetscStrcmp(lname, "depth", &isDepth)); 1898 if (isDepth) continue; 1899 PetscCall(DMGetLabel(sdm, lname, &mlabel)); 1900 PetscCall(DMLabelGetValue(mlabel, newp, &val)); 1901 if (val >= 0) PetscCall(DMLabelSetValue(mlabel, splitp, val)); 1902 } 1903 } 1904 } 1905 for (sp = 0; sp < numSP; ++sp) { 1906 const PetscInt dep = values[sp]; 1907 1908 if ((dep < 0) || (dep > depth)) continue; 1909 if (splitIS[dep]) PetscCall(ISRestoreIndices(splitIS[dep], &splitPoints[dep])); 1910 PetscCall(ISDestroy(&splitIS[dep])); 1911 if (unsplitIS[dep]) PetscCall(ISRestoreIndices(unsplitIS[dep], &unsplitPoints[dep])); 1912 PetscCall(ISDestroy(&unsplitIS[dep])); 1913 } 1914 if (ghostIS) PetscCall(ISRestoreIndices(ghostIS, &ghostPoints)); 1915 PetscCall(ISDestroy(&ghostIS)); 1916 if (label) { 1917 PetscCall(ISRestoreIndices(valueIS, &values)); 1918 PetscCall(ISDestroy(&valueIS)); 1919 } 1920 for (d = 0; d <= depth; ++d) { 1921 PetscCall(DMPlexGetDepthStratum(sdm, d, NULL, &pEnd)); 1922 pMaxNew[d] = pEnd - numHybridPoints[d] - numHybridPointsOld[d]; 1923 } 1924 PetscCall(PetscFree3(coneNew, coneONew, supportNew)); 1925 PetscCall(PetscFree5(depthMax, depthEnd, depthShift, pMaxNew, numHybridPointsOld)); 1926 PetscCall(PetscFree7(splitIS, unsplitIS, numSplitPoints, numUnsplitPoints, numHybridPoints, splitPoints, unsplitPoints)); 1927 PetscFunctionReturn(PETSC_SUCCESS); 1928 } 1929 1930 /*@C 1931 DMPlexConstructCohesiveCells - Construct cohesive cells which split the face along an internal interface 1932 1933 Collective 1934 1935 Input Parameters: 1936 + dm - The original `DM` 1937 - label - The `DMLabel` specifying the boundary faces (this could be auto-generated) 1938 1939 Output Parameters: 1940 + splitLabel - The `DMLabel` containing the split points, or `NULL` if no output is desired 1941 - dmSplit - The new `DM` 1942 1943 Level: developer 1944 1945 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMCreate()`, `DMPlexLabelCohesiveComplete()` 1946 @*/ 1947 PetscErrorCode DMPlexConstructCohesiveCells(DM dm, DMLabel label, DMLabel splitLabel, DM *dmSplit) 1948 { 1949 DM sdm; 1950 PetscInt dim; 1951 1952 PetscFunctionBegin; 1953 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1954 PetscAssertPointer(dmSplit, 4); 1955 PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &sdm)); 1956 PetscCall(DMSetType(sdm, DMPLEX)); 1957 PetscCall(DMGetDimension(dm, &dim)); 1958 PetscCall(DMSetDimension(sdm, dim)); 1959 switch (dim) { 1960 case 2: 1961 case 3: 1962 PetscCall(DMPlexConstructCohesiveCells_Internal(dm, label, splitLabel, sdm)); 1963 break; 1964 default: 1965 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct cohesive cells for dimension %" PetscInt_FMT, dim); 1966 } 1967 *dmSplit = sdm; 1968 PetscFunctionReturn(PETSC_SUCCESS); 1969 } 1970 1971 /* Returns the side of the surface for a given cell with a face on the surface */ 1972 static PetscErrorCode GetSurfaceSide_Static(DM dm, DM subdm, PetscInt numSubpoints, const PetscInt *subpoints, PetscInt cell, PetscInt face, PetscBool *pos) 1973 { 1974 const PetscInt *cone, *ornt; 1975 PetscInt dim, coneSize, c; 1976 1977 PetscFunctionBegin; 1978 *pos = PETSC_TRUE; 1979 PetscCall(DMGetDimension(dm, &dim)); 1980 PetscCall(DMPlexGetConeSize(dm, cell, &coneSize)); 1981 PetscCall(DMPlexGetCone(dm, cell, &cone)); 1982 PetscCall(DMPlexGetConeOrientation(dm, cell, &ornt)); 1983 for (c = 0; c < coneSize; ++c) { 1984 if (cone[c] == face) { 1985 PetscInt o = ornt[c]; 1986 1987 if (subdm) { 1988 const PetscInt *subcone, *subornt; 1989 PetscInt subpoint, subface, subconeSize, sc; 1990 1991 PetscCall(PetscFindInt(cell, numSubpoints, subpoints, &subpoint)); 1992 PetscCall(PetscFindInt(face, numSubpoints, subpoints, &subface)); 1993 PetscCall(DMPlexGetConeSize(subdm, subpoint, &subconeSize)); 1994 PetscCall(DMPlexGetCone(subdm, subpoint, &subcone)); 1995 PetscCall(DMPlexGetConeOrientation(subdm, subpoint, &subornt)); 1996 for (sc = 0; sc < subconeSize; ++sc) { 1997 if (subcone[sc] == subface) { 1998 o = subornt[0]; 1999 break; 2000 } 2001 } 2002 PetscCheck(sc < subconeSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find subpoint %" PetscInt_FMT " (%" PetscInt_FMT ") in cone for subpoint %" PetscInt_FMT " (%" PetscInt_FMT ")", subface, face, subpoint, cell); 2003 } 2004 if (o >= 0) *pos = PETSC_TRUE; 2005 else *pos = PETSC_FALSE; 2006 break; 2007 } 2008 } 2009 PetscCheck(c != coneSize, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " in split face %" PetscInt_FMT " support does not have it in the cone", cell, face); 2010 PetscFunctionReturn(PETSC_SUCCESS); 2011 } 2012 2013 static PetscErrorCode CheckFaultEdge_Private(DM dm, DMLabel label, PetscBool split) 2014 { 2015 IS facePosIS, faceNegIS, dimIS; 2016 const PetscInt *points; 2017 PetscInt *closure = NULL, *inclosure = NULL; 2018 PetscInt dim, numPoints, shift = 100, shift2 = 200, debug = 0; 2019 2020 PetscFunctionBegin; 2021 PetscCall(DMGetDimension(dm, &dim)); 2022 // If any faces touching the fault divide cells on either side, 2023 // either split them, or unsplit the connection 2024 PetscCall(DMLabelGetStratumIS(label, shift + dim - 1, &facePosIS)); 2025 PetscCall(DMLabelGetStratumIS(label, -(shift + dim - 1), &faceNegIS)); 2026 if (!facePosIS || !faceNegIS) { 2027 PetscCall(ISDestroy(&facePosIS)); 2028 PetscCall(ISDestroy(&faceNegIS)); 2029 PetscFunctionReturn(PETSC_SUCCESS); 2030 } 2031 PetscCall(ISExpand(facePosIS, faceNegIS, &dimIS)); 2032 PetscCall(ISDestroy(&facePosIS)); 2033 PetscCall(ISDestroy(&faceNegIS)); 2034 PetscCall(ISGetLocalSize(dimIS, &numPoints)); 2035 PetscCall(ISGetIndices(dimIS, &points)); 2036 for (PetscInt p = 0; p < numPoints; ++p) { 2037 const PetscInt point = points[p]; 2038 const PetscInt *support; 2039 PetscInt supportSize, valA, valB; 2040 2041 PetscCall(DMPlexGetSupportSize(dm, point, &supportSize)); 2042 if (supportSize != 2) continue; 2043 PetscCall(DMPlexGetSupport(dm, point, &support)); 2044 PetscCall(DMLabelGetValue(label, support[0], &valA)); 2045 PetscCall(DMLabelGetValue(label, support[1], &valB)); 2046 if ((valA == -1) || (valB == -1)) continue; 2047 if (valA * valB > 0) continue; 2048 // Check that this face is not incident on only unsplit faces, 2049 // meaning has at least one split face 2050 { 2051 PetscBool split = PETSC_FALSE; 2052 PetscInt Ncl, val; 2053 2054 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &Ncl, &closure)); 2055 for (PetscInt cl = 0; cl < Ncl * 2; cl += 2) { 2056 PetscCall(DMLabelGetValue(label, closure[cl], &val)); 2057 if (val >= 0 && val <= dim) { 2058 split = PETSC_TRUE; 2059 break; 2060 } 2061 } 2062 if (!split) continue; 2063 } 2064 if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, "Point %" PetscInt_FMT " is impinging (%" PetscInt_FMT ":%" PetscInt_FMT ", %" PetscInt_FMT ":%" PetscInt_FMT ")\n", point, support[0], valA, support[1], valB)); 2065 if (split) { 2066 // Split the face 2067 PetscCall(DMLabelGetValue(label, point, &valA)); 2068 PetscCall(DMLabelClearValue(label, point, valA)); 2069 PetscCall(DMLabelSetValue(label, point, dim - 1)); 2070 /* Label its closure: 2071 unmarked: label as unsplit 2072 incident: relabel as split 2073 split: do nothing */ 2074 { 2075 PetscInt closureSize, cl, dep; 2076 2077 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure)); 2078 for (cl = 0; cl < closureSize * 2; cl += 2) { 2079 PetscCall(DMLabelGetValue(label, closure[cl], &valA)); 2080 if (valA == -1) { /* Mark as unsplit */ 2081 PetscCall(DMPlexGetPointDepth(dm, closure[cl], &dep)); 2082 PetscCall(DMLabelSetValue(label, closure[cl], shift2 + dep)); 2083 } else if ((valA >= shift && valA < shift2) || (valA <= -shift && valA > -shift2)) { 2084 PetscCall(DMPlexGetPointDepth(dm, closure[cl], &dep)); 2085 PetscCall(DMLabelClearValue(label, closure[cl], valA)); 2086 PetscCall(DMLabelSetValue(label, closure[cl], dep)); 2087 } 2088 } 2089 } 2090 } else { 2091 // Unsplit the incident faces and their closures 2092 PetscInt Ncl, dep, val; 2093 2094 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &Ncl, &closure)); 2095 for (PetscInt cl = 0; cl < Ncl * 2; cl += 2) { 2096 PetscCall(DMLabelGetValue(label, closure[cl], &val)); 2097 if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, " Point %" PetscInt_FMT ":%" PetscInt_FMT "\n", closure[cl], val)); 2098 if (val >= 0 && val <= dim) { 2099 PetscInt Nincl, inval, indep; 2100 2101 if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, " Point %" PetscInt_FMT " is being unsplit\n", closure[cl])); 2102 PetscCall(DMPlexGetPointDepth(dm, closure[cl], &dep)); 2103 PetscCall(DMLabelClearValue(label, closure[cl], val)); 2104 PetscCall(DMLabelSetValue(label, closure[cl], shift2 + dep)); 2105 2106 PetscCall(DMPlexGetTransitiveClosure(dm, closure[cl], PETSC_TRUE, &Nincl, &inclosure)); 2107 for (PetscInt incl = 0; incl < Nincl * 2; incl += 2) { 2108 PetscCall(DMLabelGetValue(label, inclosure[cl], &inval)); 2109 if (inval >= 0 && inval <= dim) { 2110 if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, " Point %" PetscInt_FMT " is being unsplit\n", inclosure[incl])); 2111 PetscCall(DMPlexGetPointDepth(dm, inclosure[incl], &indep)); 2112 PetscCall(DMLabelClearValue(label, inclosure[incl], inval)); 2113 PetscCall(DMLabelSetValue(label, inclosure[incl], shift2 + indep)); 2114 } 2115 } 2116 } 2117 } 2118 } 2119 } 2120 PetscCall(DMPlexRestoreTransitiveClosure(dm, 0, PETSC_TRUE, NULL, &inclosure)); 2121 PetscCall(DMPlexRestoreTransitiveClosure(dm, 0, PETSC_TRUE, NULL, &closure)); 2122 PetscCall(ISRestoreIndices(dimIS, &points)); 2123 PetscCall(ISDestroy(&dimIS)); 2124 PetscFunctionReturn(PETSC_SUCCESS); 2125 } 2126 2127 /*@ 2128 DMPlexLabelCohesiveComplete - Starting with a label marking points on an internal surface, we add all other mesh pieces 2129 to complete the surface 2130 2131 Input Parameters: 2132 + dm - The `DM` 2133 . label - A `DMLabel` marking the surface 2134 . blabel - A `DMLabel` marking the vertices on the boundary which will not be duplicated, or `NULL` to find them automatically 2135 . bvalue - Value of `DMLabel` marking the vertices on the boundary 2136 . flip - Flag to flip the submesh normal and replace points on the other side 2137 . split - Split faces impinging on the surface, rather than clamping the surface boundary 2138 - subdm - The `DM` associated with the label, or `NULL` 2139 2140 Output Parameter: 2141 . label - A `DMLabel` marking all surface points 2142 2143 Level: developer 2144 2145 Note: 2146 The vertices in blabel are called "unsplit" in the terminology from hybrid cell creation. 2147 2148 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructCohesiveCells()`, `DMPlexLabelComplete()` 2149 @*/ 2150 PetscErrorCode DMPlexLabelCohesiveComplete(DM dm, DMLabel label, DMLabel blabel, PetscInt bvalue, PetscBool flip, PetscBool split, DM subdm) 2151 { 2152 DMLabel depthLabel; 2153 IS dimIS, subpointIS = NULL; 2154 const PetscInt *points, *subpoints; 2155 const PetscInt rev = flip ? -1 : 1; 2156 PetscInt shift = 100, shift2 = 200, shift3 = split ? 300 : 0, dim, depth, numPoints, numSubpoints, p, val; 2157 2158 PetscFunctionBegin; 2159 PetscCall(DMPlexGetDepth(dm, &depth)); 2160 PetscCall(DMGetDimension(dm, &dim)); 2161 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 2162 if (subdm) { 2163 PetscCall(DMPlexGetSubpointIS(subdm, &subpointIS)); 2164 if (subpointIS) { 2165 PetscCall(ISGetLocalSize(subpointIS, &numSubpoints)); 2166 PetscCall(ISGetIndices(subpointIS, &subpoints)); 2167 } 2168 } 2169 /* Mark cell on the fault, and its faces which touch the fault: cell orientation for face gives the side of the fault */ 2170 PetscCall(DMLabelGetStratumIS(label, dim - 1, &dimIS)); 2171 if (!dimIS) goto divide; 2172 PetscCall(ISGetLocalSize(dimIS, &numPoints)); 2173 PetscCall(ISGetIndices(dimIS, &points)); 2174 for (p = 0; p < numPoints; ++p) { /* Loop over fault faces */ 2175 const PetscInt *support; 2176 PetscInt supportSize, s; 2177 2178 PetscCall(DMPlexGetSupportSize(dm, points[p], &supportSize)); 2179 #if 0 2180 if (supportSize != 2) { 2181 const PetscInt *lp; 2182 PetscInt Nlp, pind; 2183 2184 /* Check that for a cell with a single support face, that face is in the SF */ 2185 /* THis check only works for the remote side. We would need root side information */ 2186 PetscCall(PetscSFGetGraph(dm->sf, NULL, &Nlp, &lp, NULL)); 2187 PetscCall(PetscFindInt(points[p], Nlp, lp, &pind)); 2188 PetscCheck(pind >= 0,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Split face %" PetscInt_FMT " has %" PetscInt_FMT " != 2 supports, and the face is not shared with another process", points[p], supportSize); 2189 } 2190 #endif 2191 PetscCall(DMPlexGetSupport(dm, points[p], &support)); 2192 for (s = 0; s < supportSize; ++s) { 2193 const PetscInt *cone; 2194 PetscInt coneSize, c; 2195 PetscBool pos; 2196 2197 PetscCall(GetSurfaceSide_Static(dm, subdm, numSubpoints, subpoints, support[s], points[p], &pos)); 2198 if (pos) PetscCall(DMLabelSetValue(label, support[s], rev * (shift + dim))); 2199 else PetscCall(DMLabelSetValue(label, support[s], -rev * (shift + dim))); 2200 if (rev < 0) pos = !pos ? PETSC_TRUE : PETSC_FALSE; 2201 /* Put faces touching the fault in the label */ 2202 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 2203 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 2204 for (c = 0; c < coneSize; ++c) { 2205 const PetscInt point = cone[c]; 2206 2207 PetscCall(DMLabelGetValue(label, point, &val)); 2208 if (val == -1) { 2209 PetscInt *closure = NULL; 2210 PetscInt closureSize, cl; 2211 2212 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure)); 2213 for (cl = 0; cl < closureSize * 2; cl += 2) { 2214 const PetscInt clp = closure[cl]; 2215 PetscInt bval = -1; 2216 2217 PetscCall(DMLabelGetValue(label, clp, &val)); 2218 if (blabel) PetscCall(DMLabelGetValue(blabel, clp, &bval)); 2219 if (val >= 0 && val < dim - 1 && bval < 0) { 2220 PetscCall(DMLabelSetValue(label, point, pos == PETSC_TRUE ? shift + dim - 1 : -(shift + dim - 1))); 2221 break; 2222 } 2223 } 2224 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure)); 2225 } 2226 } 2227 } 2228 } 2229 PetscCall(ISRestoreIndices(dimIS, &points)); 2230 PetscCall(ISDestroy(&dimIS)); 2231 /* Mark boundary points as unsplit */ 2232 if (blabel) { 2233 IS bdIS; 2234 2235 PetscCall(DMLabelGetStratumIS(blabel, bvalue, &bdIS)); 2236 PetscCall(ISGetLocalSize(bdIS, &numPoints)); 2237 PetscCall(ISGetIndices(bdIS, &points)); 2238 for (p = 0; p < numPoints; ++p) { 2239 const PetscInt point = points[p]; 2240 PetscInt val, bval; 2241 2242 PetscCall(DMLabelGetValue(blabel, point, &bval)); 2243 if (bval >= 0) { 2244 PetscCall(DMLabelGetValue(label, point, &val)); 2245 if ((val < 0) || (val > dim)) { 2246 /* This could be a point added from splitting a vertex on an adjacent fault, otherwise its just wrong */ 2247 PetscCall(DMLabelClearValue(blabel, point, bval)); 2248 } 2249 } 2250 } 2251 for (p = 0; p < numPoints; ++p) { 2252 const PetscInt point = points[p]; 2253 PetscInt val, bval; 2254 2255 PetscCall(DMLabelGetValue(blabel, point, &bval)); 2256 if (bval >= 0) { 2257 const PetscInt *cone, *support; 2258 PetscInt coneSize, supportSize, s, valA, valB, valE; 2259 2260 /* Mark as unsplit */ 2261 PetscCall(DMLabelGetValue(label, point, &val)); 2262 PetscCheck(val >= 0 && val <= dim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " has label value %" PetscInt_FMT ", should be part of the fault", point, val); 2263 PetscCall(DMLabelClearValue(label, point, val)); 2264 PetscCall(DMLabelSetValue(label, point, shift2 + val)); 2265 /* Check for cross-edge 2266 A cross-edge has endpoints which are both on the boundary of the surface, but the edge itself is not. */ 2267 if (val != 0) continue; 2268 PetscCall(DMPlexGetSupport(dm, point, &support)); 2269 PetscCall(DMPlexGetSupportSize(dm, point, &supportSize)); 2270 for (s = 0; s < supportSize; ++s) { 2271 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 2272 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 2273 PetscCheck(coneSize == 2, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Edge %" PetscInt_FMT " has %" PetscInt_FMT " vertices != 2", support[s], coneSize); 2274 PetscCall(DMLabelGetValue(blabel, cone[0], &valA)); 2275 PetscCall(DMLabelGetValue(blabel, cone[1], &valB)); 2276 PetscCall(DMLabelGetValue(blabel, support[s], &valE)); 2277 if (valE < 0 && valA >= 0 && valB >= 0 && cone[0] != cone[1]) PetscCall(DMLabelSetValue(blabel, support[s], 2)); 2278 } 2279 } 2280 } 2281 PetscCall(ISRestoreIndices(bdIS, &points)); 2282 PetscCall(ISDestroy(&bdIS)); 2283 } 2284 /* Mark ghost fault cells */ 2285 { 2286 PetscSF sf; 2287 const PetscInt *leaves; 2288 PetscInt Nl, l; 2289 2290 PetscCall(DMGetPointSF(dm, &sf)); 2291 PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &leaves, NULL)); 2292 PetscCall(DMLabelGetStratumIS(label, dim - 1, &dimIS)); 2293 if (!dimIS) goto divide; 2294 PetscCall(ISGetLocalSize(dimIS, &numPoints)); 2295 PetscCall(ISGetIndices(dimIS, &points)); 2296 if (Nl > 0) { 2297 for (p = 0; p < numPoints; ++p) { 2298 const PetscInt point = points[p]; 2299 PetscInt val; 2300 2301 PetscCall(PetscFindInt(point, Nl, leaves, &l)); 2302 if (l >= 0) { 2303 PetscInt *closure = NULL; 2304 PetscInt closureSize, cl; 2305 2306 PetscCall(DMLabelGetValue(label, point, &val)); 2307 PetscCheck((val == dim - 1) || (val == shift2 + dim - 1), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " has label value %" PetscInt_FMT ", should be a fault face", point, val); 2308 PetscCall(DMLabelClearValue(label, point, val)); 2309 PetscCall(DMLabelSetValue(label, point, shift3 + val)); 2310 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure)); 2311 for (cl = 2; cl < closureSize * 2; cl += 2) { 2312 const PetscInt clp = closure[cl]; 2313 2314 PetscCall(DMLabelGetValue(label, clp, &val)); 2315 PetscCheck(val != -1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " is missing from label, but is in the closure of a fault face", point); 2316 PetscCall(DMLabelClearValue(label, clp, val)); 2317 PetscCall(DMLabelSetValue(label, clp, shift3 + val)); 2318 } 2319 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure)); 2320 } 2321 } 2322 } 2323 PetscCall(ISRestoreIndices(dimIS, &points)); 2324 PetscCall(ISDestroy(&dimIS)); 2325 } 2326 divide: 2327 if (subpointIS) PetscCall(ISRestoreIndices(subpointIS, &subpoints)); 2328 PetscCall(DMPlexLabelFaultHalo(dm, label)); 2329 PetscCall(CheckFaultEdge_Private(dm, label, split)); 2330 PetscFunctionReturn(PETSC_SUCCESS); 2331 } 2332 2333 /* Check that no cell have all vertices on the fault */ 2334 static PetscErrorCode DMPlexCheckValidSubmesh_Private(DM dm, DMLabel label, DM subdm) 2335 { 2336 IS subpointIS; 2337 const PetscInt *dmpoints; 2338 PetscInt defaultValue, cStart, cEnd, c, vStart, vEnd; 2339 2340 PetscFunctionBegin; 2341 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 2342 PetscCall(DMLabelGetDefaultValue(label, &defaultValue)); 2343 PetscCall(DMPlexGetSubpointIS(subdm, &subpointIS)); 2344 if (!subpointIS) PetscFunctionReturn(PETSC_SUCCESS); 2345 PetscCall(DMPlexGetHeightStratum(subdm, 0, &cStart, &cEnd)); 2346 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 2347 PetscCall(ISGetIndices(subpointIS, &dmpoints)); 2348 for (c = cStart; c < cEnd; ++c) { 2349 PetscBool invalidCell = PETSC_TRUE; 2350 PetscInt *closure = NULL; 2351 PetscInt closureSize, cl; 2352 2353 PetscCall(DMPlexGetTransitiveClosure(dm, dmpoints[c], PETSC_TRUE, &closureSize, &closure)); 2354 for (cl = 0; cl < closureSize * 2; cl += 2) { 2355 PetscInt value = 0; 2356 2357 if ((closure[cl] < vStart) || (closure[cl] >= vEnd)) continue; 2358 PetscCall(DMLabelGetValue(label, closure[cl], &value)); 2359 if (value == defaultValue) { 2360 invalidCell = PETSC_FALSE; 2361 break; 2362 } 2363 } 2364 PetscCall(DMPlexRestoreTransitiveClosure(dm, dmpoints[c], PETSC_TRUE, &closureSize, &closure)); 2365 if (invalidCell) { 2366 PetscCall(ISRestoreIndices(subpointIS, &dmpoints)); 2367 PetscCall(ISDestroy(&subpointIS)); 2368 PetscCall(DMDestroy(&subdm)); 2369 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Ambiguous submesh. Cell %" PetscInt_FMT " has all of its vertices on the submesh.", dmpoints[c]); 2370 } 2371 } 2372 PetscCall(ISRestoreIndices(subpointIS, &dmpoints)); 2373 PetscFunctionReturn(PETSC_SUCCESS); 2374 } 2375 2376 /*@ 2377 DMPlexCreateHybridMesh - Create a mesh with hybrid cells along an internal interface 2378 2379 Collective 2380 2381 Input Parameters: 2382 + dm - The original `DM` 2383 . label - The label specifying the interface vertices 2384 . bdlabel - The optional label specifying the interface boundary vertices 2385 - bdvalue - Value of optional label specifying the interface boundary vertices 2386 2387 Output Parameters: 2388 + hybridLabel - The label fully marking the interface, or `NULL` if no output is desired 2389 . splitLabel - The label containing the split points, or `NULL` if no output is desired 2390 . dmInterface - The new interface `DM`, or `NULL` 2391 - dmHybrid - The new `DM` with cohesive cells 2392 2393 Level: developer 2394 2395 Note: 2396 The hybridLabel indicates what parts of the original mesh impinged on the division surface. For points 2397 directly on the division surface, they are labeled with their dimension, so an edge 7 on the division surface would be 2398 7 (1) in hybridLabel. For points that impinge from the positive side, they are labeled with 100+dim, so an edge 6 with 2399 one vertex 3 on the surface would be 6 (101) and 3 (0) in hybridLabel. If an edge 9 from the negative side of the 2400 surface also hits vertex 3, it would be 9 (-101) in hybridLabel. 2401 2402 The splitLabel indicates what points in the new hybrid mesh were the result of splitting points in the original 2403 mesh. The label value is $\pm 100+dim$ for each point. For example, if two edges 10 and 14 in the hybrid resulting from 2404 splitting an edge in the original mesh, you would have 10 (101) and 14 (-101) in the splitLabel. 2405 2406 The dmInterface is a `DM` built from the original division surface. It has a label which can be retrieved using 2407 `DMPlexGetSubpointMap()` which maps each point back to the point in the surface of the original mesh. 2408 2409 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexConstructCohesiveCells()`, `DMPlexLabelCohesiveComplete()`, `DMPlexGetSubpointMap()`, `DMCreate()` 2410 @*/ 2411 PetscErrorCode DMPlexCreateHybridMesh(DM dm, DMLabel label, DMLabel bdlabel, PetscInt bdvalue, DMLabel *hybridLabel, DMLabel *splitLabel, DM *dmInterface, DM *dmHybrid) 2412 { 2413 DM idm; 2414 DMLabel subpointMap, hlabel, slabel = NULL; 2415 PetscInt dim; 2416 2417 PetscFunctionBegin; 2418 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2419 if (label) PetscAssertPointer(label, 2); 2420 if (bdlabel) PetscAssertPointer(bdlabel, 3); 2421 if (hybridLabel) PetscAssertPointer(hybridLabel, 5); 2422 if (splitLabel) PetscAssertPointer(splitLabel, 6); 2423 if (dmInterface) PetscAssertPointer(dmInterface, 7); 2424 PetscAssertPointer(dmHybrid, 8); 2425 PetscCall(DMGetDimension(dm, &dim)); 2426 PetscCall(DMPlexCreateSubmesh(dm, label, 1, PETSC_FALSE, &idm)); 2427 PetscCall(DMPlexCheckValidSubmesh_Private(dm, label, idm)); 2428 PetscCall(DMPlexOrient(idm)); 2429 PetscCall(DMPlexGetSubpointMap(idm, &subpointMap)); 2430 PetscCall(DMLabelDuplicate(subpointMap, &hlabel)); 2431 PetscCall(DMLabelClearStratum(hlabel, dim)); 2432 if (splitLabel) { 2433 const char *name; 2434 char sname[PETSC_MAX_PATH_LEN]; 2435 2436 PetscCall(PetscObjectGetName((PetscObject)hlabel, &name)); 2437 PetscCall(PetscStrncpy(sname, name, sizeof(sname))); 2438 PetscCall(PetscStrlcat(sname, " split", sizeof(sname))); 2439 PetscCall(DMLabelCreate(PETSC_COMM_SELF, sname, &slabel)); 2440 } 2441 PetscCall(DMPlexLabelCohesiveComplete(dm, hlabel, bdlabel, bdvalue, PETSC_FALSE, PETSC_TRUE, idm)); 2442 if (dmInterface) { 2443 *dmInterface = idm; 2444 } else PetscCall(DMDestroy(&idm)); 2445 PetscCall(DMPlexConstructCohesiveCells(dm, hlabel, slabel, dmHybrid)); 2446 PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_TRUE, *dmHybrid)); 2447 if (hybridLabel) *hybridLabel = hlabel; 2448 else PetscCall(DMLabelDestroy(&hlabel)); 2449 if (splitLabel) *splitLabel = slabel; 2450 { 2451 DM cdm; 2452 DMLabel ctLabel; 2453 2454 /* We need to somehow share the celltype label with the coordinate dm */ 2455 PetscCall(DMGetCoordinateDM(*dmHybrid, &cdm)); 2456 PetscCall(DMPlexGetCellTypeLabel(*dmHybrid, &ctLabel)); 2457 PetscCall(DMSetLabel(cdm, ctLabel)); 2458 } 2459 PetscFunctionReturn(PETSC_SUCCESS); 2460 } 2461 2462 /* Here we need the explicit assumption that: 2463 2464 For any marked cell, the marked vertices constitute a single face 2465 */ 2466 static PetscErrorCode DMPlexMarkSubmesh_Uninterpolated(DM dm, DMLabel vertexLabel, PetscInt value, DMLabel subpointMap, PetscInt *numFaces, PetscInt *nFV, DM subdm) 2467 { 2468 IS subvertexIS = NULL; 2469 const PetscInt *subvertices; 2470 PetscInt *pStart, *pEnd, pSize; 2471 PetscInt depth, dim, d, numSubVerticesInitial = 0, v; 2472 2473 PetscFunctionBegin; 2474 *numFaces = 0; 2475 *nFV = 0; 2476 PetscCall(DMPlexGetDepth(dm, &depth)); 2477 PetscCall(DMGetDimension(dm, &dim)); 2478 pSize = PetscMax(depth, dim) + 1; 2479 PetscCall(PetscMalloc2(pSize, &pStart, pSize, &pEnd)); 2480 for (d = 0; d <= depth; ++d) PetscCall(DMPlexGetSimplexOrBoxCells(dm, depth - d, &pStart[d], &pEnd[d])); 2481 /* Loop over initial vertices and mark all faces in the collective star() */ 2482 if (vertexLabel) PetscCall(DMLabelGetStratumIS(vertexLabel, value, &subvertexIS)); 2483 if (subvertexIS) { 2484 PetscCall(ISGetSize(subvertexIS, &numSubVerticesInitial)); 2485 PetscCall(ISGetIndices(subvertexIS, &subvertices)); 2486 } 2487 for (v = 0; v < numSubVerticesInitial; ++v) { 2488 const PetscInt vertex = subvertices[v]; 2489 PetscInt *star = NULL; 2490 PetscInt starSize, s, numCells = 0, c; 2491 2492 PetscCall(DMPlexGetTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star)); 2493 for (s = 0; s < starSize * 2; s += 2) { 2494 const PetscInt point = star[s]; 2495 if (point >= pStart[depth] && point < pEnd[depth]) star[numCells++] = point; 2496 } 2497 for (c = 0; c < numCells; ++c) { 2498 const PetscInt cell = star[c]; 2499 PetscInt *closure = NULL; 2500 PetscInt closureSize, cl; 2501 PetscInt cellLoc, numCorners = 0, faceSize = 0; 2502 2503 PetscCall(DMLabelGetValue(subpointMap, cell, &cellLoc)); 2504 if (cellLoc == 2) continue; 2505 PetscCheck(cellLoc < 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Cell %" PetscInt_FMT " has dimension %" PetscInt_FMT " in the surface label", cell, cellLoc); 2506 PetscCall(DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure)); 2507 for (cl = 0; cl < closureSize * 2; cl += 2) { 2508 const PetscInt point = closure[cl]; 2509 PetscInt vertexLoc; 2510 2511 if (point >= pStart[0] && point < pEnd[0]) { 2512 ++numCorners; 2513 PetscCall(DMLabelGetValue(vertexLabel, point, &vertexLoc)); 2514 if (vertexLoc == value) closure[faceSize++] = point; 2515 } 2516 } 2517 if (!*nFV) PetscCall(DMPlexGetNumFaceVertices(dm, dim, numCorners, nFV)); 2518 PetscCheck(faceSize <= *nFV, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %" PetscInt_FMT " of an element on the surface", faceSize); 2519 if (faceSize == *nFV) { 2520 const PetscInt *cells = NULL; 2521 PetscInt numCells, nc; 2522 2523 ++(*numFaces); 2524 for (cl = 0; cl < faceSize; ++cl) PetscCall(DMLabelSetValue(subpointMap, closure[cl], 0)); 2525 PetscCall(DMPlexGetJoin(dm, faceSize, closure, &numCells, &cells)); 2526 for (nc = 0; nc < numCells; ++nc) PetscCall(DMLabelSetValue(subpointMap, cells[nc], 2)); 2527 PetscCall(DMPlexRestoreJoin(dm, faceSize, closure, &numCells, &cells)); 2528 } 2529 PetscCall(DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure)); 2530 } 2531 PetscCall(DMPlexRestoreTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star)); 2532 } 2533 if (subvertexIS) PetscCall(ISRestoreIndices(subvertexIS, &subvertices)); 2534 PetscCall(ISDestroy(&subvertexIS)); 2535 PetscCall(PetscFree2(pStart, pEnd)); 2536 PetscFunctionReturn(PETSC_SUCCESS); 2537 } 2538 2539 PetscErrorCode DMPlexMarkSubmesh_Interpolated(DM dm, DMLabel vertexLabel, PetscInt value, PetscBool markedFaces, PetscBool addCells, DMLabel subpointMap, DM subdm) 2540 { 2541 IS subvertexIS = NULL; 2542 const PetscInt *subvertices; 2543 PetscInt *pStart, *pEnd; 2544 PetscInt dim, d, numSubVerticesInitial = 0, v; 2545 2546 PetscFunctionBegin; 2547 PetscCall(DMGetDimension(dm, &dim)); 2548 PetscCall(PetscMalloc2(dim + 1, &pStart, dim + 1, &pEnd)); 2549 for (d = 0; d <= dim; ++d) PetscCall(DMPlexGetSimplexOrBoxCells(dm, dim - d, &pStart[d], &pEnd[d])); 2550 /* Loop over initial vertices and mark all faces in the collective star() */ 2551 if (vertexLabel) { 2552 PetscCall(DMLabelGetStratumIS(vertexLabel, value, &subvertexIS)); 2553 if (subvertexIS) { 2554 PetscCall(ISGetSize(subvertexIS, &numSubVerticesInitial)); 2555 PetscCall(ISGetIndices(subvertexIS, &subvertices)); 2556 } 2557 } 2558 for (v = 0; v < numSubVerticesInitial; ++v) { 2559 const PetscInt vertex = subvertices[v]; 2560 PetscInt *star = NULL; 2561 PetscInt starSize, s, numFaces = 0, f; 2562 2563 PetscCall(DMPlexGetTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star)); 2564 for (s = 0; s < starSize * 2; s += 2) { 2565 const PetscInt point = star[s]; 2566 PetscInt faceLoc; 2567 2568 if (point >= pStart[dim - 1] && point < pEnd[dim - 1]) { 2569 if (markedFaces) { 2570 PetscCall(DMLabelGetValue(vertexLabel, point, &faceLoc)); 2571 if (faceLoc < 0) continue; 2572 } 2573 star[numFaces++] = point; 2574 } 2575 } 2576 for (f = 0; f < numFaces; ++f) { 2577 const PetscInt face = star[f]; 2578 PetscInt *closure = NULL; 2579 PetscInt closureSize, c; 2580 PetscInt faceLoc; 2581 2582 PetscCall(DMLabelGetValue(subpointMap, face, &faceLoc)); 2583 if (faceLoc == dim - 1) continue; 2584 PetscCheck(faceLoc < 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Face %" PetscInt_FMT " has dimension %" PetscInt_FMT " in the surface label", face, faceLoc); 2585 PetscCall(DMPlexGetTransitiveClosure(dm, face, PETSC_TRUE, &closureSize, &closure)); 2586 for (c = 0; c < closureSize * 2; c += 2) { 2587 const PetscInt point = closure[c]; 2588 PetscInt vertexLoc; 2589 2590 if (point >= pStart[0] && point < pEnd[0]) { 2591 PetscCall(DMLabelGetValue(vertexLabel, point, &vertexLoc)); 2592 if (vertexLoc != value) break; 2593 } 2594 } 2595 if (c == closureSize * 2) { 2596 const PetscInt *support; 2597 PetscInt supportSize, s; 2598 2599 for (c = 0; c < closureSize * 2; c += 2) { 2600 const PetscInt point = closure[c]; 2601 2602 for (d = 0; d < dim; ++d) { 2603 if (point >= pStart[d] && point < pEnd[d]) { 2604 PetscCall(DMLabelSetValue(subpointMap, point, d)); 2605 break; 2606 } 2607 } 2608 } 2609 PetscCall(DMPlexGetSupportSize(dm, face, &supportSize)); 2610 PetscCall(DMPlexGetSupport(dm, face, &support)); 2611 if (addCells) 2612 for (s = 0; s < supportSize; ++s) PetscCall(DMLabelSetValue(subpointMap, support[s], dim)); 2613 } 2614 PetscCall(DMPlexRestoreTransitiveClosure(dm, face, PETSC_TRUE, &closureSize, &closure)); 2615 } 2616 PetscCall(DMPlexRestoreTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star)); 2617 } 2618 if (subvertexIS) PetscCall(ISRestoreIndices(subvertexIS, &subvertices)); 2619 PetscCall(ISDestroy(&subvertexIS)); 2620 PetscCall(PetscFree2(pStart, pEnd)); 2621 PetscFunctionReturn(PETSC_SUCCESS); 2622 } 2623 2624 static PetscErrorCode DMPlexMarkCohesiveSubmesh_Uninterpolated(DM dm, PetscBool hasLagrange, const char labelname[], PetscInt value, DMLabel subpointMap, PetscInt *numFaces, PetscInt *nFV, PetscInt *subCells[], DM subdm) 2625 { 2626 DMLabel label = NULL; 2627 const PetscInt *cone; 2628 PetscInt dim, cMax, cEnd, c, subc = 0, p, coneSize = -1; 2629 2630 PetscFunctionBegin; 2631 *numFaces = 0; 2632 *nFV = 0; 2633 if (labelname) PetscCall(DMGetLabel(dm, labelname, &label)); 2634 *subCells = NULL; 2635 PetscCall(DMGetDimension(dm, &dim)); 2636 PetscCall(DMPlexGetTensorPrismBounds_Internal(dm, dim, &cMax, &cEnd)); 2637 if (cMax < 0) PetscFunctionReturn(PETSC_SUCCESS); 2638 if (label) { 2639 for (c = cMax; c < cEnd; ++c) { 2640 PetscInt val; 2641 2642 PetscCall(DMLabelGetValue(label, c, &val)); 2643 if (val == value) { 2644 ++(*numFaces); 2645 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 2646 } 2647 } 2648 } else { 2649 *numFaces = cEnd - cMax; 2650 PetscCall(DMPlexGetConeSize(dm, cMax, &coneSize)); 2651 } 2652 PetscCall(PetscMalloc1(*numFaces * 2, subCells)); 2653 if (!*numFaces) PetscFunctionReturn(PETSC_SUCCESS); 2654 *nFV = hasLagrange ? coneSize / 3 : coneSize / 2; 2655 for (c = cMax; c < cEnd; ++c) { 2656 const PetscInt *cells; 2657 PetscInt numCells; 2658 2659 if (label) { 2660 PetscInt val; 2661 2662 PetscCall(DMLabelGetValue(label, c, &val)); 2663 if (val != value) continue; 2664 } 2665 PetscCall(DMPlexGetCone(dm, c, &cone)); 2666 for (p = 0; p < *nFV; ++p) PetscCall(DMLabelSetValue(subpointMap, cone[p], 0)); 2667 /* Negative face */ 2668 PetscCall(DMPlexGetJoin(dm, *nFV, cone, &numCells, &cells)); 2669 /* Not true in parallel 2670 PetscCheck(numCells == 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cohesive cells should separate two cells"); */ 2671 for (p = 0; p < numCells; ++p) { 2672 PetscCall(DMLabelSetValue(subpointMap, cells[p], 2)); 2673 (*subCells)[subc++] = cells[p]; 2674 } 2675 PetscCall(DMPlexRestoreJoin(dm, *nFV, cone, &numCells, &cells)); 2676 /* Positive face is not included */ 2677 } 2678 PetscFunctionReturn(PETSC_SUCCESS); 2679 } 2680 2681 static PetscErrorCode DMPlexMarkCohesiveSubmesh_Interpolated(DM dm, DMLabel label, PetscInt value, DMLabel subpointMap, DM subdm) 2682 { 2683 PetscInt *pStart, *pEnd; 2684 PetscInt dim, cMax, cEnd, c, d; 2685 2686 PetscFunctionBegin; 2687 PetscCall(DMGetDimension(dm, &dim)); 2688 PetscCall(DMPlexGetTensorPrismBounds_Internal(dm, dim, &cMax, &cEnd)); 2689 if (cMax < 0) PetscFunctionReturn(PETSC_SUCCESS); 2690 PetscCall(PetscMalloc2(dim + 1, &pStart, dim + 1, &pEnd)); 2691 for (d = 0; d <= dim; ++d) PetscCall(DMPlexGetDepthStratum(dm, d, &pStart[d], &pEnd[d])); 2692 for (c = cMax; c < cEnd; ++c) { 2693 const PetscInt *cone; 2694 PetscInt *closure = NULL; 2695 PetscInt fconeSize, coneSize, closureSize, cl, val; 2696 2697 if (label) { 2698 PetscCall(DMLabelGetValue(label, c, &val)); 2699 if (val != value) continue; 2700 } 2701 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 2702 PetscCall(DMPlexGetCone(dm, c, &cone)); 2703 PetscCall(DMPlexGetConeSize(dm, cone[0], &fconeSize)); 2704 PetscCheck(coneSize == (fconeSize ? fconeSize : 1) + 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cohesive cells should separate two cells"); 2705 /* Negative face */ 2706 PetscCall(DMPlexGetTransitiveClosure(dm, cone[0], PETSC_TRUE, &closureSize, &closure)); 2707 for (cl = 0; cl < closureSize * 2; cl += 2) { 2708 const PetscInt point = closure[cl]; 2709 2710 for (d = 0; d <= dim; ++d) { 2711 if (point >= pStart[d] && point < pEnd[d]) { 2712 PetscCall(DMLabelSetValue(subpointMap, point, d)); 2713 break; 2714 } 2715 } 2716 } 2717 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], PETSC_TRUE, &closureSize, &closure)); 2718 /* Cells -- positive face is not included */ 2719 for (cl = 0; cl < 1; ++cl) { 2720 const PetscInt *support; 2721 PetscInt supportSize, s; 2722 2723 PetscCall(DMPlexGetSupportSize(dm, cone[cl], &supportSize)); 2724 /* PetscCheck(supportSize == 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cohesive faces should separate two cells"); */ 2725 PetscCall(DMPlexGetSupport(dm, cone[cl], &support)); 2726 for (s = 0; s < supportSize; ++s) PetscCall(DMLabelSetValue(subpointMap, support[s], dim)); 2727 } 2728 } 2729 PetscCall(PetscFree2(pStart, pEnd)); 2730 PetscFunctionReturn(PETSC_SUCCESS); 2731 } 2732 2733 static PetscErrorCode DMPlexGetFaceOrientation(DM dm, PetscInt cell, PetscInt numCorners, PetscInt indices[], PetscInt oppositeVertex, PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented) 2734 { 2735 MPI_Comm comm; 2736 PetscBool posOrient = PETSC_FALSE; 2737 const PetscInt debug = 0; 2738 PetscInt cellDim, faceSize, f; 2739 2740 PetscFunctionBegin; 2741 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 2742 PetscCall(DMGetDimension(dm, &cellDim)); 2743 if (debug) PetscCall(PetscPrintf(comm, "cellDim: %" PetscInt_FMT " numCorners: %" PetscInt_FMT "\n", cellDim, numCorners)); 2744 2745 if (cellDim == 1 && numCorners == 2) { 2746 /* Triangle */ 2747 faceSize = numCorners - 1; 2748 posOrient = !(oppositeVertex % 2) ? PETSC_TRUE : PETSC_FALSE; 2749 } else if (cellDim == 2 && numCorners == 3) { 2750 /* Triangle */ 2751 faceSize = numCorners - 1; 2752 posOrient = !(oppositeVertex % 2) ? PETSC_TRUE : PETSC_FALSE; 2753 } else if (cellDim == 3 && numCorners == 4) { 2754 /* Tetrahedron */ 2755 faceSize = numCorners - 1; 2756 posOrient = (oppositeVertex % 2) ? PETSC_TRUE : PETSC_FALSE; 2757 } else if (cellDim == 1 && numCorners == 3) { 2758 /* Quadratic line */ 2759 faceSize = 1; 2760 posOrient = PETSC_TRUE; 2761 } else if (cellDim == 2 && numCorners == 4) { 2762 /* Quads */ 2763 faceSize = 2; 2764 if (indices[1] > indices[0] && indices[1] - indices[0] == 1) { 2765 posOrient = PETSC_TRUE; 2766 } else if (indices[0] == 3 && indices[1] == 0) { 2767 posOrient = PETSC_TRUE; 2768 } else { 2769 PetscCheck((indices[0] > indices[1] && indices[0] - indices[1] == 1) || (indices[0] == 0 && indices[1] == 3), comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossedge"); 2770 posOrient = PETSC_FALSE; 2771 } 2772 } else if (cellDim == 2 && numCorners == 6) { 2773 /* Quadratic triangle (I hate this) */ 2774 /* Edges are determined by the first 2 vertices (corners of edges) */ 2775 const PetscInt faceSizeTri = 3; 2776 PetscInt sortedIndices[3], i, iFace; 2777 PetscBool found = PETSC_FALSE; 2778 PetscInt faceVerticesTriSorted[9] = { 2779 0, 3, 4, /* bottom */ 2780 1, 4, 5, /* right */ 2781 2, 3, 5, /* left */ 2782 }; 2783 PetscInt faceVerticesTri[9] = { 2784 0, 3, 4, /* bottom */ 2785 1, 4, 5, /* right */ 2786 2, 5, 3, /* left */ 2787 }; 2788 2789 for (i = 0; i < faceSizeTri; ++i) sortedIndices[i] = indices[i]; 2790 PetscCall(PetscSortInt(faceSizeTri, sortedIndices)); 2791 for (iFace = 0; iFace < 3; ++iFace) { 2792 const PetscInt ii = iFace * faceSizeTri; 2793 PetscInt fVertex, cVertex; 2794 2795 if (sortedIndices[0] == faceVerticesTriSorted[ii + 0] && sortedIndices[1] == faceVerticesTriSorted[ii + 1]) { 2796 for (fVertex = 0; fVertex < faceSizeTri; ++fVertex) { 2797 for (cVertex = 0; cVertex < faceSizeTri; ++cVertex) { 2798 if (indices[cVertex] == faceVerticesTri[ii + fVertex]) { 2799 faceVertices[fVertex] = origVertices[cVertex]; 2800 break; 2801 } 2802 } 2803 } 2804 found = PETSC_TRUE; 2805 break; 2806 } 2807 } 2808 PetscCheck(found, comm, PETSC_ERR_ARG_WRONG, "Invalid tri crossface"); 2809 if (posOriented) *posOriented = PETSC_TRUE; 2810 PetscFunctionReturn(PETSC_SUCCESS); 2811 } else if (cellDim == 2 && numCorners == 9) { 2812 /* Quadratic quad (I hate this) */ 2813 /* Edges are determined by the first 2 vertices (corners of edges) */ 2814 const PetscInt faceSizeQuad = 3; 2815 PetscInt sortedIndices[3], i, iFace; 2816 PetscBool found = PETSC_FALSE; 2817 PetscInt faceVerticesQuadSorted[12] = { 2818 0, 1, 4, /* bottom */ 2819 1, 2, 5, /* right */ 2820 2, 3, 6, /* top */ 2821 0, 3, 7, /* left */ 2822 }; 2823 PetscInt faceVerticesQuad[12] = { 2824 0, 1, 4, /* bottom */ 2825 1, 2, 5, /* right */ 2826 2, 3, 6, /* top */ 2827 3, 0, 7, /* left */ 2828 }; 2829 2830 for (i = 0; i < faceSizeQuad; ++i) sortedIndices[i] = indices[i]; 2831 PetscCall(PetscSortInt(faceSizeQuad, sortedIndices)); 2832 for (iFace = 0; iFace < 4; ++iFace) { 2833 const PetscInt ii = iFace * faceSizeQuad; 2834 PetscInt fVertex, cVertex; 2835 2836 if (sortedIndices[0] == faceVerticesQuadSorted[ii + 0] && sortedIndices[1] == faceVerticesQuadSorted[ii + 1]) { 2837 for (fVertex = 0; fVertex < faceSizeQuad; ++fVertex) { 2838 for (cVertex = 0; cVertex < faceSizeQuad; ++cVertex) { 2839 if (indices[cVertex] == faceVerticesQuad[ii + fVertex]) { 2840 faceVertices[fVertex] = origVertices[cVertex]; 2841 break; 2842 } 2843 } 2844 } 2845 found = PETSC_TRUE; 2846 break; 2847 } 2848 } 2849 PetscCheck(found, comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossface"); 2850 if (posOriented) *posOriented = PETSC_TRUE; 2851 PetscFunctionReturn(PETSC_SUCCESS); 2852 } else if (cellDim == 3 && numCorners == 8) { 2853 /* Hexes 2854 A hex is two oriented quads with the normal of the first 2855 pointing up at the second. 2856 2857 7---6 2858 /| /| 2859 4---5 | 2860 | 1-|-2 2861 |/ |/ 2862 0---3 2863 2864 Faces are determined by the first 4 vertices (corners of faces) */ 2865 const PetscInt faceSizeHex = 4; 2866 PetscInt sortedIndices[4], i, iFace; 2867 PetscBool found = PETSC_FALSE; 2868 PetscInt faceVerticesHexSorted[24] = { 2869 0, 1, 2, 3, /* bottom */ 2870 4, 5, 6, 7, /* top */ 2871 0, 3, 4, 5, /* front */ 2872 2, 3, 5, 6, /* right */ 2873 1, 2, 6, 7, /* back */ 2874 0, 1, 4, 7, /* left */ 2875 }; 2876 PetscInt faceVerticesHex[24] = { 2877 1, 2, 3, 0, /* bottom */ 2878 4, 5, 6, 7, /* top */ 2879 0, 3, 5, 4, /* front */ 2880 3, 2, 6, 5, /* right */ 2881 2, 1, 7, 6, /* back */ 2882 1, 0, 4, 7, /* left */ 2883 }; 2884 2885 for (i = 0; i < faceSizeHex; ++i) sortedIndices[i] = indices[i]; 2886 PetscCall(PetscSortInt(faceSizeHex, sortedIndices)); 2887 for (iFace = 0; iFace < 6; ++iFace) { 2888 const PetscInt ii = iFace * faceSizeHex; 2889 PetscInt fVertex, cVertex; 2890 2891 if (sortedIndices[0] == faceVerticesHexSorted[ii + 0] && sortedIndices[1] == faceVerticesHexSorted[ii + 1] && sortedIndices[2] == faceVerticesHexSorted[ii + 2] && sortedIndices[3] == faceVerticesHexSorted[ii + 3]) { 2892 for (fVertex = 0; fVertex < faceSizeHex; ++fVertex) { 2893 for (cVertex = 0; cVertex < faceSizeHex; ++cVertex) { 2894 if (indices[cVertex] == faceVerticesHex[ii + fVertex]) { 2895 faceVertices[fVertex] = origVertices[cVertex]; 2896 break; 2897 } 2898 } 2899 } 2900 found = PETSC_TRUE; 2901 break; 2902 } 2903 } 2904 PetscCheck(found, comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface"); 2905 if (posOriented) *posOriented = PETSC_TRUE; 2906 PetscFunctionReturn(PETSC_SUCCESS); 2907 } else if (cellDim == 3 && numCorners == 10) { 2908 /* Quadratic tet */ 2909 /* Faces are determined by the first 3 vertices (corners of faces) */ 2910 const PetscInt faceSizeTet = 6; 2911 PetscInt sortedIndices[6], i, iFace; 2912 PetscBool found = PETSC_FALSE; 2913 PetscInt faceVerticesTetSorted[24] = { 2914 0, 1, 2, 6, 7, 8, /* bottom */ 2915 0, 3, 4, 6, 7, 9, /* front */ 2916 1, 4, 5, 7, 8, 9, /* right */ 2917 2, 3, 5, 6, 8, 9, /* left */ 2918 }; 2919 PetscInt faceVerticesTet[24] = { 2920 0, 1, 2, 6, 7, 8, /* bottom */ 2921 0, 4, 3, 6, 7, 9, /* front */ 2922 1, 5, 4, 7, 8, 9, /* right */ 2923 2, 3, 5, 8, 6, 9, /* left */ 2924 }; 2925 2926 for (i = 0; i < faceSizeTet; ++i) sortedIndices[i] = indices[i]; 2927 PetscCall(PetscSortInt(faceSizeTet, sortedIndices)); 2928 for (iFace = 0; iFace < 4; ++iFace) { 2929 const PetscInt ii = iFace * faceSizeTet; 2930 PetscInt fVertex, cVertex; 2931 2932 if (sortedIndices[0] == faceVerticesTetSorted[ii + 0] && sortedIndices[1] == faceVerticesTetSorted[ii + 1] && sortedIndices[2] == faceVerticesTetSorted[ii + 2] && sortedIndices[3] == faceVerticesTetSorted[ii + 3]) { 2933 for (fVertex = 0; fVertex < faceSizeTet; ++fVertex) { 2934 for (cVertex = 0; cVertex < faceSizeTet; ++cVertex) { 2935 if (indices[cVertex] == faceVerticesTet[ii + fVertex]) { 2936 faceVertices[fVertex] = origVertices[cVertex]; 2937 break; 2938 } 2939 } 2940 } 2941 found = PETSC_TRUE; 2942 break; 2943 } 2944 } 2945 PetscCheck(found, comm, PETSC_ERR_ARG_WRONG, "Invalid tet crossface"); 2946 if (posOriented) *posOriented = PETSC_TRUE; 2947 PetscFunctionReturn(PETSC_SUCCESS); 2948 } else if (cellDim == 3 && numCorners == 27) { 2949 /* Quadratic hexes (I hate this) 2950 A hex is two oriented quads with the normal of the first 2951 pointing up at the second. 2952 2953 7---6 2954 /| /| 2955 4---5 | 2956 | 3-|-2 2957 |/ |/ 2958 0---1 2959 2960 Faces are determined by the first 4 vertices (corners of faces) */ 2961 const PetscInt faceSizeQuadHex = 9; 2962 PetscInt sortedIndices[9], i, iFace; 2963 PetscBool found = PETSC_FALSE; 2964 PetscInt faceVerticesQuadHexSorted[54] = { 2965 0, 1, 2, 3, 8, 9, 10, 11, 24, /* bottom */ 2966 4, 5, 6, 7, 12, 13, 14, 15, 25, /* top */ 2967 0, 1, 4, 5, 8, 12, 16, 17, 22, /* front */ 2968 1, 2, 5, 6, 9, 13, 17, 18, 21, /* right */ 2969 2, 3, 6, 7, 10, 14, 18, 19, 23, /* back */ 2970 0, 3, 4, 7, 11, 15, 16, 19, 20, /* left */ 2971 }; 2972 PetscInt faceVerticesQuadHex[54] = { 2973 3, 2, 1, 0, 10, 9, 8, 11, 24, /* bottom */ 2974 4, 5, 6, 7, 12, 13, 14, 15, 25, /* top */ 2975 0, 1, 5, 4, 8, 17, 12, 16, 22, /* front */ 2976 1, 2, 6, 5, 9, 18, 13, 17, 21, /* right */ 2977 2, 3, 7, 6, 10, 19, 14, 18, 23, /* back */ 2978 3, 0, 4, 7, 11, 16, 15, 19, 20 /* left */ 2979 }; 2980 2981 for (i = 0; i < faceSizeQuadHex; ++i) sortedIndices[i] = indices[i]; 2982 PetscCall(PetscSortInt(faceSizeQuadHex, sortedIndices)); 2983 for (iFace = 0; iFace < 6; ++iFace) { 2984 const PetscInt ii = iFace * faceSizeQuadHex; 2985 PetscInt fVertex, cVertex; 2986 2987 if (sortedIndices[0] == faceVerticesQuadHexSorted[ii + 0] && sortedIndices[1] == faceVerticesQuadHexSorted[ii + 1] && sortedIndices[2] == faceVerticesQuadHexSorted[ii + 2] && sortedIndices[3] == faceVerticesQuadHexSorted[ii + 3]) { 2988 for (fVertex = 0; fVertex < faceSizeQuadHex; ++fVertex) { 2989 for (cVertex = 0; cVertex < faceSizeQuadHex; ++cVertex) { 2990 if (indices[cVertex] == faceVerticesQuadHex[ii + fVertex]) { 2991 faceVertices[fVertex] = origVertices[cVertex]; 2992 break; 2993 } 2994 } 2995 } 2996 found = PETSC_TRUE; 2997 break; 2998 } 2999 } 3000 PetscCheck(found, comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface"); 3001 if (posOriented) *posOriented = PETSC_TRUE; 3002 PetscFunctionReturn(PETSC_SUCCESS); 3003 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Unknown cell type for faceOrientation()."); 3004 if (!posOrient) { 3005 if (debug) PetscCall(PetscPrintf(comm, " Reversing initial face orientation\n")); 3006 for (f = 0; f < faceSize; ++f) faceVertices[f] = origVertices[faceSize - 1 - f]; 3007 } else { 3008 if (debug) PetscCall(PetscPrintf(comm, " Keeping initial face orientation\n")); 3009 for (f = 0; f < faceSize; ++f) faceVertices[f] = origVertices[f]; 3010 } 3011 if (posOriented) *posOriented = posOrient; 3012 PetscFunctionReturn(PETSC_SUCCESS); 3013 } 3014 3015 /*@ 3016 DMPlexGetOrientedFace - Given a cell and a face, as a set of vertices, return the oriented face, as a set of vertices, 3017 in faceVertices. The orientation is such that the face normal points out of the cell 3018 3019 Not Collective 3020 3021 Input Parameters: 3022 + dm - The original mesh 3023 . cell - The cell mesh point 3024 . faceSize - The number of vertices on the face 3025 . face - The face vertices 3026 . numCorners - The number of vertices on the cell 3027 . indices - Local numbering of face vertices in cell cone 3028 - origVertices - Original face vertices 3029 3030 Output Parameters: 3031 + faceVertices - The face vertices properly oriented 3032 - posOriented - `PETSC_TRUE` if the face was oriented with outward normal 3033 3034 Level: developer 3035 3036 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetCone()` 3037 @*/ 3038 PetscErrorCode DMPlexGetOrientedFace(DM dm, PetscInt cell, PetscInt faceSize, const PetscInt face[], PetscInt numCorners, PetscInt indices[], PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented) 3039 { 3040 const PetscInt *cone = NULL; 3041 PetscInt coneSize, v, f, v2; 3042 PetscInt oppositeVertex = -1; 3043 3044 PetscFunctionBegin; 3045 PetscCall(DMPlexGetConeSize(dm, cell, &coneSize)); 3046 PetscCall(DMPlexGetCone(dm, cell, &cone)); 3047 for (v = 0, v2 = 0; v < coneSize; ++v) { 3048 PetscBool found = PETSC_FALSE; 3049 3050 for (f = 0; f < faceSize; ++f) { 3051 if (face[f] == cone[v]) { 3052 found = PETSC_TRUE; 3053 break; 3054 } 3055 } 3056 if (found) { 3057 indices[v2] = v; 3058 origVertices[v2] = cone[v]; 3059 ++v2; 3060 } else { 3061 oppositeVertex = v; 3062 } 3063 } 3064 PetscCall(DMPlexGetFaceOrientation(dm, cell, numCorners, indices, oppositeVertex, origVertices, faceVertices, posOriented)); 3065 PetscFunctionReturn(PETSC_SUCCESS); 3066 } 3067 3068 /* 3069 DMPlexInsertFace_Internal - Puts a face into the mesh 3070 3071 Not Collective 3072 3073 Input Parameters: 3074 + dm - The `DMPLEX` 3075 . numFaceVertex - The number of vertices in the face 3076 . faceVertices - The vertices in the face for `dm` 3077 . subfaceVertices - The vertices in the face for subdm 3078 . numCorners - The number of vertices in the `cell` 3079 . cell - A cell in `dm` containing the face 3080 . subcell - A cell in subdm containing the face 3081 . firstFace - First face in the mesh 3082 - newFacePoint - Next face in the mesh 3083 3084 Output Parameter: 3085 . newFacePoint - Contains next face point number on input, updated on output 3086 3087 Level: developer 3088 */ 3089 static PetscErrorCode DMPlexInsertFace_Internal(DM dm, DM subdm, PetscInt numFaceVertices, const PetscInt faceVertices[], const PetscInt subfaceVertices[], PetscInt numCorners, PetscInt cell, PetscInt subcell, PetscInt firstFace, PetscInt *newFacePoint) 3090 { 3091 MPI_Comm comm; 3092 DM_Plex *submesh = (DM_Plex *)subdm->data; 3093 const PetscInt *faces; 3094 PetscInt numFaces, coneSize; 3095 3096 PetscFunctionBegin; 3097 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 3098 PetscCall(DMPlexGetConeSize(subdm, subcell, &coneSize)); 3099 PetscCheck(coneSize == 1, comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size of cell %" PetscInt_FMT " is %" PetscInt_FMT " != 1", cell, coneSize); 3100 #if 0 3101 /* Cannot use this because support() has not been constructed yet */ 3102 PetscCall(DMPlexGetJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces)); 3103 #else 3104 { 3105 PetscInt f; 3106 3107 numFaces = 0; 3108 PetscCall(DMGetWorkArray(subdm, 1, MPIU_INT, (void **)&faces)); 3109 for (f = firstFace; f < *newFacePoint; ++f) { 3110 PetscInt dof, off, d; 3111 3112 PetscCall(PetscSectionGetDof(submesh->coneSection, f, &dof)); 3113 PetscCall(PetscSectionGetOffset(submesh->coneSection, f, &off)); 3114 /* Yes, I know this is quadratic, but I expect the sizes to be <5 */ 3115 for (d = 0; d < dof; ++d) { 3116 const PetscInt p = submesh->cones[off + d]; 3117 PetscInt v; 3118 3119 for (v = 0; v < numFaceVertices; ++v) { 3120 if (subfaceVertices[v] == p) break; 3121 } 3122 if (v == numFaceVertices) break; 3123 } 3124 if (d == dof) { 3125 numFaces = 1; 3126 ((PetscInt *)faces)[0] = f; 3127 } 3128 } 3129 } 3130 #endif 3131 PetscCheck(numFaces <= 1, comm, PETSC_ERR_ARG_WRONG, "Vertex set had %" PetscInt_FMT " faces, not one", numFaces); 3132 if (numFaces == 1) { 3133 /* Add the other cell neighbor for this face */ 3134 PetscCall(DMPlexSetCone(subdm, subcell, faces)); 3135 } else { 3136 PetscInt *indices, *origVertices, *orientedVertices, *orientedSubVertices, v, ov; 3137 PetscBool posOriented; 3138 3139 PetscCall(DMGetWorkArray(subdm, 4 * numFaceVertices * sizeof(PetscInt), MPIU_INT, &orientedVertices)); 3140 origVertices = &orientedVertices[numFaceVertices]; 3141 indices = &orientedVertices[numFaceVertices * 2]; 3142 orientedSubVertices = &orientedVertices[numFaceVertices * 3]; 3143 PetscCall(DMPlexGetOrientedFace(dm, cell, numFaceVertices, faceVertices, numCorners, indices, origVertices, orientedVertices, &posOriented)); 3144 /* TODO: I know that routine should return a permutation, not the indices */ 3145 for (v = 0; v < numFaceVertices; ++v) { 3146 const PetscInt vertex = faceVertices[v], subvertex = subfaceVertices[v]; 3147 for (ov = 0; ov < numFaceVertices; ++ov) { 3148 if (orientedVertices[ov] == vertex) { 3149 orientedSubVertices[ov] = subvertex; 3150 break; 3151 } 3152 } 3153 PetscCheck(ov != numFaceVertices, comm, PETSC_ERR_PLIB, "Could not find face vertex %" PetscInt_FMT " in orientated set", vertex); 3154 } 3155 PetscCall(DMPlexSetCone(subdm, *newFacePoint, orientedSubVertices)); 3156 PetscCall(DMPlexSetCone(subdm, subcell, newFacePoint)); 3157 PetscCall(DMRestoreWorkArray(subdm, 4 * numFaceVertices * sizeof(PetscInt), MPIU_INT, &orientedVertices)); 3158 ++(*newFacePoint); 3159 } 3160 #if 0 3161 PetscCall(DMPlexRestoreJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces)); 3162 #else 3163 PetscCall(DMRestoreWorkArray(subdm, 1, MPIU_INT, (void **)&faces)); 3164 #endif 3165 PetscFunctionReturn(PETSC_SUCCESS); 3166 } 3167 3168 static PetscErrorCode DMPlexCreateSubmesh_Uninterpolated(DM dm, DMLabel vertexLabel, PetscInt value, DM subdm) 3169 { 3170 MPI_Comm comm; 3171 DMLabel subpointMap; 3172 IS subvertexIS, subcellIS; 3173 const PetscInt *subVertices, *subCells; 3174 PetscInt numSubVertices, firstSubVertex, numSubCells; 3175 PetscInt *subface, maxConeSize, numSubFaces = 0, firstSubFace, newFacePoint, nFV = 0; 3176 PetscInt vStart, vEnd, c, f; 3177 3178 PetscFunctionBegin; 3179 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 3180 /* Create subpointMap which marks the submesh */ 3181 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "subpoint_map", &subpointMap)); 3182 PetscCall(DMPlexSetSubpointMap(subdm, subpointMap)); 3183 if (vertexLabel) PetscCall(DMPlexMarkSubmesh_Uninterpolated(dm, vertexLabel, value, subpointMap, &numSubFaces, &nFV, subdm)); 3184 /* Setup chart */ 3185 PetscCall(DMLabelGetStratumSize(subpointMap, 0, &numSubVertices)); 3186 PetscCall(DMLabelGetStratumSize(subpointMap, 2, &numSubCells)); 3187 PetscCall(DMPlexSetChart(subdm, 0, numSubCells + numSubFaces + numSubVertices)); 3188 PetscCall(DMPlexSetVTKCellHeight(subdm, 1)); 3189 /* Set cone sizes */ 3190 firstSubVertex = numSubCells; 3191 firstSubFace = numSubCells + numSubVertices; 3192 newFacePoint = firstSubFace; 3193 PetscCall(DMLabelGetStratumIS(subpointMap, 0, &subvertexIS)); 3194 if (subvertexIS) PetscCall(ISGetIndices(subvertexIS, &subVertices)); 3195 PetscCall(DMLabelGetStratumIS(subpointMap, 2, &subcellIS)); 3196 if (subcellIS) PetscCall(ISGetIndices(subcellIS, &subCells)); 3197 for (c = 0; c < numSubCells; ++c) PetscCall(DMPlexSetConeSize(subdm, c, 1)); 3198 for (f = firstSubFace; f < firstSubFace + numSubFaces; ++f) PetscCall(DMPlexSetConeSize(subdm, f, nFV)); 3199 PetscCall(DMSetUp(subdm)); 3200 PetscCall(DMLabelDestroy(&subpointMap)); 3201 /* Create face cones */ 3202 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 3203 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, NULL)); 3204 PetscCall(DMGetWorkArray(subdm, maxConeSize, MPIU_INT, (void **)&subface)); 3205 for (c = 0; c < numSubCells; ++c) { 3206 const PetscInt cell = subCells[c]; 3207 const PetscInt subcell = c; 3208 PetscInt *closure = NULL; 3209 PetscInt closureSize, cl, numCorners = 0, faceSize = 0; 3210 3211 PetscCall(DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure)); 3212 for (cl = 0; cl < closureSize * 2; cl += 2) { 3213 const PetscInt point = closure[cl]; 3214 PetscInt subVertex; 3215 3216 if (point >= vStart && point < vEnd) { 3217 ++numCorners; 3218 PetscCall(PetscFindInt(point, numSubVertices, subVertices, &subVertex)); 3219 if (subVertex >= 0) { 3220 closure[faceSize] = point; 3221 subface[faceSize] = firstSubVertex + subVertex; 3222 ++faceSize; 3223 } 3224 } 3225 } 3226 PetscCheck(faceSize <= nFV, comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %" PetscInt_FMT " of an element on the surface", faceSize); 3227 if (faceSize == nFV) PetscCall(DMPlexInsertFace_Internal(dm, subdm, faceSize, closure, subface, numCorners, cell, subcell, firstSubFace, &newFacePoint)); 3228 PetscCall(DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure)); 3229 } 3230 PetscCall(DMRestoreWorkArray(subdm, maxConeSize, MPIU_INT, (void **)&subface)); 3231 PetscCall(DMPlexSymmetrize(subdm)); 3232 PetscCall(DMPlexStratify(subdm)); 3233 /* Build coordinates */ 3234 { 3235 PetscSection coordSection, subCoordSection; 3236 Vec coordinates, subCoordinates; 3237 PetscScalar *coords, *subCoords; 3238 PetscInt numComp, coordSize, v; 3239 const char *name; 3240 3241 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 3242 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 3243 PetscCall(DMGetCoordinateSection(subdm, &subCoordSection)); 3244 PetscCall(PetscSectionSetNumFields(subCoordSection, 1)); 3245 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &numComp)); 3246 PetscCall(PetscSectionSetFieldComponents(subCoordSection, 0, numComp)); 3247 PetscCall(PetscSectionSetChart(subCoordSection, firstSubVertex, firstSubVertex + numSubVertices)); 3248 for (v = 0; v < numSubVertices; ++v) { 3249 const PetscInt vertex = subVertices[v]; 3250 const PetscInt subvertex = firstSubVertex + v; 3251 PetscInt dof; 3252 3253 PetscCall(PetscSectionGetDof(coordSection, vertex, &dof)); 3254 PetscCall(PetscSectionSetDof(subCoordSection, subvertex, dof)); 3255 PetscCall(PetscSectionSetFieldDof(subCoordSection, subvertex, 0, dof)); 3256 } 3257 PetscCall(PetscSectionSetUp(subCoordSection)); 3258 PetscCall(PetscSectionGetStorageSize(subCoordSection, &coordSize)); 3259 PetscCall(VecCreate(PETSC_COMM_SELF, &subCoordinates)); 3260 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 3261 PetscCall(PetscObjectSetName((PetscObject)subCoordinates, name)); 3262 PetscCall(VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE)); 3263 PetscCall(VecSetType(subCoordinates, VECSTANDARD)); 3264 if (coordSize) { 3265 PetscCall(VecGetArray(coordinates, &coords)); 3266 PetscCall(VecGetArray(subCoordinates, &subCoords)); 3267 for (v = 0; v < numSubVertices; ++v) { 3268 const PetscInt vertex = subVertices[v]; 3269 const PetscInt subvertex = firstSubVertex + v; 3270 PetscInt dof, off, sdof, soff, d; 3271 3272 PetscCall(PetscSectionGetDof(coordSection, vertex, &dof)); 3273 PetscCall(PetscSectionGetOffset(coordSection, vertex, &off)); 3274 PetscCall(PetscSectionGetDof(subCoordSection, subvertex, &sdof)); 3275 PetscCall(PetscSectionGetOffset(subCoordSection, subvertex, &soff)); 3276 PetscCheck(dof == sdof, comm, PETSC_ERR_PLIB, "Coordinate dimension %" PetscInt_FMT " on subvertex %" PetscInt_FMT ", vertex %" PetscInt_FMT " should be %" PetscInt_FMT, sdof, subvertex, vertex, dof); 3277 for (d = 0; d < dof; ++d) subCoords[soff + d] = coords[off + d]; 3278 } 3279 PetscCall(VecRestoreArray(coordinates, &coords)); 3280 PetscCall(VecRestoreArray(subCoordinates, &subCoords)); 3281 } 3282 PetscCall(DMSetCoordinatesLocal(subdm, subCoordinates)); 3283 PetscCall(VecDestroy(&subCoordinates)); 3284 } 3285 /* Cleanup */ 3286 if (subvertexIS) PetscCall(ISRestoreIndices(subvertexIS, &subVertices)); 3287 PetscCall(ISDestroy(&subvertexIS)); 3288 if (subcellIS) PetscCall(ISRestoreIndices(subcellIS, &subCells)); 3289 PetscCall(ISDestroy(&subcellIS)); 3290 PetscFunctionReturn(PETSC_SUCCESS); 3291 } 3292 3293 /* TODO: Fix this to properly propagate up error conditions it may find */ 3294 static inline PetscInt DMPlexFilterPoint_Internal(PetscInt point, PetscInt firstSubPoint, PetscInt numSubPoints, const PetscInt subPoints[]) 3295 { 3296 PetscInt subPoint; 3297 PetscErrorCode ierr; 3298 3299 ierr = PetscFindInt(point, numSubPoints, subPoints, &subPoint); 3300 if (ierr) return -1; 3301 return subPoint < 0 ? subPoint : firstSubPoint + subPoint; 3302 } 3303 3304 /* TODO: Fix this to properly propagate up error conditions it may find */ 3305 static inline PetscInt DMPlexFilterPointPerm_Internal(PetscInt point, PetscInt firstSubPoint, PetscInt numSubPoints, const PetscInt subPoints[], const PetscInt subIndices[]) 3306 { 3307 PetscInt subPoint; 3308 PetscErrorCode ierr; 3309 3310 ierr = PetscFindInt(point, numSubPoints, subPoints, &subPoint); 3311 if (ierr) return -1; 3312 return subPoint < 0 ? subPoint : firstSubPoint + (subIndices ? subIndices[subPoint] : subPoint); 3313 } 3314 3315 static PetscErrorCode DMPlexFilterLabels_Internal(DM dm, const PetscInt numSubPoints[], const PetscInt *subpoints[], const PetscInt firstSubPoint[], DM subdm) 3316 { 3317 DMLabel depthLabel; 3318 PetscInt Nl, l, d; 3319 3320 PetscFunctionBegin; 3321 // Reset depth label for fast lookup 3322 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 3323 PetscCall(DMLabelMakeAllInvalid_Internal(depthLabel)); 3324 PetscCall(DMGetNumLabels(dm, &Nl)); 3325 for (l = 0; l < Nl; ++l) { 3326 DMLabel label, newlabel; 3327 const char *lname; 3328 PetscBool isDepth, isDim, isCelltype, isVTK; 3329 IS valueIS; 3330 const PetscInt *values; 3331 PetscInt Nv, v; 3332 3333 PetscCall(DMGetLabelName(dm, l, &lname)); 3334 PetscCall(PetscStrcmp(lname, "depth", &isDepth)); 3335 PetscCall(PetscStrcmp(lname, "dim", &isDim)); 3336 PetscCall(PetscStrcmp(lname, "celltype", &isCelltype)); 3337 PetscCall(PetscStrcmp(lname, "vtk", &isVTK)); 3338 if (isDepth || isDim || isCelltype || isVTK) continue; 3339 PetscCall(DMCreateLabel(subdm, lname)); 3340 PetscCall(DMGetLabel(dm, lname, &label)); 3341 PetscCall(DMGetLabel(subdm, lname, &newlabel)); 3342 PetscCall(DMLabelGetDefaultValue(label, &v)); 3343 PetscCall(DMLabelSetDefaultValue(newlabel, v)); 3344 PetscCall(DMLabelGetValueIS(label, &valueIS)); 3345 PetscCall(ISGetLocalSize(valueIS, &Nv)); 3346 PetscCall(ISGetIndices(valueIS, &values)); 3347 for (v = 0; v < Nv; ++v) { 3348 IS pointIS; 3349 const PetscInt *points; 3350 PetscInt Np, p; 3351 3352 PetscCall(DMLabelGetStratumIS(label, values[v], &pointIS)); 3353 PetscCall(ISGetLocalSize(pointIS, &Np)); 3354 PetscCall(ISGetIndices(pointIS, &points)); 3355 for (p = 0; p < Np; ++p) { 3356 const PetscInt point = points[p]; 3357 PetscInt subp, subdepth; 3358 3359 PetscCall(DMPlexGetPointDepth(dm, point, &d)); 3360 PetscCall(DMPlexGetDepth(subdm, &subdepth)); 3361 if (d > subdepth) continue; 3362 subp = DMPlexFilterPoint_Internal(point, firstSubPoint[d], numSubPoints[d], subpoints[d]); 3363 if (subp >= 0) PetscCall(DMLabelSetValue(newlabel, subp, values[v])); 3364 } 3365 PetscCall(ISRestoreIndices(pointIS, &points)); 3366 PetscCall(ISDestroy(&pointIS)); 3367 } 3368 PetscCall(ISRestoreIndices(valueIS, &values)); 3369 PetscCall(ISDestroy(&valueIS)); 3370 } 3371 PetscFunctionReturn(PETSC_SUCCESS); 3372 } 3373 3374 static PetscErrorCode DMPlexCreateSubmeshGeneric_Interpolated(DM dm, DMLabel label, PetscInt value, PetscBool markedFaces, PetscBool isCohesive, PetscInt cellHeight, PetscBool ignoreLabelHalo, PetscBool sanitizeSubmesh, PetscSF *ownershipTransferSF, DM subdm) 3375 { 3376 MPI_Comm comm; 3377 DMLabel subpointMap; 3378 IS *subpointIS; 3379 const PetscInt **subpoints; 3380 PetscInt *numSubPoints, *firstSubPoint, *coneNew, *orntNew; 3381 PetscInt totSubPoints = 0, maxConeSize, dim, sdim, cdim, p, d, coordinate_type; 3382 PetscMPIInt rank; 3383 3384 PetscFunctionBegin; 3385 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 3386 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 3387 /* Create subpointMap which marks the submesh */ 3388 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "subpoint_map", &subpointMap)); 3389 PetscCall(DMPlexSetSubpointMap(subdm, subpointMap)); 3390 if (cellHeight) { 3391 if (isCohesive) PetscCall(DMPlexMarkCohesiveSubmesh_Interpolated(dm, label, value, subpointMap, subdm)); 3392 else PetscCall(DMPlexMarkSubmesh_Interpolated(dm, label, value, markedFaces, PETSC_TRUE, subpointMap, subdm)); 3393 } else { 3394 DMLabel depth; 3395 IS pointIS; 3396 const PetscInt *points; 3397 PetscInt numPoints = 0, pStart = 0; 3398 PetscBool *isGhost = NULL; 3399 3400 PetscCall(DMPlexGetDepthLabel(dm, &depth)); 3401 PetscCall(DMLabelGetStratumIS(label, value, &pointIS)); 3402 if (pointIS) { 3403 PetscCall(ISGetIndices(pointIS, &points)); 3404 PetscCall(ISGetLocalSize(pointIS, &numPoints)); 3405 } 3406 if (ignoreLabelHalo) { 3407 PetscSF pointSF; 3408 PetscInt nleaves, pEnd; 3409 const PetscInt *ilocal = NULL; 3410 3411 PetscCall(DMGetPointSF(dm, &pointSF)); 3412 PetscCall(PetscSFGetGraph(pointSF, NULL, &nleaves, &ilocal, NULL)); 3413 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3414 PetscCall(PetscMalloc1(pEnd - pStart, &isGhost)); 3415 for (p = 0; p < pEnd - pStart; ++p) isGhost[p] = PETSC_FALSE; 3416 for (p = 0; p < nleaves; ++p) isGhost[(ilocal ? ilocal[p] : p) - pStart] = PETSC_TRUE; 3417 } 3418 for (p = 0; p < numPoints; ++p) { 3419 PetscInt *closure = NULL; 3420 PetscInt closureSize, c, pdim; 3421 3422 if (ignoreLabelHalo && isGhost[points[p] - pStart]) continue; 3423 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closure)); 3424 for (c = 0; c < closureSize * 2; c += 2) { 3425 PetscCall(DMLabelGetValue(depth, closure[c], &pdim)); 3426 PetscCall(DMLabelSetValue(subpointMap, closure[c], pdim)); 3427 } 3428 PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closure)); 3429 } 3430 PetscCall(PetscFree(isGhost)); 3431 if (pointIS) PetscCall(ISRestoreIndices(pointIS, &points)); 3432 PetscCall(ISDestroy(&pointIS)); 3433 } 3434 /* Setup chart */ 3435 PetscCall(DMGetDimension(dm, &dim)); 3436 PetscCall(DMGetCoordinateDim(dm, &cdim)); 3437 PetscCall(PetscMalloc4(dim + 1, &numSubPoints, dim + 1, &firstSubPoint, dim + 1, &subpointIS, dim + 1, &subpoints)); 3438 for (d = 0; d <= dim; ++d) { 3439 PetscCall(DMLabelGetStratumSize(subpointMap, d, &numSubPoints[d])); 3440 totSubPoints += numSubPoints[d]; 3441 } 3442 // Determine submesh dimension 3443 PetscCall(DMGetDimension(subdm, &sdim)); 3444 if (sdim > 0) { 3445 // Calling function knows what dimension to use, and we include neighboring cells as well 3446 sdim = dim; 3447 } else { 3448 // We reset the subdimension based on what is being selected 3449 PetscInt lsdim; 3450 for (lsdim = dim; lsdim >= 0; --lsdim) 3451 if (numSubPoints[lsdim]) break; 3452 PetscCallMPI(MPIU_Allreduce(&lsdim, &sdim, 1, MPIU_INT, MPI_MAX, comm)); 3453 PetscCall(DMSetDimension(subdm, sdim)); 3454 PetscCall(DMSetCoordinateDim(subdm, cdim)); 3455 } 3456 PetscCall(DMPlexSetChart(subdm, 0, totSubPoints)); 3457 PetscCall(DMPlexSetVTKCellHeight(subdm, cellHeight)); 3458 /* Set cone sizes */ 3459 firstSubPoint[sdim] = 0; 3460 firstSubPoint[0] = firstSubPoint[sdim] + numSubPoints[sdim]; 3461 if (sdim > 1) firstSubPoint[sdim - 1] = firstSubPoint[0] + numSubPoints[0]; 3462 if (sdim > 2) firstSubPoint[sdim - 2] = firstSubPoint[sdim - 1] + numSubPoints[sdim - 1]; 3463 for (d = 0; d <= sdim; ++d) { 3464 PetscCall(DMLabelGetStratumIS(subpointMap, d, &subpointIS[d])); 3465 if (subpointIS[d]) PetscCall(ISGetIndices(subpointIS[d], &subpoints[d])); 3466 } 3467 /* We do not want this label automatically computed, instead we compute it here */ 3468 PetscCall(DMCreateLabel(subdm, "celltype")); 3469 for (d = 0; d <= sdim; ++d) { 3470 for (p = 0; p < numSubPoints[d]; ++p) { 3471 const PetscInt point = subpoints[d][p]; 3472 const PetscInt subpoint = firstSubPoint[d] + p; 3473 const PetscInt *cone; 3474 PetscInt coneSize; 3475 3476 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 3477 if (cellHeight && (d == sdim)) { 3478 PetscInt coneSizeNew, c, val; 3479 3480 PetscCall(DMPlexGetCone(dm, point, &cone)); 3481 for (c = 0, coneSizeNew = 0; c < coneSize; ++c) { 3482 PetscCall(DMLabelGetValue(subpointMap, cone[c], &val)); 3483 if (val >= 0) coneSizeNew++; 3484 } 3485 PetscCall(DMPlexSetConeSize(subdm, subpoint, coneSizeNew)); 3486 PetscCall(DMPlexSetCellType(subdm, subpoint, DM_POLYTOPE_FV_GHOST)); 3487 } else { 3488 DMPolytopeType ct; 3489 3490 PetscCall(DMPlexSetConeSize(subdm, subpoint, coneSize)); 3491 PetscCall(DMPlexGetCellType(dm, point, &ct)); 3492 PetscCall(DMPlexSetCellType(subdm, subpoint, ct)); 3493 } 3494 } 3495 } 3496 PetscCall(DMLabelDestroy(&subpointMap)); 3497 PetscCall(DMSetUp(subdm)); 3498 /* Set cones */ 3499 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, NULL)); 3500 PetscCall(PetscMalloc2(maxConeSize, &coneNew, maxConeSize, &orntNew)); 3501 for (d = 0; d <= sdim; ++d) { 3502 for (p = 0; p < numSubPoints[d]; ++p) { 3503 const PetscInt point = subpoints[d][p]; 3504 const PetscInt subpoint = firstSubPoint[d] + p; 3505 const PetscInt *cone, *ornt; 3506 PetscInt coneSize, subconeSize, coneSizeNew, c, subc, fornt = 0; 3507 3508 if (d == sdim - 1) { 3509 const PetscInt *support, *cone, *ornt; 3510 PetscInt supportSize, coneSize, s, subc; 3511 3512 PetscCall(DMPlexGetSupport(dm, point, &support)); 3513 PetscCall(DMPlexGetSupportSize(dm, point, &supportSize)); 3514 for (s = 0; s < supportSize; ++s) { 3515 PetscBool isHybrid = PETSC_FALSE; 3516 3517 PetscCall(DMPlexCellIsHybrid_Internal(dm, support[s], &isHybrid)); 3518 if (!isHybrid) continue; 3519 PetscCall(PetscFindInt(support[s], numSubPoints[d + 1], subpoints[d + 1], &subc)); 3520 if (subc >= 0) { 3521 const PetscInt ccell = subpoints[d + 1][subc]; 3522 3523 PetscCall(DMPlexGetCone(dm, ccell, &cone)); 3524 PetscCall(DMPlexGetConeSize(dm, ccell, &coneSize)); 3525 PetscCall(DMPlexGetConeOrientation(dm, ccell, &ornt)); 3526 for (c = 0; c < coneSize; ++c) { 3527 if (cone[c] == point) { 3528 fornt = ornt[c]; 3529 break; 3530 } 3531 } 3532 break; 3533 } 3534 } 3535 } 3536 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 3537 PetscCall(DMPlexGetConeSize(subdm, subpoint, &subconeSize)); 3538 PetscCall(DMPlexGetCone(dm, point, &cone)); 3539 PetscCall(DMPlexGetConeOrientation(dm, point, &ornt)); 3540 for (c = 0, coneSizeNew = 0; c < coneSize; ++c) { 3541 PetscCall(PetscFindInt(cone[c], numSubPoints[d - 1], subpoints[d - 1], &subc)); 3542 if (subc >= 0) { 3543 coneNew[coneSizeNew] = firstSubPoint[d - 1] + subc; 3544 orntNew[coneSizeNew] = ornt[c]; 3545 ++coneSizeNew; 3546 } 3547 } 3548 PetscCheck(coneSizeNew == subconeSize, comm, PETSC_ERR_PLIB, "Number of cone points located %" PetscInt_FMT " does not match subcone size %" PetscInt_FMT, coneSizeNew, subconeSize); 3549 PetscCall(DMPlexSetCone(subdm, subpoint, coneNew)); 3550 PetscCall(DMPlexSetConeOrientation(subdm, subpoint, orntNew)); 3551 if (fornt < 0) PetscCall(DMPlexOrientPoint(subdm, subpoint, fornt)); 3552 } 3553 } 3554 PetscCall(PetscFree2(coneNew, orntNew)); 3555 PetscCall(DMPlexSymmetrize(subdm)); 3556 PetscCall(DMPlexStratify(subdm)); 3557 /* Build coordinates */ 3558 for (coordinate_type = 0; coordinate_type < 2; ++coordinate_type) { 3559 DM coordDM = NULL, subCoordDM = NULL; 3560 PetscSection coordSection = NULL, subCoordSection = NULL; 3561 Vec coordinates = NULL, subCoordinates = NULL; 3562 PetscScalar *coords = NULL, *subCoords = NULL; 3563 PetscInt bs, numComp, coordSize, firstP, lastP, firstSubP = totSubPoints, lastSubP = -1, numFields; 3564 const char *name; 3565 PetscBool localized = (PetscBool)coordinate_type; 3566 3567 if (!dm->coordinates[coordinate_type].dm) continue; 3568 if (!localized) { 3569 PetscCall(DMGetCoordinateDM(dm, &coordDM)); 3570 PetscCall(DMGetCoordinateDM(subdm, &subCoordDM)); 3571 } else { 3572 { 3573 PetscInt localizationHeight; 3574 PetscBool sparseLocalize; 3575 3576 PetscCall(DMGetSparseLocalize(dm, &sparseLocalize)); 3577 PetscCall(DMSetSparseLocalize(subdm, sparseLocalize)); 3578 PetscCall(DMGetCoordinateDM(dm, &coordDM)); 3579 PetscCall(DMGetCoordinateDM(subdm, &subCoordDM)); 3580 PetscCall(DMPlexGetMaxProjectionHeight(coordDM, &localizationHeight)); 3581 PetscCall(DMPlexSetMaxProjectionHeight(subCoordDM, localizationHeight - (dim - sdim) - cellHeight)); 3582 PetscUseTypeMethod(subdm, createcellcoordinatedm, &subCoordDM); 3583 PetscCall(DMSetCellCoordinateDM(subdm, subCoordDM)); 3584 PetscCall(DMDestroy(&subCoordDM)); 3585 } 3586 PetscCall(DMGetCellCoordinateDM(dm, &coordDM)); 3587 PetscCall(DMGetCellCoordinateDM(subdm, &subCoordDM)); 3588 } 3589 PetscCall(DMGetNumFields(coordDM, &numFields)); 3590 if (numFields > 0) { 3591 PetscFE fe = NULL; 3592 PetscSpace P = NULL; 3593 PetscClassId id; 3594 PetscInt degree; 3595 3596 PetscCall(DMGetField(coordDM, 0, NULL, (PetscObject *)&fe)); 3597 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 3598 if (id == PETSCFE_CLASSID) { 3599 if (sdim == dim && cellHeight == 0) { 3600 /* TODO: Handle Field labels correctly */ 3601 PetscCall(DMSetField(subCoordDM, 0, NULL, (PetscObject)fe)); 3602 PetscCall(DMCreateDS(subCoordDM)); 3603 } else { 3604 /* TODO: Reconstruct the lower-dimensional FE more robustly */ 3605 PetscCall(PetscFEGetBasisSpace(fe, &P)); 3606 PetscCall(PetscSpaceGetDegree(P, °ree, NULL)); 3607 PetscCall(DMPlexCreateCoordinateSpace(subdm, degree, localized, PETSC_FALSE)); 3608 } 3609 } 3610 } 3611 if (!localized) { 3612 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 3613 PetscCall(DMGetCoordinateSection(subdm, &subCoordSection)); 3614 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 3615 } else { 3616 PetscCall(DMGetCellCoordinateSection(dm, &coordSection)); 3617 PetscCall(DMGetCellCoordinateSection(subdm, &subCoordSection)); 3618 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinates)); 3619 } 3620 PetscCall(PetscSectionSetNumFields(subCoordSection, 1)); 3621 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &numComp)); 3622 PetscCall(PetscSectionSetFieldComponents(subCoordSection, 0, numComp)); 3623 PetscCall(PetscSectionGetChart(coordSection, &firstP, &lastP)); 3624 for (d = 0; d <= sdim; ++d) { 3625 for (p = 0; p < numSubPoints[d]; ++p) { 3626 const PetscInt point = subpoints[d][p]; 3627 const PetscInt subpoint = firstSubPoint[d] + p; 3628 3629 if (point >= firstP && point < lastP) { 3630 firstSubP = PetscMin(firstSubP, subpoint); 3631 lastSubP = PetscMax(lastSubP, subpoint); 3632 } 3633 } 3634 } 3635 lastSubP += 1; 3636 if (firstSubP == totSubPoints) { 3637 /* Zero if there is no coordinate point. */ 3638 firstSubP = 0; 3639 lastSubP = 0; 3640 } 3641 PetscCall(PetscSectionSetChart(subCoordSection, firstSubP, lastSubP)); 3642 for (d = 0; d <= sdim; ++d) { 3643 for (p = 0; p < numSubPoints[d]; ++p) { 3644 const PetscInt point = subpoints[d][p]; 3645 const PetscInt subpoint = firstSubPoint[d] + p; 3646 PetscInt dof; 3647 3648 if (point >= firstP && point < lastP) { 3649 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 3650 PetscCall(PetscSectionSetDof(subCoordSection, subpoint, dof)); 3651 PetscCall(PetscSectionSetFieldDof(subCoordSection, subpoint, 0, dof)); 3652 } 3653 } 3654 } 3655 PetscCall(PetscSectionSetUp(subCoordSection)); 3656 PetscCall(PetscSectionGetStorageSize(subCoordSection, &coordSize)); 3657 PetscCall(VecCreate(PETSC_COMM_SELF, &subCoordinates)); 3658 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 3659 PetscCall(PetscObjectSetName((PetscObject)subCoordinates, name)); 3660 PetscCall(VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE)); 3661 PetscCall(VecGetBlockSize(coordinates, &bs)); 3662 PetscCall(VecSetBlockSize(subCoordinates, bs)); 3663 PetscCall(VecSetType(subCoordinates, VECSTANDARD)); 3664 PetscCall(VecGetArray(coordinates, &coords)); 3665 PetscCall(VecGetArray(subCoordinates, &subCoords)); 3666 for (d = 0; d <= sdim; ++d) { 3667 for (p = 0; p < numSubPoints[d]; ++p) { 3668 const PetscInt point = subpoints[d][p]; 3669 const PetscInt subpoint = firstSubPoint[d] + p; 3670 PetscInt dof, off, sdof, soff, d; 3671 3672 if (point >= firstP && point < lastP) { 3673 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 3674 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 3675 PetscCall(PetscSectionGetDof(subCoordSection, subpoint, &sdof)); 3676 PetscCall(PetscSectionGetOffset(subCoordSection, subpoint, &soff)); 3677 PetscCheck(dof == sdof, comm, PETSC_ERR_PLIB, "Coordinate dimension %" PetscInt_FMT " on subpoint %" PetscInt_FMT ", point %" PetscInt_FMT " should be %" PetscInt_FMT, sdof, subpoint, point, dof); 3678 for (d = 0; d < dof; ++d) subCoords[soff + d] = coords[off + d]; 3679 } 3680 } 3681 } 3682 PetscCall(VecRestoreArray(coordinates, &coords)); 3683 PetscCall(VecRestoreArray(subCoordinates, &subCoords)); 3684 switch (coordinate_type) { 3685 case 0: 3686 PetscCall(DMSetCoordinatesLocal(subdm, subCoordinates)); 3687 break; 3688 case 1: 3689 PetscCall(DMSetCellCoordinatesLocal(subdm, subCoordinates)); 3690 break; 3691 default: 3692 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "coordinate_type must be {0, 1}"); 3693 } 3694 PetscCall(VecDestroy(&subCoordinates)); 3695 } 3696 /* Build SF: We need this complexity because subpoints might not be selected on the owning process */ 3697 { 3698 PetscSF sfPoint, sfPointSub; 3699 IS subpIS; 3700 const PetscSFNode *remotePoints; 3701 PetscSFNode *sremotePoints = NULL, *newLocalPoints = NULL, *newOwners = NULL; 3702 const PetscInt *localPoints, *subpoints, *rootdegree; 3703 PetscInt *slocalPoints = NULL, *sortedPoints = NULL, *sortedIndices = NULL; 3704 PetscInt numRoots, numLeaves, numSubpoints = 0, numSubroots, numSubleaves = 0, l, sl = 0, ll = 0, pStart, pEnd, p; 3705 PetscMPIInt rank, size; 3706 3707 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 3708 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 3709 PetscCall(DMGetPointSF(dm, &sfPoint)); 3710 PetscCall(DMGetPointSF(subdm, &sfPointSub)); 3711 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3712 PetscCall(DMPlexGetChart(subdm, NULL, &numSubroots)); 3713 PetscCall(DMPlexGetSubpointIS(subdm, &subpIS)); 3714 if (subpIS) { 3715 PetscBool sorted = PETSC_TRUE; 3716 3717 PetscCall(ISGetIndices(subpIS, &subpoints)); 3718 PetscCall(ISGetLocalSize(subpIS, &numSubpoints)); 3719 for (p = 1; p < numSubpoints; ++p) sorted = sorted && (subpoints[p] >= subpoints[p - 1]) ? PETSC_TRUE : PETSC_FALSE; 3720 if (!sorted) { 3721 PetscCall(PetscMalloc2(numSubpoints, &sortedPoints, numSubpoints, &sortedIndices)); 3722 for (p = 0; p < numSubpoints; ++p) sortedIndices[p] = p; 3723 PetscCall(PetscArraycpy(sortedPoints, subpoints, numSubpoints)); 3724 PetscCall(PetscSortIntWithArray(numSubpoints, sortedPoints, sortedIndices)); 3725 } 3726 } 3727 PetscCall(PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints)); 3728 if (numRoots >= 0) { 3729 PetscCall(PetscSFComputeDegreeBegin(sfPoint, &rootdegree)); 3730 PetscCall(PetscSFComputeDegreeEnd(sfPoint, &rootdegree)); 3731 PetscCall(PetscMalloc2(pEnd - pStart, &newLocalPoints, numRoots, &newOwners)); 3732 for (p = 0; p < pEnd - pStart; ++p) { 3733 newLocalPoints[p].rank = -2; 3734 newLocalPoints[p].index = -2; 3735 } 3736 for (p = pStart; p < pEnd; ++p) { 3737 newOwners[p - pStart].rank = -3; 3738 newOwners[p - pStart].index = -3; 3739 } 3740 if (sanitizeSubmesh) { 3741 /* A subpoint is forced to be owned by a rank that owns */ 3742 /* a subcell that contains the subpoint in its closure. */ 3743 PetscInt cStart, cEnd, c, clSize, cl; 3744 PetscInt *ownedCells, *closure = NULL; 3745 3746 /* claim ownership */ 3747 for (p = 0; p < numSubpoints; ++p) { 3748 const PetscInt point = subpoints[p]; 3749 3750 newLocalPoints[point - pStart].rank = rank; 3751 newLocalPoints[point - pStart].index = p; 3752 } 3753 PetscCall(DMGetDimension(subdm, &sdim)); 3754 PetscCall(DMPlexGetDepthStratum(dm, sdim, &cStart, &cEnd)); 3755 PetscCall(PetscMalloc1(cEnd - cStart, &ownedCells)); 3756 for (c = cStart; c < cEnd; ++c) ownedCells[c - cStart] = 0; 3757 for (p = 0; p < numSubpoints; ++p) { 3758 c = subpoints[p]; 3759 if (c >= cStart && c < cEnd) ownedCells[c - cStart] = 1; 3760 } 3761 for (l = 0; l < numLeaves; ++l) { 3762 c = localPoints ? localPoints[l] : l; 3763 if (c >= cStart && c < cEnd) ownedCells[c - cStart] = 0; 3764 } 3765 for (c = cStart; c < cEnd; ++c) { 3766 if (ownedCells[c - cStart] == 0) continue; 3767 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 3768 for (cl = 0; cl < clSize * 2; cl += 2) { 3769 p = closure[cl]; 3770 if (newLocalPoints[p - pStart].rank < size) newLocalPoints[p - pStart].rank += size; 3771 } 3772 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 3773 } 3774 PetscCall(PetscFree(ownedCells)); 3775 for (p = 0; p < numRoots; ++p) { 3776 newOwners[p].rank = newLocalPoints[p].rank; 3777 newOwners[p].index = newLocalPoints[p].index; 3778 } 3779 } else { 3780 /* Set subleaves */ 3781 for (l = 0; l < numLeaves; ++l) { 3782 const PetscInt point = localPoints[l]; 3783 const PetscInt subpoint = DMPlexFilterPointPerm_Internal(point, 0, numSubpoints, sortedPoints ? sortedPoints : subpoints, sortedIndices); 3784 3785 if (subpoint < 0) continue; 3786 newLocalPoints[point - pStart].rank = rank; 3787 newLocalPoints[point - pStart].index = subpoint; 3788 ++numSubleaves; 3789 } 3790 /* Must put in owned subpoints */ 3791 for (p = 0; p < numSubpoints; ++p) { 3792 /* Hold on to currently owned points */ 3793 if (rootdegree[subpoints[p] - pStart]) newOwners[subpoints[p] - pStart].rank = rank + size; 3794 else newOwners[subpoints[p] - pStart].rank = rank; 3795 newOwners[subpoints[p] - pStart].index = p; 3796 } 3797 } 3798 PetscCall(PetscSFReduceBegin(sfPoint, MPIU_SF_NODE, newLocalPoints, newOwners, MPI_MAXLOC)); 3799 PetscCall(PetscSFReduceEnd(sfPoint, MPIU_SF_NODE, newLocalPoints, newOwners, MPI_MAXLOC)); 3800 for (p = pStart; p < pEnd; ++p) 3801 if (newOwners[p - pStart].rank >= size) newOwners[p - pStart].rank -= size; 3802 if (ownershipTransferSF) { 3803 PetscSFNode *iremote1 = NULL, *newOwners1 = NULL; 3804 PetscInt *ilocal1 = NULL; 3805 PetscInt nleaves1, point; 3806 3807 for (p = 0; p < numSubpoints; ++p) { 3808 point = subpoints[p]; 3809 newLocalPoints[point - pStart].index = point; 3810 } 3811 PetscCall(PetscMalloc1(numRoots, &newOwners1)); 3812 for (p = 0; p < numRoots; ++p) { 3813 newOwners1[p].rank = -1; 3814 newOwners1[p].index = -1; 3815 } 3816 PetscCall(PetscSFReduceBegin(sfPoint, MPIU_SF_NODE, newLocalPoints, newOwners1, MPI_MAXLOC)); 3817 PetscCall(PetscSFReduceEnd(sfPoint, MPIU_SF_NODE, newLocalPoints, newOwners1, MPI_MAXLOC)); 3818 for (p = 0, nleaves1 = 0; p < numRoots; ++p) { 3819 if (newOwners[p].rank >= 0 && newOwners[p].rank != rank) ++nleaves1; 3820 } 3821 PetscCall(PetscMalloc1(nleaves1, &ilocal1)); 3822 PetscCall(PetscMalloc1(nleaves1, &iremote1)); 3823 for (p = 0, nleaves1 = 0; p < numRoots; ++p) { 3824 if (newOwners[p].rank >= 0 && newOwners[p].rank != rank) { 3825 ilocal1[nleaves1] = pStart + p; 3826 iremote1[nleaves1].rank = newOwners[p].rank; 3827 iremote1[nleaves1].index = newOwners1[p].index; 3828 ++nleaves1; 3829 } 3830 } 3831 PetscCall(PetscFree(newOwners1)); 3832 PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)sfPoint), ownershipTransferSF)); 3833 PetscCall(PetscSFSetFromOptions(*ownershipTransferSF)); 3834 PetscCall(PetscSFSetGraph(*ownershipTransferSF, pEnd - pStart, nleaves1, ilocal1, PETSC_OWN_POINTER, iremote1, PETSC_OWN_POINTER)); 3835 } 3836 if (sanitizeSubmesh) { 3837 for (p = pStart; p < pEnd; ++p) { 3838 newLocalPoints[p - pStart].rank = newOwners[p - pStart].rank; 3839 newLocalPoints[p - pStart].index = newOwners[p - pStart].index; 3840 } 3841 } 3842 PetscCall(PetscSFBcastBegin(sfPoint, MPIU_SF_NODE, newOwners, newLocalPoints, MPI_REPLACE)); 3843 PetscCall(PetscSFBcastEnd(sfPoint, MPIU_SF_NODE, newOwners, newLocalPoints, MPI_REPLACE)); 3844 if (sanitizeSubmesh) { 3845 for (p = 0; p < numSubpoints; ++p) { 3846 const PetscInt point = subpoints[p]; 3847 3848 if (newLocalPoints[point - pStart].rank >= 0 && newLocalPoints[point - pStart].rank != rank) ++sl; 3849 } 3850 PetscCall(PetscMalloc1(sl, &slocalPoints)); 3851 PetscCall(PetscMalloc1(sl, &sremotePoints)); 3852 for (p = 0, sl = 0; p < numSubpoints; ++p) { 3853 const PetscInt point = subpoints[p]; 3854 3855 if (newLocalPoints[point - pStart].rank >= 0 && newLocalPoints[point - pStart].rank != rank) { 3856 slocalPoints[sl] = p; 3857 sremotePoints[sl].rank = newLocalPoints[point - pStart].rank; 3858 sremotePoints[sl].index = newLocalPoints[point - pStart].index; 3859 PetscCheck(sremotePoints[sl].rank >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid remote rank"); 3860 PetscCheck(sremotePoints[sl].index >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid remote subpoint"); 3861 ++sl; 3862 } 3863 } 3864 } else { 3865 PetscCall(PetscMalloc1(numSubleaves, &slocalPoints)); 3866 PetscCall(PetscMalloc1(numSubleaves, &sremotePoints)); 3867 for (l = 0; l < numLeaves; ++l) { 3868 const PetscInt point = localPoints[l]; 3869 const PetscInt subpoint = DMPlexFilterPointPerm_Internal(point, 0, numSubpoints, sortedPoints ? sortedPoints : subpoints, sortedIndices); 3870 3871 if (subpoint < 0) continue; 3872 if (newLocalPoints[point].rank == rank) { 3873 ++ll; 3874 continue; 3875 } 3876 slocalPoints[sl] = subpoint; 3877 sremotePoints[sl].rank = newLocalPoints[point].rank; 3878 sremotePoints[sl].index = newLocalPoints[point].index; 3879 PetscCheck(sremotePoints[sl].rank >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid remote rank for local point %" PetscInt_FMT, point); 3880 PetscCheck(sremotePoints[sl].index >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid remote subpoint for local point %" PetscInt_FMT, point); 3881 ++sl; 3882 } 3883 PetscCheck(sl + ll == numSubleaves, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatch in number of subleaves %" PetscInt_FMT " + %" PetscInt_FMT " != %" PetscInt_FMT, sl, ll, numSubleaves); 3884 } 3885 PetscCall(PetscFree2(newLocalPoints, newOwners)); 3886 PetscCall(PetscSFSetGraph(sfPointSub, numSubroots, sl, slocalPoints, PETSC_OWN_POINTER, sremotePoints, PETSC_OWN_POINTER)); 3887 } 3888 if (subpIS) PetscCall(ISRestoreIndices(subpIS, &subpoints)); 3889 PetscCall(PetscFree2(sortedPoints, sortedIndices)); 3890 } 3891 /* Filter labels */ 3892 PetscCall(DMPlexFilterLabels_Internal(dm, numSubPoints, subpoints, firstSubPoint, subdm)); 3893 /* Cleanup */ 3894 for (d = 0; d <= sdim; ++d) { 3895 if (subpointIS[d]) PetscCall(ISRestoreIndices(subpointIS[d], &subpoints[d])); 3896 PetscCall(ISDestroy(&subpointIS[d])); 3897 } 3898 PetscCall(PetscFree4(numSubPoints, firstSubPoint, subpointIS, subpoints)); 3899 PetscFunctionReturn(PETSC_SUCCESS); 3900 } 3901 3902 static PetscErrorCode DMPlexCreateSubmesh_Interpolated(DM dm, DMLabel vertexLabel, PetscInt value, PetscBool markedFaces, DM subdm) 3903 { 3904 PetscFunctionBegin; 3905 PetscCall(DMPlexCreateSubmeshGeneric_Interpolated(dm, vertexLabel, value, markedFaces, PETSC_FALSE, 1, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 3906 PetscFunctionReturn(PETSC_SUCCESS); 3907 } 3908 3909 /*@ 3910 DMPlexCreateSubmesh - Extract a hypersurface from the mesh using vertices defined by a label 3911 3912 Input Parameters: 3913 + dm - The original mesh 3914 . vertexLabel - The `DMLabel` marking points contained in the surface 3915 . value - The label value to use 3916 - markedFaces - `PETSC_TRUE` if surface faces are marked in addition to vertices, `PETSC_FALSE` if only vertices are marked 3917 3918 Output Parameter: 3919 . subdm - The surface mesh 3920 3921 Level: developer 3922 3923 Note: 3924 This function produces a `DMLabel` mapping original points in the submesh to their depth. This can be obtained using `DMPlexGetSubpointMap()`. 3925 3926 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSubpointMap()`, `DMGetLabel()`, `DMLabelSetValue()` 3927 @*/ 3928 PetscErrorCode DMPlexCreateSubmesh(DM dm, DMLabel vertexLabel, PetscInt value, PetscBool markedFaces, DM *subdm) 3929 { 3930 DMPlexInterpolatedFlag interpolated; 3931 PetscInt dim, cdim; 3932 3933 PetscFunctionBegin; 3934 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3935 PetscAssertPointer(subdm, 5); 3936 PetscCall(DMGetDimension(dm, &dim)); 3937 PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), subdm)); 3938 PetscCall(DMSetType(*subdm, DMPLEX)); 3939 PetscCall(DMSetDimension(*subdm, dim - 1)); 3940 PetscCall(DMGetCoordinateDim(dm, &cdim)); 3941 PetscCall(DMSetCoordinateDim(*subdm, cdim)); 3942 PetscCall(DMPlexIsInterpolated(dm, &interpolated)); 3943 PetscCheck(interpolated != DMPLEX_INTERPOLATED_PARTIAL, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not for partially interpolated meshes"); 3944 if (interpolated) { 3945 PetscCall(DMPlexCreateSubmesh_Interpolated(dm, vertexLabel, value, markedFaces, *subdm)); 3946 } else { 3947 PetscCall(DMPlexCreateSubmesh_Uninterpolated(dm, vertexLabel, value, *subdm)); 3948 } 3949 PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_TRUE, *subdm)); 3950 PetscFunctionReturn(PETSC_SUCCESS); 3951 } 3952 3953 static PetscErrorCode DMPlexCreateCohesiveSubmesh_Uninterpolated(DM dm, PetscBool hasLagrange, const char label[], PetscInt value, DM subdm) 3954 { 3955 MPI_Comm comm; 3956 DMLabel subpointMap; 3957 IS subvertexIS; 3958 const PetscInt *subVertices; 3959 PetscInt numSubVertices, firstSubVertex, numSubCells, *subCells = NULL; 3960 PetscInt *subface, maxConeSize, numSubFaces, firstSubFace, newFacePoint, nFV; 3961 PetscInt c, f; 3962 3963 PetscFunctionBegin; 3964 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 3965 /* Create subpointMap which marks the submesh */ 3966 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "subpoint_map", &subpointMap)); 3967 PetscCall(DMPlexSetSubpointMap(subdm, subpointMap)); 3968 PetscCall(DMPlexMarkCohesiveSubmesh_Uninterpolated(dm, hasLagrange, label, value, subpointMap, &numSubFaces, &nFV, &subCells, subdm)); 3969 /* Setup chart */ 3970 PetscCall(DMLabelGetStratumSize(subpointMap, 0, &numSubVertices)); 3971 PetscCall(DMLabelGetStratumSize(subpointMap, 2, &numSubCells)); 3972 PetscCall(DMPlexSetChart(subdm, 0, numSubCells + numSubFaces + numSubVertices)); 3973 PetscCall(DMPlexSetVTKCellHeight(subdm, 1)); 3974 /* Set cone sizes */ 3975 firstSubVertex = numSubCells; 3976 firstSubFace = numSubCells + numSubVertices; 3977 newFacePoint = firstSubFace; 3978 PetscCall(DMLabelGetStratumIS(subpointMap, 0, &subvertexIS)); 3979 if (subvertexIS) PetscCall(ISGetIndices(subvertexIS, &subVertices)); 3980 for (c = 0; c < numSubCells; ++c) PetscCall(DMPlexSetConeSize(subdm, c, 1)); 3981 for (f = firstSubFace; f < firstSubFace + numSubFaces; ++f) PetscCall(DMPlexSetConeSize(subdm, f, nFV)); 3982 PetscCall(DMSetUp(subdm)); 3983 PetscCall(DMLabelDestroy(&subpointMap)); 3984 /* Create face cones */ 3985 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, NULL)); 3986 PetscCall(DMGetWorkArray(subdm, maxConeSize, MPIU_INT, (void **)&subface)); 3987 for (c = 0; c < numSubCells; ++c) { 3988 const PetscInt cell = subCells[c]; 3989 const PetscInt subcell = c; 3990 const PetscInt *cone, *cells; 3991 PetscBool isHybrid = PETSC_FALSE; 3992 PetscInt numCells, subVertex, p, v; 3993 3994 PetscCall(DMPlexCellIsHybrid_Internal(dm, cell, &isHybrid)); 3995 if (!isHybrid) continue; 3996 PetscCall(DMPlexGetCone(dm, cell, &cone)); 3997 for (v = 0; v < nFV; ++v) { 3998 PetscCall(PetscFindInt(cone[v], numSubVertices, subVertices, &subVertex)); 3999 subface[v] = firstSubVertex + subVertex; 4000 } 4001 PetscCall(DMPlexSetCone(subdm, newFacePoint, subface)); 4002 PetscCall(DMPlexSetCone(subdm, subcell, &newFacePoint)); 4003 PetscCall(DMPlexGetJoin(dm, nFV, cone, &numCells, &cells)); 4004 /* Not true in parallel 4005 PetscCheck(numCells == 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cohesive cells should separate two cells"); */ 4006 for (p = 0; p < numCells; ++p) { 4007 PetscInt negsubcell; 4008 PetscBool isHybrid = PETSC_FALSE; 4009 4010 PetscCall(DMPlexCellIsHybrid_Internal(dm, cells[p], &isHybrid)); 4011 if (isHybrid) continue; 4012 /* I know this is a crap search */ 4013 for (negsubcell = 0; negsubcell < numSubCells; ++negsubcell) { 4014 if (subCells[negsubcell] == cells[p]) break; 4015 } 4016 PetscCheck(negsubcell != numSubCells, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find negative face neighbor for cohesive cell %" PetscInt_FMT, cell); 4017 PetscCall(DMPlexSetCone(subdm, negsubcell, &newFacePoint)); 4018 } 4019 PetscCall(DMPlexRestoreJoin(dm, nFV, cone, &numCells, &cells)); 4020 ++newFacePoint; 4021 } 4022 PetscCall(DMRestoreWorkArray(subdm, maxConeSize, MPIU_INT, (void **)&subface)); 4023 PetscCall(DMPlexSymmetrize(subdm)); 4024 PetscCall(DMPlexStratify(subdm)); 4025 /* Build coordinates */ 4026 { 4027 PetscSection coordSection, subCoordSection; 4028 Vec coordinates, subCoordinates; 4029 PetscScalar *coords, *subCoords; 4030 PetscInt cdim, numComp, coordSize, v; 4031 const char *name; 4032 4033 PetscCall(DMGetCoordinateDim(dm, &cdim)); 4034 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 4035 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 4036 PetscCall(DMGetCoordinateSection(subdm, &subCoordSection)); 4037 PetscCall(PetscSectionSetNumFields(subCoordSection, 1)); 4038 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &numComp)); 4039 PetscCall(PetscSectionSetFieldComponents(subCoordSection, 0, numComp)); 4040 PetscCall(PetscSectionSetChart(subCoordSection, firstSubVertex, firstSubVertex + numSubVertices)); 4041 for (v = 0; v < numSubVertices; ++v) { 4042 const PetscInt vertex = subVertices[v]; 4043 const PetscInt subvertex = firstSubVertex + v; 4044 PetscInt dof; 4045 4046 PetscCall(PetscSectionGetDof(coordSection, vertex, &dof)); 4047 PetscCall(PetscSectionSetDof(subCoordSection, subvertex, dof)); 4048 PetscCall(PetscSectionSetFieldDof(subCoordSection, subvertex, 0, dof)); 4049 } 4050 PetscCall(PetscSectionSetUp(subCoordSection)); 4051 PetscCall(PetscSectionGetStorageSize(subCoordSection, &coordSize)); 4052 PetscCall(VecCreate(PETSC_COMM_SELF, &subCoordinates)); 4053 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 4054 PetscCall(PetscObjectSetName((PetscObject)subCoordinates, name)); 4055 PetscCall(VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE)); 4056 PetscCall(VecSetBlockSize(subCoordinates, cdim)); 4057 PetscCall(VecSetType(subCoordinates, VECSTANDARD)); 4058 PetscCall(VecGetArray(coordinates, &coords)); 4059 PetscCall(VecGetArray(subCoordinates, &subCoords)); 4060 for (v = 0; v < numSubVertices; ++v) { 4061 const PetscInt vertex = subVertices[v]; 4062 const PetscInt subvertex = firstSubVertex + v; 4063 PetscInt dof, off, sdof, soff, d; 4064 4065 PetscCall(PetscSectionGetDof(coordSection, vertex, &dof)); 4066 PetscCall(PetscSectionGetOffset(coordSection, vertex, &off)); 4067 PetscCall(PetscSectionGetDof(subCoordSection, subvertex, &sdof)); 4068 PetscCall(PetscSectionGetOffset(subCoordSection, subvertex, &soff)); 4069 PetscCheck(dof == sdof, comm, PETSC_ERR_PLIB, "Coordinate dimension %" PetscInt_FMT " on subvertex %" PetscInt_FMT ", vertex %" PetscInt_FMT " should be %" PetscInt_FMT, sdof, subvertex, vertex, dof); 4070 for (d = 0; d < dof; ++d) subCoords[soff + d] = coords[off + d]; 4071 } 4072 PetscCall(VecRestoreArray(coordinates, &coords)); 4073 PetscCall(VecRestoreArray(subCoordinates, &subCoords)); 4074 PetscCall(DMSetCoordinatesLocal(subdm, subCoordinates)); 4075 PetscCall(VecDestroy(&subCoordinates)); 4076 } 4077 /* Build SF */ 4078 CHKMEMQ; 4079 { 4080 PetscSF sfPoint, sfPointSub; 4081 const PetscSFNode *remotePoints; 4082 PetscSFNode *sremotePoints, *newLocalPoints, *newOwners; 4083 const PetscInt *localPoints; 4084 PetscInt *slocalPoints; 4085 PetscInt numRoots, numLeaves, numSubRoots = numSubCells + numSubFaces + numSubVertices, numSubLeaves = 0, l, sl, ll, pStart, pEnd, p, vStart, vEnd; 4086 PetscMPIInt rank; 4087 4088 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 4089 PetscCall(DMGetPointSF(dm, &sfPoint)); 4090 PetscCall(DMGetPointSF(subdm, &sfPointSub)); 4091 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4092 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 4093 PetscCall(PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints)); 4094 if (numRoots >= 0) { 4095 /* Only vertices should be shared */ 4096 PetscCall(PetscMalloc2(pEnd - pStart, &newLocalPoints, numRoots, &newOwners)); 4097 for (p = 0; p < pEnd - pStart; ++p) { 4098 newLocalPoints[p].rank = -2; 4099 newLocalPoints[p].index = -2; 4100 } 4101 /* Set subleaves */ 4102 for (l = 0; l < numLeaves; ++l) { 4103 const PetscInt point = localPoints[l]; 4104 const PetscInt subPoint = DMPlexFilterPoint_Internal(point, firstSubVertex, numSubVertices, subVertices); 4105 4106 PetscCheck(!(point < vStart) || !(point >= vEnd), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Should not be mapping anything but vertices, %" PetscInt_FMT, point); 4107 if (subPoint < 0) continue; 4108 newLocalPoints[point - pStart].rank = rank; 4109 newLocalPoints[point - pStart].index = subPoint; 4110 ++numSubLeaves; 4111 } 4112 /* Must put in owned subpoints */ 4113 for (p = pStart; p < pEnd; ++p) { 4114 const PetscInt subPoint = DMPlexFilterPoint_Internal(p, firstSubVertex, numSubVertices, subVertices); 4115 4116 if (subPoint < 0) { 4117 newOwners[p - pStart].rank = -3; 4118 newOwners[p - pStart].index = -3; 4119 } else { 4120 newOwners[p - pStart].rank = rank; 4121 newOwners[p - pStart].index = subPoint; 4122 } 4123 } 4124 PetscCall(PetscSFReduceBegin(sfPoint, MPIU_SF_NODE, newLocalPoints, newOwners, MPI_MAXLOC)); 4125 PetscCall(PetscSFReduceEnd(sfPoint, MPIU_SF_NODE, newLocalPoints, newOwners, MPI_MAXLOC)); 4126 PetscCall(PetscSFBcastBegin(sfPoint, MPIU_SF_NODE, newOwners, newLocalPoints, MPI_REPLACE)); 4127 PetscCall(PetscSFBcastEnd(sfPoint, MPIU_SF_NODE, newOwners, newLocalPoints, MPI_REPLACE)); 4128 PetscCall(PetscMalloc1(numSubLeaves, &slocalPoints)); 4129 PetscCall(PetscMalloc1(numSubLeaves, &sremotePoints)); 4130 for (l = 0, sl = 0, ll = 0; l < numLeaves; ++l) { 4131 const PetscInt point = localPoints[l]; 4132 const PetscInt subPoint = DMPlexFilterPoint_Internal(point, firstSubVertex, numSubVertices, subVertices); 4133 4134 if (subPoint < 0) continue; 4135 if (newLocalPoints[point].rank == rank) { 4136 ++ll; 4137 continue; 4138 } 4139 slocalPoints[sl] = subPoint; 4140 sremotePoints[sl].rank = newLocalPoints[point].rank; 4141 sremotePoints[sl].index = newLocalPoints[point].index; 4142 PetscCheck(sremotePoints[sl].rank >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid remote rank for local point %" PetscInt_FMT, point); 4143 PetscCheck(sremotePoints[sl].index >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid remote subpoint for local point %" PetscInt_FMT, point); 4144 ++sl; 4145 } 4146 PetscCall(PetscFree2(newLocalPoints, newOwners)); 4147 PetscCheck(sl + ll == numSubLeaves, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatch in number of subleaves %" PetscInt_FMT " + %" PetscInt_FMT " != %" PetscInt_FMT, sl, ll, numSubLeaves); 4148 PetscCall(PetscSFSetGraph(sfPointSub, numSubRoots, sl, slocalPoints, PETSC_OWN_POINTER, sremotePoints, PETSC_OWN_POINTER)); 4149 } 4150 } 4151 CHKMEMQ; 4152 /* Cleanup */ 4153 if (subvertexIS) PetscCall(ISRestoreIndices(subvertexIS, &subVertices)); 4154 PetscCall(ISDestroy(&subvertexIS)); 4155 PetscCall(PetscFree(subCells)); 4156 PetscFunctionReturn(PETSC_SUCCESS); 4157 } 4158 4159 static PetscErrorCode DMPlexCreateCohesiveSubmesh_Interpolated(DM dm, const char labelname[], PetscInt value, DM subdm) 4160 { 4161 DMLabel label = NULL; 4162 4163 PetscFunctionBegin; 4164 if (labelname) PetscCall(DMGetLabel(dm, labelname, &label)); 4165 PetscCall(DMPlexCreateSubmeshGeneric_Interpolated(dm, label, value, PETSC_FALSE, PETSC_TRUE, 1, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 4166 PetscFunctionReturn(PETSC_SUCCESS); 4167 } 4168 4169 /*@ 4170 DMPlexCreateCohesiveSubmesh - Extract from a mesh with cohesive cells the hypersurface defined by one face of the cells. Optionally, a label can be given to restrict the cells. 4171 4172 Input Parameters: 4173 + dm - The original mesh 4174 . hasLagrange - The mesh has Lagrange unknowns in the cohesive cells 4175 . label - A label name, or `NULL` 4176 - value - A label value 4177 4178 Output Parameter: 4179 . subdm - The surface mesh 4180 4181 Level: developer 4182 4183 Note: 4184 This function produces a `DMLabel` mapping original points in the submesh to their depth. This can be obtained using `DMPlexGetSubpointMap()`. 4185 4186 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSubpointMap()`, `DMPlexCreateSubmesh()` 4187 @*/ 4188 PetscErrorCode DMPlexCreateCohesiveSubmesh(DM dm, PetscBool hasLagrange, const char label[], PetscInt value, DM *subdm) 4189 { 4190 PetscInt dim, cdim, depth; 4191 4192 PetscFunctionBegin; 4193 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4194 PetscAssertPointer(subdm, 5); 4195 PetscCall(DMGetDimension(dm, &dim)); 4196 PetscCall(DMPlexGetDepth(dm, &depth)); 4197 PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), subdm)); 4198 PetscCall(DMSetType(*subdm, DMPLEX)); 4199 PetscCall(DMSetDimension(*subdm, dim - 1)); 4200 PetscCall(DMGetCoordinateDim(dm, &cdim)); 4201 PetscCall(DMSetCoordinateDim(*subdm, cdim)); 4202 if (depth == dim) { 4203 PetscCall(DMPlexCreateCohesiveSubmesh_Interpolated(dm, label, value, *subdm)); 4204 } else { 4205 PetscCall(DMPlexCreateCohesiveSubmesh_Uninterpolated(dm, hasLagrange, label, value, *subdm)); 4206 } 4207 PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_TRUE, *subdm)); 4208 PetscFunctionReturn(PETSC_SUCCESS); 4209 } 4210 4211 /*@ 4212 DMPlexReorderCohesiveSupports - Ensure that face supports for cohesive end caps are ordered 4213 4214 Not Collective 4215 4216 Input Parameter: 4217 . dm - The `DM` containing cohesive cells 4218 4219 Level: developer 4220 4221 Note: 4222 For the negative size (first) face, the cohesive cell should be first in the support, and for 4223 the positive side (second) face, the cohesive cell should be second in the support. 4224 4225 .seealso: `DMPlexConstructCohesiveCells()`, `DMPlexCreateCohesiveSubmesh()` 4226 @*/ 4227 PetscErrorCode DMPlexReorderCohesiveSupports(DM dm) 4228 { 4229 PetscInt dim, cStart, cEnd; 4230 4231 PetscFunctionBegin; 4232 PetscCall(DMGetDimension(dm, &dim)); 4233 PetscCall(DMPlexGetTensorPrismBounds_Internal(dm, dim, &cStart, &cEnd)); 4234 for (PetscInt c = cStart; c < cEnd; ++c) { 4235 const PetscInt *cone; 4236 PetscInt coneSize; 4237 4238 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 4239 PetscCall(DMPlexGetCone(dm, c, &cone)); 4240 PetscCheck(coneSize >= 2, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Hybrid cell %" PetscInt_FMT " cone size %" PetscInt_FMT " must be >= 2", c, coneSize); 4241 for (PetscInt s = 0; s < 2; ++s) { 4242 const PetscInt *supp; 4243 PetscInt suppSize, newsupp[2]; 4244 4245 PetscCall(DMPlexGetSupportSize(dm, cone[s], &suppSize)); 4246 PetscCall(DMPlexGetSupport(dm, cone[s], &supp)); 4247 if (suppSize == 2) { 4248 /* Reorder hybrid end cap support */ 4249 if (supp[s] == c) { 4250 newsupp[0] = supp[1]; 4251 newsupp[1] = supp[0]; 4252 } else { 4253 newsupp[0] = supp[0]; 4254 newsupp[1] = supp[1]; 4255 } 4256 PetscCheck(newsupp[1 - s] == c, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Hybrid end cap %" PetscInt_FMT " support entry %" PetscInt_FMT " != %" PetscInt_FMT " hybrid cell", cone[s], newsupp[1 - s], c); 4257 PetscCall(DMPlexSetSupport(dm, cone[s], newsupp)); 4258 } 4259 } 4260 } 4261 PetscFunctionReturn(PETSC_SUCCESS); 4262 } 4263 4264 /*@ 4265 DMPlexFilter - Extract a subset of mesh cells defined by a label as a separate mesh 4266 4267 Input Parameters: 4268 + dm - The original mesh 4269 . cellLabel - The `DMLabel` marking cells contained in the new mesh 4270 . value - The label value to use 4271 . ignoreLabelHalo - The flag indicating if labeled points that are in the halo are ignored 4272 - sanitizeSubmesh - The flag indicating if a subpoint is forced to be owned by a rank that owns a subcell that contains that point in its closure 4273 4274 Output Parameters: 4275 + ownershipTransferSF - The `PetscSF` representing the ownership transfers between parent local meshes due to submeshing. 4276 - subdm - The new mesh 4277 4278 Level: developer 4279 4280 Note: 4281 This function produces a `DMLabel` mapping original points in the submesh to their depth. This can be obtained using `DMPlexGetSubpointMap()`. 4282 4283 On a given rank, the leaves of the ownershipTransferSF are the points in the local mesh that this rank gives up ownership of (in the submesh), and 4284 the remote locations for these leaves are tuples of rank and point that represent the new owners. 4285 4286 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSubpointMap()`, `DMGetLabel()`, `DMLabelSetValue()`, `DMPlexCreateSubmesh()` 4287 @*/ 4288 PetscErrorCode DMPlexFilter(DM dm, DMLabel cellLabel, PetscInt value, PetscBool ignoreLabelHalo, PetscBool sanitizeSubmesh, PetscSF *ownershipTransferSF, DM *subdm) 4289 { 4290 PetscInt dim, overlap; 4291 4292 PetscFunctionBegin; 4293 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4294 if (ownershipTransferSF) PetscAssertPointer(ownershipTransferSF, 6); 4295 PetscAssertPointer(subdm, 7); 4296 PetscCall(DMGetDimension(dm, &dim)); 4297 PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), subdm)); 4298 PetscCall(DMSetType(*subdm, DMPLEX)); 4299 /* Extract submesh in place, could be empty on some procs, could have inconsistency if procs do not both extract a shared cell */ 4300 PetscCall(DMPlexCreateSubmeshGeneric_Interpolated(dm, cellLabel, value, PETSC_FALSE, PETSC_FALSE, 0, ignoreLabelHalo, sanitizeSubmesh, ownershipTransferSF, *subdm)); 4301 PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_TRUE, *subdm)); 4302 // It is possible to obtain a surface mesh where some faces are in SF 4303 // We should either mark the mesh as having an overlap, or delete these from the SF 4304 PetscCall(DMPlexGetOverlap(dm, &overlap)); 4305 if (!overlap) { 4306 PetscSF sf; 4307 const PetscInt *leaves; 4308 PetscInt cStart, cEnd, Nl; 4309 PetscBool hasSubcell = PETSC_FALSE, ghasSubcell; 4310 4311 PetscCall(DMPlexGetHeightStratum(*subdm, 0, &cStart, &cEnd)); 4312 PetscCall(DMGetPointSF(*subdm, &sf)); 4313 PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &leaves, NULL)); 4314 for (PetscInt l = 0; l < Nl; ++l) { 4315 const PetscInt point = leaves ? leaves[l] : l; 4316 4317 if (point >= cStart && point < cEnd) { 4318 hasSubcell = PETSC_TRUE; 4319 break; 4320 } 4321 } 4322 PetscCallMPI(MPIU_Allreduce(&hasSubcell, &ghasSubcell, 1, MPI_C_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 4323 if (ghasSubcell) PetscCall(DMPlexSetOverlap(*subdm, NULL, 1)); 4324 } 4325 PetscFunctionReturn(PETSC_SUCCESS); 4326 } 4327 4328 /*@ 4329 DMPlexGetSubpointMap - Returns a `DMLabel` with point dimension as values 4330 4331 Input Parameter: 4332 . dm - The submesh `DM` 4333 4334 Output Parameter: 4335 . subpointMap - The `DMLabel` of all the points from the original mesh in this submesh, or `NULL` if this is not a submesh 4336 4337 Level: developer 4338 4339 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateSubmesh()`, `DMPlexGetSubpointIS()` 4340 @*/ 4341 PetscErrorCode DMPlexGetSubpointMap(DM dm, DMLabel *subpointMap) 4342 { 4343 PetscFunctionBegin; 4344 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4345 PetscAssertPointer(subpointMap, 2); 4346 *subpointMap = ((DM_Plex *)dm->data)->subpointMap; 4347 PetscFunctionReturn(PETSC_SUCCESS); 4348 } 4349 4350 /*@ 4351 DMPlexSetSubpointMap - Sets the `DMLabel` with point dimension as values 4352 4353 Input Parameters: 4354 + dm - The submesh `DM` 4355 - subpointMap - The `DMLabel` of all the points from the original mesh in this submesh 4356 4357 Level: developer 4358 4359 Note: 4360 Should normally not be called by the user, since it is set in `DMPlexCreateSubmesh()` 4361 4362 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateSubmesh()`, `DMPlexGetSubpointIS()` 4363 @*/ 4364 PetscErrorCode DMPlexSetSubpointMap(DM dm, DMLabel subpointMap) 4365 { 4366 DM_Plex *mesh = (DM_Plex *)dm->data; 4367 DMLabel tmp; 4368 4369 PetscFunctionBegin; 4370 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4371 tmp = mesh->subpointMap; 4372 mesh->subpointMap = subpointMap; 4373 PetscCall(PetscObjectReference((PetscObject)mesh->subpointMap)); 4374 PetscCall(DMLabelDestroy(&tmp)); 4375 PetscFunctionReturn(PETSC_SUCCESS); 4376 } 4377 4378 static PetscErrorCode DMPlexCreateSubpointIS_Internal(DM dm, IS *subpointIS) 4379 { 4380 DMLabel spmap; 4381 PetscInt depth, d; 4382 4383 PetscFunctionBegin; 4384 PetscCall(DMPlexGetSubpointMap(dm, &spmap)); 4385 PetscCall(DMPlexGetDepth(dm, &depth)); 4386 if (spmap && depth >= 0) { 4387 DM_Plex *mesh = (DM_Plex *)dm->data; 4388 PetscInt *points, *depths; 4389 PetscInt pStart, pEnd, p, off; 4390 4391 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4392 PetscCheck(!pStart, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Submeshes must start the point numbering at 0, not %" PetscInt_FMT, pStart); 4393 PetscCall(PetscMalloc1(pEnd, &points)); 4394 PetscCall(DMGetWorkArray(dm, depth + 1, MPIU_INT, &depths)); 4395 depths[0] = depth; 4396 depths[1] = 0; 4397 for (d = 2; d <= depth; ++d) depths[d] = depth + 1 - d; 4398 for (d = 0, off = 0; d <= depth; ++d) { 4399 const PetscInt dep = depths[d]; 4400 PetscInt depStart, depEnd, n; 4401 4402 PetscCall(DMPlexGetDepthStratum(dm, dep, &depStart, &depEnd)); 4403 PetscCall(DMLabelGetStratumSize(spmap, dep, &n)); 4404 if ((d < 2 && depth > 1) || d == 1) { /* Only check vertices and cells for now since the map is broken for others */ 4405 PetscCheck(n == depEnd - depStart, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of mapped submesh points %" PetscInt_FMT " at depth %" PetscInt_FMT " should be %" PetscInt_FMT, n, dep, depEnd - depStart); 4406 } else { 4407 if (!n) { 4408 if (d == 0) { 4409 /* Missing cells */ 4410 for (p = 0; p < depEnd - depStart; ++p, ++off) points[off] = -1; 4411 } else { 4412 /* Missing faces */ 4413 for (p = 0; p < depEnd - depStart; ++p, ++off) points[off] = PETSC_INT_MAX; 4414 } 4415 } 4416 } 4417 if (n) { 4418 IS is; 4419 const PetscInt *opoints; 4420 4421 PetscCall(DMLabelGetStratumIS(spmap, dep, &is)); 4422 PetscCall(ISGetIndices(is, &opoints)); 4423 for (p = 0; p < n; ++p, ++off) points[off] = opoints[p]; 4424 PetscCall(ISRestoreIndices(is, &opoints)); 4425 PetscCall(ISDestroy(&is)); 4426 } 4427 } 4428 PetscCall(DMRestoreWorkArray(dm, depth + 1, MPIU_INT, &depths)); 4429 PetscCheck(off == pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of mapped submesh points %" PetscInt_FMT " should be %" PetscInt_FMT, off, pEnd); 4430 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, pEnd, points, PETSC_OWN_POINTER, subpointIS)); 4431 PetscCall(PetscObjectStateGet((PetscObject)spmap, &mesh->subpointState)); 4432 } 4433 PetscFunctionReturn(PETSC_SUCCESS); 4434 } 4435 4436 /*@ 4437 DMPlexGetSubpointIS - Returns an `IS` covering the entire subdm chart with the original points as data 4438 4439 Input Parameter: 4440 . dm - The submesh `DM` 4441 4442 Output Parameter: 4443 . subpointIS - The `IS` of all the points from the original mesh in this submesh, or `NULL` if this is not a submesh 4444 4445 Level: developer 4446 4447 Note: 4448 This `IS` is guaranteed to be sorted by the construction of the submesh. However, if the filtering operation removes an entire stratum, then the strata in the submesh can be in a different order, and the `subpointIS` will only be sorted within each stratum. 4449 4450 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateSubmesh()`, `DMPlexGetSubpointMap()` 4451 @*/ 4452 PetscErrorCode DMPlexGetSubpointIS(DM dm, IS *subpointIS) 4453 { 4454 DM_Plex *mesh = (DM_Plex *)dm->data; 4455 DMLabel spmap; 4456 PetscObjectState state; 4457 4458 PetscFunctionBegin; 4459 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4460 PetscAssertPointer(subpointIS, 2); 4461 PetscCall(DMPlexGetSubpointMap(dm, &spmap)); 4462 PetscCall(PetscObjectStateGet((PetscObject)spmap, &state)); 4463 if (state != mesh->subpointState || !mesh->subpointIS) PetscCall(DMPlexCreateSubpointIS_Internal(dm, &mesh->subpointIS)); 4464 *subpointIS = mesh->subpointIS; 4465 PetscFunctionReturn(PETSC_SUCCESS); 4466 } 4467 4468 /*@ 4469 DMGetEnclosureRelation - Get the relationship between `dmA` and `dmB` 4470 4471 Input Parameters: 4472 + dmA - The first `DM` 4473 - dmB - The second `DM` 4474 4475 Output Parameter: 4476 . rel - The relation of `dmA` to `dmB` 4477 4478 Level: intermediate 4479 4480 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetEnclosurePoint()` 4481 @*/ 4482 PetscErrorCode DMGetEnclosureRelation(DM dmA, DM dmB, DMEnclosureType *rel) 4483 { 4484 DM plexA, plexB, sdm; 4485 DMLabel spmap; 4486 PetscInt pStartA, pEndA, pStartB, pEndB, NpA, NpB; 4487 4488 PetscFunctionBegin; 4489 PetscAssertPointer(rel, 3); 4490 *rel = DM_ENC_NONE; 4491 if (!dmA || !dmB) PetscFunctionReturn(PETSC_SUCCESS); 4492 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 4493 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 4494 if (dmA == dmB) { 4495 *rel = DM_ENC_EQUALITY; 4496 PetscFunctionReturn(PETSC_SUCCESS); 4497 } 4498 PetscCall(DMConvert(dmA, DMPLEX, &plexA)); 4499 PetscCall(DMConvert(dmB, DMPLEX, &plexB)); 4500 PetscCall(DMPlexGetChart(plexA, &pStartA, &pEndA)); 4501 PetscCall(DMPlexGetChart(plexB, &pStartB, &pEndB)); 4502 /* Assumption 1: subDMs have smaller charts than the DMs that they originate from 4503 - The degenerate case of a subdomain which includes all of the domain on some process can be treated as equality */ 4504 if (pStartA == pStartB && pEndA == pEndB) { 4505 *rel = DM_ENC_EQUALITY; 4506 goto end; 4507 } 4508 NpA = pEndA - pStartA; 4509 NpB = pEndB - pStartB; 4510 if (NpA == NpB) goto end; 4511 sdm = NpA > NpB ? plexB : plexA; /* The other is the original, enclosing dm */ 4512 PetscCall(DMPlexGetSubpointMap(sdm, &spmap)); 4513 if (!spmap) goto end; 4514 /* TODO Check the space mapped to by subpointMap is same size as dm */ 4515 if (NpA > NpB) { 4516 *rel = DM_ENC_SUPERMESH; 4517 } else { 4518 *rel = DM_ENC_SUBMESH; 4519 } 4520 end: 4521 PetscCall(DMDestroy(&plexA)); 4522 PetscCall(DMDestroy(&plexB)); 4523 PetscFunctionReturn(PETSC_SUCCESS); 4524 } 4525 4526 /*@ 4527 DMGetEnclosurePoint - Get the point `pA` in `dmA` which corresponds to the point `pB` in `dmB` 4528 4529 Input Parameters: 4530 + dmA - The first `DM` 4531 . dmB - The second `DM` 4532 . etype - The type of enclosure relation that `dmA` has to `dmB` 4533 - pB - A point of `dmB` 4534 4535 Output Parameter: 4536 . pA - The corresponding point of `dmA` 4537 4538 Level: intermediate 4539 4540 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetEnclosureRelation()` 4541 @*/ 4542 PetscErrorCode DMGetEnclosurePoint(DM dmA, DM dmB, DMEnclosureType etype, PetscInt pB, PetscInt *pA) 4543 { 4544 DM sdm; 4545 IS subpointIS; 4546 const PetscInt *subpoints; 4547 PetscInt numSubpoints; 4548 4549 PetscFunctionBegin; 4550 /* TODO Cache the IS, making it look like an index */ 4551 switch (etype) { 4552 case DM_ENC_SUPERMESH: 4553 sdm = dmB; 4554 PetscCall(DMPlexGetSubpointIS(sdm, &subpointIS)); 4555 PetscCall(ISGetIndices(subpointIS, &subpoints)); 4556 *pA = subpoints[pB]; 4557 PetscCall(ISRestoreIndices(subpointIS, &subpoints)); 4558 break; 4559 case DM_ENC_SUBMESH: 4560 sdm = dmA; 4561 PetscCall(DMPlexGetSubpointIS(sdm, &subpointIS)); 4562 PetscCall(ISGetLocalSize(subpointIS, &numSubpoints)); 4563 PetscCall(ISGetIndices(subpointIS, &subpoints)); 4564 PetscCall(PetscFindInt(pB, numSubpoints, subpoints, pA)); 4565 if (*pA < 0) { 4566 PetscCall(DMViewFromOptions(dmA, NULL, "-dm_enc_A_view")); 4567 PetscCall(DMViewFromOptions(dmB, NULL, "-dm_enc_B_view")); 4568 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " not found in submesh", pB); 4569 } 4570 PetscCall(ISRestoreIndices(subpointIS, &subpoints)); 4571 break; 4572 case DM_ENC_EQUALITY: 4573 case DM_ENC_NONE: 4574 *pA = pB; 4575 break; 4576 case DM_ENC_UNKNOWN: { 4577 DMEnclosureType enc; 4578 4579 PetscCall(DMGetEnclosureRelation(dmA, dmB, &enc)); 4580 PetscCall(DMGetEnclosurePoint(dmA, dmB, enc, pB, pA)); 4581 } break; 4582 default: 4583 SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Invalid enclosure type %d", (int)etype); 4584 } 4585 PetscFunctionReturn(PETSC_SUCCESS); 4586 } 4587