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, we add their transitive closure 286 287 Input Parameters: 288 + dm - The `DM` 289 - label - A `DMLabel` marking the points 290 291 Output Parameter: 292 . label - A `DMLabel` marking all 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, PetscCtx 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, pEnd; 3398 PetscBool *isGhost = NULL; 3399 3400 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3401 PetscCall(DMPlexGetDepthLabel(dm, &depth)); 3402 if (label) PetscCall(DMLabelGetStratumIS(label, value, &pointIS)); 3403 else { 3404 PetscInt cStart, cEnd; 3405 3406 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 3407 PetscCall(ISCreateStride(PETSC_COMM_SELF, cEnd - cStart, cStart, 1, &pointIS)); 3408 } 3409 if (pointIS) { 3410 PetscCall(ISGetIndices(pointIS, &points)); 3411 PetscCall(ISGetLocalSize(pointIS, &numPoints)); 3412 } 3413 if (ignoreLabelHalo) { 3414 PetscSF pointSF; 3415 PetscInt nleaves; 3416 const PetscInt *ilocal = NULL; 3417 3418 PetscCall(DMGetPointSF(dm, &pointSF)); 3419 PetscCall(PetscSFGetGraph(pointSF, NULL, &nleaves, &ilocal, NULL)); 3420 PetscCall(PetscMalloc1(pEnd - pStart, &isGhost)); 3421 for (p = 0; p < pEnd - pStart; ++p) isGhost[p] = PETSC_FALSE; 3422 for (p = 0; p < nleaves; ++p) isGhost[(ilocal ? ilocal[p] : p) - pStart] = PETSC_TRUE; 3423 } 3424 for (p = 0; p < numPoints; ++p) { 3425 PetscInt *closure = NULL; 3426 PetscInt closureSize, c, pdim; 3427 3428 if (isGhost && isGhost[points[p] - pStart]) continue; 3429 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closure)); 3430 for (c = 0; c < closureSize * 2; c += 2) { 3431 PetscCall(DMLabelGetValue(depth, closure[c], &pdim)); 3432 PetscCall(DMLabelSetValue(subpointMap, closure[c], pdim)); 3433 } 3434 PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closure)); 3435 } 3436 PetscCall(PetscFree(isGhost)); 3437 if (pointIS) PetscCall(ISRestoreIndices(pointIS, &points)); 3438 PetscCall(ISDestroy(&pointIS)); 3439 } 3440 /* Setup chart */ 3441 PetscCall(DMGetDimension(dm, &dim)); 3442 PetscCall(DMGetCoordinateDim(dm, &cdim)); 3443 PetscCall(PetscMalloc4(dim + 1, &numSubPoints, dim + 1, &firstSubPoint, dim + 1, &subpointIS, dim + 1, &subpoints)); 3444 for (d = 0; d <= dim; ++d) { 3445 PetscCall(DMLabelGetStratumSize(subpointMap, d, &numSubPoints[d])); 3446 totSubPoints += numSubPoints[d]; 3447 } 3448 // Determine submesh dimension 3449 PetscCall(DMGetDimension(subdm, &sdim)); 3450 if (sdim > 0) { 3451 // Calling function knows what dimension to use, and we include neighboring cells as well 3452 sdim = dim; 3453 } else { 3454 // We reset the subdimension based on what is being selected 3455 PetscInt lsdim; 3456 for (lsdim = dim; lsdim >= 0; --lsdim) 3457 if (numSubPoints[lsdim]) break; 3458 PetscCallMPI(MPIU_Allreduce(&lsdim, &sdim, 1, MPIU_INT, MPI_MAX, comm)); 3459 PetscCall(DMSetDimension(subdm, sdim)); 3460 PetscCall(DMSetCoordinateDim(subdm, cdim)); 3461 } 3462 PetscCall(DMPlexSetChart(subdm, 0, totSubPoints)); 3463 PetscCall(DMPlexSetVTKCellHeight(subdm, cellHeight)); 3464 /* Set cone sizes */ 3465 firstSubPoint[sdim] = 0; 3466 firstSubPoint[0] = firstSubPoint[sdim] + numSubPoints[sdim]; 3467 if (sdim > 1) firstSubPoint[sdim - 1] = firstSubPoint[0] + numSubPoints[0]; 3468 if (sdim > 2) firstSubPoint[sdim - 2] = firstSubPoint[sdim - 1] + numSubPoints[sdim - 1]; 3469 for (d = 0; d <= sdim; ++d) { 3470 PetscCall(DMLabelGetStratumIS(subpointMap, d, &subpointIS[d])); 3471 if (subpointIS[d]) PetscCall(ISGetIndices(subpointIS[d], &subpoints[d])); 3472 } 3473 /* We do not want this label automatically computed, instead we compute it here */ 3474 PetscCall(DMCreateLabel(subdm, "celltype")); 3475 for (d = 0; d <= sdim; ++d) { 3476 for (p = 0; p < numSubPoints[d]; ++p) { 3477 const PetscInt point = subpoints[d][p]; 3478 const PetscInt subpoint = firstSubPoint[d] + p; 3479 const PetscInt *cone; 3480 PetscInt coneSize; 3481 3482 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 3483 if (cellHeight && (d == sdim)) { 3484 PetscInt coneSizeNew, c, val; 3485 3486 PetscCall(DMPlexGetCone(dm, point, &cone)); 3487 for (c = 0, coneSizeNew = 0; c < coneSize; ++c) { 3488 PetscCall(DMLabelGetValue(subpointMap, cone[c], &val)); 3489 if (val >= 0) coneSizeNew++; 3490 } 3491 PetscCall(DMPlexSetConeSize(subdm, subpoint, coneSizeNew)); 3492 PetscCall(DMPlexSetCellType(subdm, subpoint, DM_POLYTOPE_FV_GHOST)); 3493 } else { 3494 DMPolytopeType ct; 3495 3496 PetscCall(DMPlexSetConeSize(subdm, subpoint, coneSize)); 3497 PetscCall(DMPlexGetCellType(dm, point, &ct)); 3498 PetscCall(DMPlexSetCellType(subdm, subpoint, ct)); 3499 } 3500 } 3501 } 3502 PetscCall(DMLabelDestroy(&subpointMap)); 3503 PetscCall(DMSetUp(subdm)); 3504 /* Set cones */ 3505 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, NULL)); 3506 PetscCall(PetscMalloc2(maxConeSize, &coneNew, maxConeSize, &orntNew)); 3507 for (d = 0; d <= sdim; ++d) { 3508 for (p = 0; p < numSubPoints[d]; ++p) { 3509 const PetscInt point = subpoints[d][p]; 3510 const PetscInt subpoint = firstSubPoint[d] + p; 3511 const PetscInt *cone, *ornt; 3512 PetscInt coneSize, subconeSize, coneSizeNew, c, subc, fornt = 0; 3513 3514 if (d == sdim - 1) { 3515 const PetscInt *support, *cone, *ornt; 3516 PetscInt supportSize, coneSize, s, subc; 3517 3518 PetscCall(DMPlexGetSupport(dm, point, &support)); 3519 PetscCall(DMPlexGetSupportSize(dm, point, &supportSize)); 3520 for (s = 0; s < supportSize; ++s) { 3521 PetscBool isHybrid = PETSC_FALSE; 3522 3523 PetscCall(DMPlexCellIsHybrid_Internal(dm, support[s], &isHybrid)); 3524 if (!isHybrid) continue; 3525 PetscCall(PetscFindInt(support[s], numSubPoints[d + 1], subpoints[d + 1], &subc)); 3526 if (subc >= 0) { 3527 const PetscInt ccell = subpoints[d + 1][subc]; 3528 3529 PetscCall(DMPlexGetCone(dm, ccell, &cone)); 3530 PetscCall(DMPlexGetConeSize(dm, ccell, &coneSize)); 3531 PetscCall(DMPlexGetConeOrientation(dm, ccell, &ornt)); 3532 for (c = 0; c < coneSize; ++c) { 3533 if (cone[c] == point) { 3534 fornt = ornt[c]; 3535 break; 3536 } 3537 } 3538 break; 3539 } 3540 } 3541 } 3542 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 3543 PetscCall(DMPlexGetConeSize(subdm, subpoint, &subconeSize)); 3544 PetscCall(DMPlexGetCone(dm, point, &cone)); 3545 PetscCall(DMPlexGetConeOrientation(dm, point, &ornt)); 3546 for (c = 0, coneSizeNew = 0; c < coneSize; ++c) { 3547 PetscCall(PetscFindInt(cone[c], numSubPoints[d - 1], subpoints[d - 1], &subc)); 3548 if (subc >= 0) { 3549 coneNew[coneSizeNew] = firstSubPoint[d - 1] + subc; 3550 orntNew[coneSizeNew] = ornt[c]; 3551 ++coneSizeNew; 3552 } 3553 } 3554 PetscCheck(coneSizeNew == subconeSize, comm, PETSC_ERR_PLIB, "Number of cone points located %" PetscInt_FMT " does not match subcone size %" PetscInt_FMT, coneSizeNew, subconeSize); 3555 PetscCall(DMPlexSetCone(subdm, subpoint, coneNew)); 3556 PetscCall(DMPlexSetConeOrientation(subdm, subpoint, orntNew)); 3557 if (fornt < 0) PetscCall(DMPlexOrientPoint(subdm, subpoint, fornt)); 3558 } 3559 } 3560 PetscCall(PetscFree2(coneNew, orntNew)); 3561 PetscCall(DMPlexSymmetrize(subdm)); 3562 PetscCall(DMPlexStratify(subdm)); 3563 /* Build coordinates */ 3564 for (coordinate_type = 0; coordinate_type < 2; ++coordinate_type) { 3565 DM coordDM = NULL, subCoordDM = NULL; 3566 PetscSection coordSection = NULL, subCoordSection = NULL; 3567 Vec coordinates = NULL, subCoordinates = NULL; 3568 PetscScalar *coords = NULL, *subCoords = NULL; 3569 PetscInt bs, numComp, coordSize, firstP, lastP, firstSubP = totSubPoints, lastSubP = -1, numFields; 3570 const char *name; 3571 PetscBool localized = (PetscBool)coordinate_type; 3572 3573 if (!dm->coordinates[coordinate_type].dm) continue; 3574 if (!localized) { 3575 PetscCall(DMGetCoordinateDM(dm, &coordDM)); 3576 PetscCall(DMGetCoordinateDM(subdm, &subCoordDM)); 3577 } else { 3578 { 3579 PetscInt localizationHeight; 3580 PetscBool sparseLocalize; 3581 3582 PetscCall(DMGetSparseLocalize(dm, &sparseLocalize)); 3583 PetscCall(DMSetSparseLocalize(subdm, sparseLocalize)); 3584 PetscCall(DMGetCoordinateDM(dm, &coordDM)); 3585 PetscCall(DMGetCoordinateDM(subdm, &subCoordDM)); 3586 PetscCall(DMPlexGetMaxProjectionHeight(coordDM, &localizationHeight)); 3587 PetscCall(DMPlexSetMaxProjectionHeight(subCoordDM, localizationHeight - (dim - sdim) - cellHeight)); 3588 PetscUseTypeMethod(subdm, createcellcoordinatedm, &subCoordDM); 3589 PetscCall(DMSetCellCoordinateDM(subdm, subCoordDM)); 3590 PetscCall(DMDestroy(&subCoordDM)); 3591 } 3592 PetscCall(DMGetCellCoordinateDM(dm, &coordDM)); 3593 PetscCall(DMGetCellCoordinateDM(subdm, &subCoordDM)); 3594 } 3595 PetscCall(DMGetNumFields(coordDM, &numFields)); 3596 if (numFields > 0) { 3597 PetscFE fe = NULL; 3598 PetscSpace P = NULL; 3599 PetscClassId id; 3600 PetscInt degree; 3601 3602 PetscCall(DMGetField(coordDM, 0, NULL, (PetscObject *)&fe)); 3603 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 3604 if (id == PETSCFE_CLASSID) { 3605 if (sdim == dim && cellHeight == 0) { 3606 /* TODO: Handle Field labels correctly */ 3607 PetscCall(DMSetField(subCoordDM, 0, NULL, (PetscObject)fe)); 3608 PetscCall(DMCreateDS(subCoordDM)); 3609 } else { 3610 /* TODO: Reconstruct the lower-dimensional FE more robustly */ 3611 PetscCall(PetscFEGetBasisSpace(fe, &P)); 3612 PetscCall(PetscSpaceGetDegree(P, °ree, NULL)); 3613 PetscCall(DMPlexCreateCoordinateSpace(subdm, degree, localized, PETSC_FALSE)); 3614 } 3615 } 3616 } 3617 if (!localized) { 3618 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 3619 PetscCall(DMGetCoordinateSection(subdm, &subCoordSection)); 3620 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 3621 } else { 3622 PetscCall(DMGetCellCoordinateSection(dm, &coordSection)); 3623 PetscCall(DMGetCellCoordinateSection(subdm, &subCoordSection)); 3624 PetscCall(DMGetCellCoordinatesLocal(dm, &coordinates)); 3625 } 3626 PetscCall(PetscSectionSetNumFields(subCoordSection, 1)); 3627 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &numComp)); 3628 PetscCall(PetscSectionSetFieldComponents(subCoordSection, 0, numComp)); 3629 PetscCall(PetscSectionGetChart(coordSection, &firstP, &lastP)); 3630 for (d = 0; d <= sdim; ++d) { 3631 for (p = 0; p < numSubPoints[d]; ++p) { 3632 const PetscInt point = subpoints[d][p]; 3633 const PetscInt subpoint = firstSubPoint[d] + p; 3634 3635 if (point >= firstP && point < lastP) { 3636 firstSubP = PetscMin(firstSubP, subpoint); 3637 lastSubP = PetscMax(lastSubP, subpoint); 3638 } 3639 } 3640 } 3641 lastSubP += 1; 3642 if (firstSubP == totSubPoints) { 3643 /* Zero if there is no coordinate point. */ 3644 firstSubP = 0; 3645 lastSubP = 0; 3646 } 3647 PetscCall(PetscSectionSetChart(subCoordSection, firstSubP, lastSubP)); 3648 for (d = 0; d <= sdim; ++d) { 3649 for (p = 0; p < numSubPoints[d]; ++p) { 3650 const PetscInt point = subpoints[d][p]; 3651 const PetscInt subpoint = firstSubPoint[d] + p; 3652 PetscInt dof; 3653 3654 if (point >= firstP && point < lastP) { 3655 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 3656 PetscCall(PetscSectionSetDof(subCoordSection, subpoint, dof)); 3657 PetscCall(PetscSectionSetFieldDof(subCoordSection, subpoint, 0, dof)); 3658 } 3659 } 3660 } 3661 PetscCall(PetscSectionSetUp(subCoordSection)); 3662 PetscCall(PetscSectionGetStorageSize(subCoordSection, &coordSize)); 3663 PetscCall(VecCreate(PETSC_COMM_SELF, &subCoordinates)); 3664 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 3665 PetscCall(PetscObjectSetName((PetscObject)subCoordinates, name)); 3666 PetscCall(VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE)); 3667 PetscCall(VecGetBlockSize(coordinates, &bs)); 3668 PetscCall(VecSetBlockSize(subCoordinates, bs)); 3669 PetscCall(VecSetType(subCoordinates, VECSTANDARD)); 3670 PetscCall(VecGetArray(coordinates, &coords)); 3671 PetscCall(VecGetArray(subCoordinates, &subCoords)); 3672 for (d = 0; d <= sdim; ++d) { 3673 for (p = 0; p < numSubPoints[d]; ++p) { 3674 const PetscInt point = subpoints[d][p]; 3675 const PetscInt subpoint = firstSubPoint[d] + p; 3676 PetscInt dof, off, sdof, soff, d; 3677 3678 if (point >= firstP && point < lastP) { 3679 PetscCall(PetscSectionGetDof(coordSection, point, &dof)); 3680 PetscCall(PetscSectionGetOffset(coordSection, point, &off)); 3681 PetscCall(PetscSectionGetDof(subCoordSection, subpoint, &sdof)); 3682 PetscCall(PetscSectionGetOffset(subCoordSection, subpoint, &soff)); 3683 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); 3684 for (d = 0; d < dof; ++d) subCoords[soff + d] = coords[off + d]; 3685 } 3686 } 3687 } 3688 PetscCall(VecRestoreArray(coordinates, &coords)); 3689 PetscCall(VecRestoreArray(subCoordinates, &subCoords)); 3690 switch (coordinate_type) { 3691 case 0: 3692 PetscCall(DMSetCoordinatesLocal(subdm, subCoordinates)); 3693 break; 3694 case 1: 3695 PetscCall(DMSetCellCoordinatesLocal(subdm, subCoordinates)); 3696 break; 3697 default: 3698 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "coordinate_type must be {0, 1}"); 3699 } 3700 PetscCall(VecDestroy(&subCoordinates)); 3701 } 3702 /* Build SF: We need this complexity because subpoints might not be selected on the owning process */ 3703 // TODO parallel subcommunicators 3704 PetscMPIInt flag; 3705 PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)dm), PetscObjectComm((PetscObject)subdm), &flag)); 3706 if (flag == MPI_CONGRUENT || flag == MPI_IDENT) { 3707 PetscSF sfPoint, sfPointSub; 3708 IS subpIS; 3709 const PetscSFNode *remotePoints; 3710 PetscSFNode *sremotePoints = NULL, *newLocalPoints = NULL, *newOwners = NULL; 3711 const PetscInt *localPoints, *subpoints, *rootdegree; 3712 PetscInt *slocalPoints = NULL, *sortedPoints = NULL, *sortedIndices = NULL; 3713 PetscInt numRoots, numLeaves, numSubpoints = 0, numSubroots, numSubleaves = 0, l, sl = 0, ll = 0, pStart, pEnd, p; 3714 PetscMPIInt rank, size; 3715 3716 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 3717 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 3718 PetscCall(DMGetPointSF(dm, &sfPoint)); 3719 PetscCall(DMGetPointSF(subdm, &sfPointSub)); 3720 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3721 PetscCall(DMPlexGetChart(subdm, NULL, &numSubroots)); 3722 PetscCall(DMPlexGetSubpointIS(subdm, &subpIS)); 3723 if (subpIS) { 3724 PetscBool sorted = PETSC_TRUE; 3725 3726 PetscCall(ISGetIndices(subpIS, &subpoints)); 3727 PetscCall(ISGetLocalSize(subpIS, &numSubpoints)); 3728 for (p = 1; p < numSubpoints; ++p) sorted = sorted && (subpoints[p] >= subpoints[p - 1]) ? PETSC_TRUE : PETSC_FALSE; 3729 if (!sorted) { 3730 PetscCall(PetscMalloc2(numSubpoints, &sortedPoints, numSubpoints, &sortedIndices)); 3731 for (p = 0; p < numSubpoints; ++p) sortedIndices[p] = p; 3732 PetscCall(PetscArraycpy(sortedPoints, subpoints, numSubpoints)); 3733 PetscCall(PetscSortIntWithArray(numSubpoints, sortedPoints, sortedIndices)); 3734 } 3735 } 3736 PetscCall(PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints)); 3737 if (numRoots >= 0) { 3738 PetscCall(PetscSFComputeDegreeBegin(sfPoint, &rootdegree)); 3739 PetscCall(PetscSFComputeDegreeEnd(sfPoint, &rootdegree)); 3740 PetscCall(PetscMalloc2(pEnd - pStart, &newLocalPoints, numRoots, &newOwners)); 3741 for (p = 0; p < pEnd - pStart; ++p) { 3742 newLocalPoints[p].rank = -2; 3743 newLocalPoints[p].index = -2; 3744 } 3745 for (p = pStart; p < pEnd; ++p) { 3746 newOwners[p - pStart].rank = -3; 3747 newOwners[p - pStart].index = -3; 3748 } 3749 if (sanitizeSubmesh) { 3750 /* A subpoint is forced to be owned by a rank that owns */ 3751 /* a subcell that contains the subpoint in its closure. */ 3752 PetscInt cStart, cEnd, c, clSize, cl; 3753 PetscInt *ownedCells, *closure = NULL; 3754 3755 /* claim ownership */ 3756 for (p = 0; p < numSubpoints; ++p) { 3757 const PetscInt point = subpoints[p]; 3758 3759 newLocalPoints[point - pStart].rank = rank; 3760 newLocalPoints[point - pStart].index = p; 3761 } 3762 PetscCall(DMGetDimension(subdm, &sdim)); 3763 PetscCall(DMPlexGetDepthStratum(dm, sdim, &cStart, &cEnd)); 3764 PetscCall(PetscMalloc1(cEnd - cStart, &ownedCells)); 3765 for (c = cStart; c < cEnd; ++c) ownedCells[c - cStart] = 0; 3766 for (p = 0; p < numSubpoints; ++p) { 3767 c = subpoints[p]; 3768 if (c >= cStart && c < cEnd) ownedCells[c - cStart] = 1; 3769 } 3770 for (l = 0; l < numLeaves; ++l) { 3771 c = localPoints ? localPoints[l] : l; 3772 if (c >= cStart && c < cEnd) ownedCells[c - cStart] = 0; 3773 } 3774 for (c = cStart; c < cEnd; ++c) { 3775 if (ownedCells[c - cStart] == 0) continue; 3776 PetscCall(DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 3777 for (cl = 0; cl < clSize * 2; cl += 2) { 3778 p = closure[cl]; 3779 if (newLocalPoints[p - pStart].rank < size) newLocalPoints[p - pStart].rank += size; 3780 } 3781 PetscCall(DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &clSize, &closure)); 3782 } 3783 PetscCall(PetscFree(ownedCells)); 3784 for (p = 0; p < numRoots; ++p) { 3785 newOwners[p].rank = newLocalPoints[p].rank; 3786 newOwners[p].index = newLocalPoints[p].index; 3787 } 3788 } else { 3789 /* Set subleaves */ 3790 for (l = 0; l < numLeaves; ++l) { 3791 const PetscInt point = localPoints[l]; 3792 const PetscInt subpoint = DMPlexFilterPointPerm_Internal(point, 0, numSubpoints, sortedPoints ? sortedPoints : subpoints, sortedIndices); 3793 3794 if (subpoint < 0) continue; 3795 newLocalPoints[point - pStart].rank = rank; 3796 newLocalPoints[point - pStart].index = subpoint; 3797 ++numSubleaves; 3798 } 3799 /* Must put in owned subpoints */ 3800 for (p = 0; p < numSubpoints; ++p) { 3801 /* Hold on to currently owned points */ 3802 if (rootdegree[subpoints[p] - pStart]) newOwners[subpoints[p] - pStart].rank = rank + size; 3803 else newOwners[subpoints[p] - pStart].rank = rank; 3804 newOwners[subpoints[p] - pStart].index = p; 3805 } 3806 } 3807 PetscCall(PetscSFReduceBegin(sfPoint, MPIU_SF_NODE, newLocalPoints, newOwners, MPI_MAXLOC)); 3808 PetscCall(PetscSFReduceEnd(sfPoint, MPIU_SF_NODE, newLocalPoints, newOwners, MPI_MAXLOC)); 3809 for (p = pStart; p < pEnd; ++p) 3810 if (newOwners[p - pStart].rank >= size) newOwners[p - pStart].rank -= size; 3811 if (ownershipTransferSF) { 3812 PetscSFNode *iremote1 = NULL, *newOwners1 = NULL; 3813 PetscInt *ilocal1 = NULL; 3814 PetscInt nleaves1, point; 3815 3816 for (p = 0; p < numSubpoints; ++p) { 3817 point = subpoints[p]; 3818 newLocalPoints[point - pStart].index = point; 3819 } 3820 PetscCall(PetscMalloc1(numRoots, &newOwners1)); 3821 for (p = 0; p < numRoots; ++p) { 3822 newOwners1[p].rank = -1; 3823 newOwners1[p].index = -1; 3824 } 3825 PetscCall(PetscSFReduceBegin(sfPoint, MPIU_SF_NODE, newLocalPoints, newOwners1, MPI_MAXLOC)); 3826 PetscCall(PetscSFReduceEnd(sfPoint, MPIU_SF_NODE, newLocalPoints, newOwners1, MPI_MAXLOC)); 3827 for (p = 0, nleaves1 = 0; p < numRoots; ++p) { 3828 if (newOwners[p].rank >= 0 && newOwners[p].rank != rank) ++nleaves1; 3829 } 3830 PetscCall(PetscMalloc1(nleaves1, &ilocal1)); 3831 PetscCall(PetscMalloc1(nleaves1, &iremote1)); 3832 for (p = 0, nleaves1 = 0; p < numRoots; ++p) { 3833 if (newOwners[p].rank >= 0 && newOwners[p].rank != rank) { 3834 ilocal1[nleaves1] = pStart + p; 3835 iremote1[nleaves1].rank = newOwners[p].rank; 3836 iremote1[nleaves1].index = newOwners1[p].index; 3837 ++nleaves1; 3838 } 3839 } 3840 PetscCall(PetscFree(newOwners1)); 3841 PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)sfPoint), ownershipTransferSF)); 3842 PetscCall(PetscSFSetFromOptions(*ownershipTransferSF)); 3843 PetscCall(PetscSFSetGraph(*ownershipTransferSF, pEnd - pStart, nleaves1, ilocal1, PETSC_OWN_POINTER, iremote1, PETSC_OWN_POINTER)); 3844 } 3845 if (sanitizeSubmesh) { 3846 for (p = pStart; p < pEnd; ++p) { 3847 newLocalPoints[p - pStart].rank = newOwners[p - pStart].rank; 3848 newLocalPoints[p - pStart].index = newOwners[p - pStart].index; 3849 } 3850 } 3851 PetscCall(PetscSFBcastBegin(sfPoint, MPIU_SF_NODE, newOwners, newLocalPoints, MPI_REPLACE)); 3852 PetscCall(PetscSFBcastEnd(sfPoint, MPIU_SF_NODE, newOwners, newLocalPoints, MPI_REPLACE)); 3853 if (sanitizeSubmesh) { 3854 for (p = 0; p < numSubpoints; ++p) { 3855 const PetscInt point = subpoints[p]; 3856 3857 if (newLocalPoints[point - pStart].rank >= 0 && newLocalPoints[point - pStart].rank != rank) ++sl; 3858 } 3859 PetscCall(PetscMalloc1(sl, &slocalPoints)); 3860 PetscCall(PetscMalloc1(sl, &sremotePoints)); 3861 for (p = 0, sl = 0; p < numSubpoints; ++p) { 3862 const PetscInt point = subpoints[p]; 3863 3864 if (newLocalPoints[point - pStart].rank >= 0 && newLocalPoints[point - pStart].rank != rank) { 3865 slocalPoints[sl] = p; 3866 sremotePoints[sl].rank = newLocalPoints[point - pStart].rank; 3867 sremotePoints[sl].index = newLocalPoints[point - pStart].index; 3868 PetscCheck(sremotePoints[sl].rank >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid remote rank"); 3869 PetscCheck(sremotePoints[sl].index >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid remote subpoint"); 3870 ++sl; 3871 } 3872 } 3873 } else { 3874 PetscCall(PetscMalloc1(numSubleaves, &slocalPoints)); 3875 PetscCall(PetscMalloc1(numSubleaves, &sremotePoints)); 3876 for (l = 0; l < numLeaves; ++l) { 3877 const PetscInt point = localPoints[l]; 3878 const PetscInt subpoint = DMPlexFilterPointPerm_Internal(point, 0, numSubpoints, sortedPoints ? sortedPoints : subpoints, sortedIndices); 3879 3880 if (subpoint < 0) continue; 3881 if (newLocalPoints[point].rank == rank) { 3882 ++ll; 3883 continue; 3884 } 3885 slocalPoints[sl] = subpoint; 3886 sremotePoints[sl].rank = newLocalPoints[point].rank; 3887 sremotePoints[sl].index = newLocalPoints[point].index; 3888 PetscCheck(sremotePoints[sl].rank >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid remote rank for local point %" PetscInt_FMT, point); 3889 PetscCheck(sremotePoints[sl].index >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid remote subpoint for local point %" PetscInt_FMT, point); 3890 ++sl; 3891 } 3892 PetscCheck(sl + ll == numSubleaves, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatch in number of subleaves %" PetscInt_FMT " + %" PetscInt_FMT " != %" PetscInt_FMT, sl, ll, numSubleaves); 3893 } 3894 PetscCall(PetscFree2(newLocalPoints, newOwners)); 3895 PetscCall(PetscSFSetGraph(sfPointSub, numSubroots, sl, slocalPoints, PETSC_OWN_POINTER, sremotePoints, PETSC_OWN_POINTER)); 3896 } 3897 if (subpIS) PetscCall(ISRestoreIndices(subpIS, &subpoints)); 3898 PetscCall(PetscFree2(sortedPoints, sortedIndices)); 3899 } 3900 /* Filter labels */ 3901 PetscCall(DMPlexFilterLabels_Internal(dm, numSubPoints, subpoints, firstSubPoint, subdm)); 3902 /* Cleanup */ 3903 for (d = 0; d <= sdim; ++d) { 3904 if (subpointIS[d]) PetscCall(ISRestoreIndices(subpointIS[d], &subpoints[d])); 3905 PetscCall(ISDestroy(&subpointIS[d])); 3906 } 3907 PetscCall(PetscFree4(numSubPoints, firstSubPoint, subpointIS, subpoints)); 3908 PetscFunctionReturn(PETSC_SUCCESS); 3909 } 3910 3911 static PetscErrorCode DMPlexCreateSubmesh_Interpolated(DM dm, DMLabel vertexLabel, PetscInt value, PetscBool markedFaces, DM subdm) 3912 { 3913 PetscFunctionBegin; 3914 PetscCall(DMPlexCreateSubmeshGeneric_Interpolated(dm, vertexLabel, value, markedFaces, PETSC_FALSE, 1, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 3915 PetscFunctionReturn(PETSC_SUCCESS); 3916 } 3917 3918 /*@ 3919 DMPlexCreateSubmesh - Extract a hypersurface from the mesh using vertices defined by a label 3920 3921 Input Parameters: 3922 + dm - The original mesh 3923 . vertexLabel - The `DMLabel` marking points contained in the surface 3924 . value - The label value to use 3925 - markedFaces - `PETSC_TRUE` if surface faces are marked in addition to vertices, `PETSC_FALSE` if only vertices are marked 3926 3927 Output Parameter: 3928 . subdm - The surface mesh 3929 3930 Level: developer 3931 3932 Note: 3933 This function produces a `DMLabel` mapping original points in the submesh to their depth. This can be obtained using `DMPlexGetSubpointMap()`. 3934 3935 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSubpointMap()`, `DMGetLabel()`, `DMLabelSetValue()` 3936 @*/ 3937 PetscErrorCode DMPlexCreateSubmesh(DM dm, DMLabel vertexLabel, PetscInt value, PetscBool markedFaces, DM *subdm) 3938 { 3939 DMPlexInterpolatedFlag interpolated; 3940 PetscInt dim, cdim; 3941 3942 PetscFunctionBegin; 3943 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3944 PetscAssertPointer(subdm, 5); 3945 PetscCall(DMGetDimension(dm, &dim)); 3946 PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), subdm)); 3947 PetscCall(DMSetType(*subdm, DMPLEX)); 3948 PetscCall(DMSetDimension(*subdm, dim - 1)); 3949 PetscCall(DMGetCoordinateDim(dm, &cdim)); 3950 PetscCall(DMSetCoordinateDim(*subdm, cdim)); 3951 PetscCall(DMPlexIsInterpolated(dm, &interpolated)); 3952 PetscCheck(interpolated != DMPLEX_INTERPOLATED_PARTIAL, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not for partially interpolated meshes"); 3953 if (interpolated) { 3954 PetscCall(DMPlexCreateSubmesh_Interpolated(dm, vertexLabel, value, markedFaces, *subdm)); 3955 } else { 3956 PetscCall(DMPlexCreateSubmesh_Uninterpolated(dm, vertexLabel, value, *subdm)); 3957 } 3958 PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_TRUE, *subdm)); 3959 PetscFunctionReturn(PETSC_SUCCESS); 3960 } 3961 3962 static PetscErrorCode DMPlexCreateCohesiveSubmesh_Uninterpolated(DM dm, PetscBool hasLagrange, const char label[], PetscInt value, DM subdm) 3963 { 3964 MPI_Comm comm; 3965 DMLabel subpointMap; 3966 IS subvertexIS; 3967 const PetscInt *subVertices; 3968 PetscInt numSubVertices, firstSubVertex, numSubCells, *subCells = NULL; 3969 PetscInt *subface, maxConeSize, numSubFaces, firstSubFace, newFacePoint, nFV; 3970 PetscInt c, f; 3971 3972 PetscFunctionBegin; 3973 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 3974 /* Create subpointMap which marks the submesh */ 3975 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "subpoint_map", &subpointMap)); 3976 PetscCall(DMPlexSetSubpointMap(subdm, subpointMap)); 3977 PetscCall(DMPlexMarkCohesiveSubmesh_Uninterpolated(dm, hasLagrange, label, value, subpointMap, &numSubFaces, &nFV, &subCells, subdm)); 3978 /* Setup chart */ 3979 PetscCall(DMLabelGetStratumSize(subpointMap, 0, &numSubVertices)); 3980 PetscCall(DMLabelGetStratumSize(subpointMap, 2, &numSubCells)); 3981 PetscCall(DMPlexSetChart(subdm, 0, numSubCells + numSubFaces + numSubVertices)); 3982 PetscCall(DMPlexSetVTKCellHeight(subdm, 1)); 3983 /* Set cone sizes */ 3984 firstSubVertex = numSubCells; 3985 firstSubFace = numSubCells + numSubVertices; 3986 newFacePoint = firstSubFace; 3987 PetscCall(DMLabelGetStratumIS(subpointMap, 0, &subvertexIS)); 3988 if (subvertexIS) PetscCall(ISGetIndices(subvertexIS, &subVertices)); 3989 for (c = 0; c < numSubCells; ++c) PetscCall(DMPlexSetConeSize(subdm, c, 1)); 3990 for (f = firstSubFace; f < firstSubFace + numSubFaces; ++f) PetscCall(DMPlexSetConeSize(subdm, f, nFV)); 3991 PetscCall(DMSetUp(subdm)); 3992 PetscCall(DMLabelDestroy(&subpointMap)); 3993 /* Create face cones */ 3994 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, NULL)); 3995 PetscCall(DMGetWorkArray(subdm, maxConeSize, MPIU_INT, (void **)&subface)); 3996 for (c = 0; c < numSubCells; ++c) { 3997 const PetscInt cell = subCells[c]; 3998 const PetscInt subcell = c; 3999 const PetscInt *cone, *cells; 4000 PetscBool isHybrid = PETSC_FALSE; 4001 PetscInt numCells, subVertex, p, v; 4002 4003 PetscCall(DMPlexCellIsHybrid_Internal(dm, cell, &isHybrid)); 4004 if (!isHybrid) continue; 4005 PetscCall(DMPlexGetCone(dm, cell, &cone)); 4006 for (v = 0; v < nFV; ++v) { 4007 PetscCall(PetscFindInt(cone[v], numSubVertices, subVertices, &subVertex)); 4008 subface[v] = firstSubVertex + subVertex; 4009 } 4010 PetscCall(DMPlexSetCone(subdm, newFacePoint, subface)); 4011 PetscCall(DMPlexSetCone(subdm, subcell, &newFacePoint)); 4012 PetscCall(DMPlexGetJoin(dm, nFV, cone, &numCells, &cells)); 4013 /* Not true in parallel 4014 PetscCheck(numCells == 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cohesive cells should separate two cells"); */ 4015 for (p = 0; p < numCells; ++p) { 4016 PetscInt negsubcell; 4017 PetscBool isHybrid = PETSC_FALSE; 4018 4019 PetscCall(DMPlexCellIsHybrid_Internal(dm, cells[p], &isHybrid)); 4020 if (isHybrid) continue; 4021 /* I know this is a crap search */ 4022 for (negsubcell = 0; negsubcell < numSubCells; ++negsubcell) { 4023 if (subCells[negsubcell] == cells[p]) break; 4024 } 4025 PetscCheck(negsubcell != numSubCells, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find negative face neighbor for cohesive cell %" PetscInt_FMT, cell); 4026 PetscCall(DMPlexSetCone(subdm, negsubcell, &newFacePoint)); 4027 } 4028 PetscCall(DMPlexRestoreJoin(dm, nFV, cone, &numCells, &cells)); 4029 ++newFacePoint; 4030 } 4031 PetscCall(DMRestoreWorkArray(subdm, maxConeSize, MPIU_INT, (void **)&subface)); 4032 PetscCall(DMPlexSymmetrize(subdm)); 4033 PetscCall(DMPlexStratify(subdm)); 4034 /* Build coordinates */ 4035 { 4036 PetscSection coordSection, subCoordSection; 4037 Vec coordinates, subCoordinates; 4038 PetscScalar *coords, *subCoords; 4039 PetscInt cdim, numComp, coordSize, v; 4040 const char *name; 4041 4042 PetscCall(DMGetCoordinateDim(dm, &cdim)); 4043 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 4044 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 4045 PetscCall(DMGetCoordinateSection(subdm, &subCoordSection)); 4046 PetscCall(PetscSectionSetNumFields(subCoordSection, 1)); 4047 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &numComp)); 4048 PetscCall(PetscSectionSetFieldComponents(subCoordSection, 0, numComp)); 4049 PetscCall(PetscSectionSetChart(subCoordSection, firstSubVertex, firstSubVertex + numSubVertices)); 4050 for (v = 0; v < numSubVertices; ++v) { 4051 const PetscInt vertex = subVertices[v]; 4052 const PetscInt subvertex = firstSubVertex + v; 4053 PetscInt dof; 4054 4055 PetscCall(PetscSectionGetDof(coordSection, vertex, &dof)); 4056 PetscCall(PetscSectionSetDof(subCoordSection, subvertex, dof)); 4057 PetscCall(PetscSectionSetFieldDof(subCoordSection, subvertex, 0, dof)); 4058 } 4059 PetscCall(PetscSectionSetUp(subCoordSection)); 4060 PetscCall(PetscSectionGetStorageSize(subCoordSection, &coordSize)); 4061 PetscCall(VecCreate(PETSC_COMM_SELF, &subCoordinates)); 4062 PetscCall(PetscObjectGetName((PetscObject)coordinates, &name)); 4063 PetscCall(PetscObjectSetName((PetscObject)subCoordinates, name)); 4064 PetscCall(VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE)); 4065 PetscCall(VecSetBlockSize(subCoordinates, cdim)); 4066 PetscCall(VecSetType(subCoordinates, VECSTANDARD)); 4067 PetscCall(VecGetArray(coordinates, &coords)); 4068 PetscCall(VecGetArray(subCoordinates, &subCoords)); 4069 for (v = 0; v < numSubVertices; ++v) { 4070 const PetscInt vertex = subVertices[v]; 4071 const PetscInt subvertex = firstSubVertex + v; 4072 PetscInt dof, off, sdof, soff, d; 4073 4074 PetscCall(PetscSectionGetDof(coordSection, vertex, &dof)); 4075 PetscCall(PetscSectionGetOffset(coordSection, vertex, &off)); 4076 PetscCall(PetscSectionGetDof(subCoordSection, subvertex, &sdof)); 4077 PetscCall(PetscSectionGetOffset(subCoordSection, subvertex, &soff)); 4078 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); 4079 for (d = 0; d < dof; ++d) subCoords[soff + d] = coords[off + d]; 4080 } 4081 PetscCall(VecRestoreArray(coordinates, &coords)); 4082 PetscCall(VecRestoreArray(subCoordinates, &subCoords)); 4083 PetscCall(DMSetCoordinatesLocal(subdm, subCoordinates)); 4084 PetscCall(VecDestroy(&subCoordinates)); 4085 } 4086 /* Build SF */ 4087 CHKMEMQ; 4088 { 4089 PetscSF sfPoint, sfPointSub; 4090 const PetscSFNode *remotePoints; 4091 PetscSFNode *sremotePoints, *newLocalPoints, *newOwners; 4092 const PetscInt *localPoints; 4093 PetscInt *slocalPoints; 4094 PetscInt numRoots, numLeaves, numSubRoots = numSubCells + numSubFaces + numSubVertices, numSubLeaves = 0, l, sl, ll, pStart, pEnd, p, vStart, vEnd; 4095 PetscMPIInt rank; 4096 4097 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 4098 PetscCall(DMGetPointSF(dm, &sfPoint)); 4099 PetscCall(DMGetPointSF(subdm, &sfPointSub)); 4100 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4101 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 4102 PetscCall(PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints)); 4103 if (numRoots >= 0) { 4104 /* Only vertices should be shared */ 4105 PetscCall(PetscMalloc2(pEnd - pStart, &newLocalPoints, numRoots, &newOwners)); 4106 for (p = 0; p < pEnd - pStart; ++p) { 4107 newLocalPoints[p].rank = -2; 4108 newLocalPoints[p].index = -2; 4109 } 4110 /* Set subleaves */ 4111 for (l = 0; l < numLeaves; ++l) { 4112 const PetscInt point = localPoints[l]; 4113 const PetscInt subPoint = DMPlexFilterPoint_Internal(point, firstSubVertex, numSubVertices, subVertices); 4114 4115 PetscCheck(!(point < vStart) || !(point >= vEnd), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Should not be mapping anything but vertices, %" PetscInt_FMT, point); 4116 if (subPoint < 0) continue; 4117 newLocalPoints[point - pStart].rank = rank; 4118 newLocalPoints[point - pStart].index = subPoint; 4119 ++numSubLeaves; 4120 } 4121 /* Must put in owned subpoints */ 4122 for (p = pStart; p < pEnd; ++p) { 4123 const PetscInt subPoint = DMPlexFilterPoint_Internal(p, firstSubVertex, numSubVertices, subVertices); 4124 4125 if (subPoint < 0) { 4126 newOwners[p - pStart].rank = -3; 4127 newOwners[p - pStart].index = -3; 4128 } else { 4129 newOwners[p - pStart].rank = rank; 4130 newOwners[p - pStart].index = subPoint; 4131 } 4132 } 4133 PetscCall(PetscSFReduceBegin(sfPoint, MPIU_SF_NODE, newLocalPoints, newOwners, MPI_MAXLOC)); 4134 PetscCall(PetscSFReduceEnd(sfPoint, MPIU_SF_NODE, newLocalPoints, newOwners, MPI_MAXLOC)); 4135 PetscCall(PetscSFBcastBegin(sfPoint, MPIU_SF_NODE, newOwners, newLocalPoints, MPI_REPLACE)); 4136 PetscCall(PetscSFBcastEnd(sfPoint, MPIU_SF_NODE, newOwners, newLocalPoints, MPI_REPLACE)); 4137 PetscCall(PetscMalloc1(numSubLeaves, &slocalPoints)); 4138 PetscCall(PetscMalloc1(numSubLeaves, &sremotePoints)); 4139 for (l = 0, sl = 0, ll = 0; l < numLeaves; ++l) { 4140 const PetscInt point = localPoints[l]; 4141 const PetscInt subPoint = DMPlexFilterPoint_Internal(point, firstSubVertex, numSubVertices, subVertices); 4142 4143 if (subPoint < 0) continue; 4144 if (newLocalPoints[point].rank == rank) { 4145 ++ll; 4146 continue; 4147 } 4148 slocalPoints[sl] = subPoint; 4149 sremotePoints[sl].rank = newLocalPoints[point].rank; 4150 sremotePoints[sl].index = newLocalPoints[point].index; 4151 PetscCheck(sremotePoints[sl].rank >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid remote rank for local point %" PetscInt_FMT, point); 4152 PetscCheck(sremotePoints[sl].index >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid remote subpoint for local point %" PetscInt_FMT, point); 4153 ++sl; 4154 } 4155 PetscCall(PetscFree2(newLocalPoints, newOwners)); 4156 PetscCheck(sl + ll == numSubLeaves, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatch in number of subleaves %" PetscInt_FMT " + %" PetscInt_FMT " != %" PetscInt_FMT, sl, ll, numSubLeaves); 4157 PetscCall(PetscSFSetGraph(sfPointSub, numSubRoots, sl, slocalPoints, PETSC_OWN_POINTER, sremotePoints, PETSC_OWN_POINTER)); 4158 } 4159 } 4160 CHKMEMQ; 4161 /* Cleanup */ 4162 if (subvertexIS) PetscCall(ISRestoreIndices(subvertexIS, &subVertices)); 4163 PetscCall(ISDestroy(&subvertexIS)); 4164 PetscCall(PetscFree(subCells)); 4165 PetscFunctionReturn(PETSC_SUCCESS); 4166 } 4167 4168 static PetscErrorCode DMPlexCreateCohesiveSubmesh_Interpolated(DM dm, const char labelname[], PetscInt value, DM subdm) 4169 { 4170 DMLabel label = NULL; 4171 4172 PetscFunctionBegin; 4173 if (labelname) PetscCall(DMGetLabel(dm, labelname, &label)); 4174 PetscCall(DMPlexCreateSubmeshGeneric_Interpolated(dm, label, value, PETSC_FALSE, PETSC_TRUE, 1, PETSC_FALSE, PETSC_FALSE, NULL, subdm)); 4175 PetscFunctionReturn(PETSC_SUCCESS); 4176 } 4177 4178 /*@ 4179 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. 4180 4181 Input Parameters: 4182 + dm - The original mesh 4183 . hasLagrange - The mesh has Lagrange unknowns in the cohesive cells 4184 . label - A label name, or `NULL` 4185 - value - A label value 4186 4187 Output Parameter: 4188 . subdm - The surface mesh 4189 4190 Level: developer 4191 4192 Note: 4193 This function produces a `DMLabel` mapping original points in the submesh to their depth. This can be obtained using `DMPlexGetSubpointMap()`. 4194 4195 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSubpointMap()`, `DMPlexCreateSubmesh()` 4196 @*/ 4197 PetscErrorCode DMPlexCreateCohesiveSubmesh(DM dm, PetscBool hasLagrange, const char label[], PetscInt value, DM *subdm) 4198 { 4199 PetscInt dim, cdim, depth; 4200 4201 PetscFunctionBegin; 4202 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4203 PetscAssertPointer(subdm, 5); 4204 PetscCall(DMGetDimension(dm, &dim)); 4205 PetscCall(DMPlexGetDepth(dm, &depth)); 4206 PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), subdm)); 4207 PetscCall(DMSetType(*subdm, DMPLEX)); 4208 PetscCall(DMSetDimension(*subdm, dim - 1)); 4209 PetscCall(DMGetCoordinateDim(dm, &cdim)); 4210 PetscCall(DMSetCoordinateDim(*subdm, cdim)); 4211 if (depth == dim) { 4212 PetscCall(DMPlexCreateCohesiveSubmesh_Interpolated(dm, label, value, *subdm)); 4213 } else { 4214 PetscCall(DMPlexCreateCohesiveSubmesh_Uninterpolated(dm, hasLagrange, label, value, *subdm)); 4215 } 4216 PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_TRUE, *subdm)); 4217 PetscFunctionReturn(PETSC_SUCCESS); 4218 } 4219 4220 /*@ 4221 DMPlexReorderCohesiveSupports - Ensure that face supports for cohesive end caps are ordered 4222 4223 Not Collective 4224 4225 Input Parameter: 4226 . dm - The `DM` containing cohesive cells 4227 4228 Level: developer 4229 4230 Note: 4231 For the negative size (first) face, the cohesive cell should be first in the support, and for 4232 the positive side (second) face, the cohesive cell should be second in the support. 4233 4234 .seealso: `DMPlexConstructCohesiveCells()`, `DMPlexCreateCohesiveSubmesh()` 4235 @*/ 4236 PetscErrorCode DMPlexReorderCohesiveSupports(DM dm) 4237 { 4238 PetscInt dim, cStart, cEnd; 4239 4240 PetscFunctionBegin; 4241 PetscCall(DMGetDimension(dm, &dim)); 4242 PetscCall(DMPlexGetTensorPrismBounds_Internal(dm, dim, &cStart, &cEnd)); 4243 for (PetscInt c = cStart; c < cEnd; ++c) { 4244 const PetscInt *cone; 4245 PetscInt coneSize; 4246 4247 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 4248 PetscCall(DMPlexGetCone(dm, c, &cone)); 4249 PetscCheck(coneSize >= 2, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Hybrid cell %" PetscInt_FMT " cone size %" PetscInt_FMT " must be >= 2", c, coneSize); 4250 for (PetscInt s = 0; s < 2; ++s) { 4251 const PetscInt *supp; 4252 PetscInt suppSize, newsupp[2]; 4253 4254 PetscCall(DMPlexGetSupportSize(dm, cone[s], &suppSize)); 4255 PetscCall(DMPlexGetSupport(dm, cone[s], &supp)); 4256 if (suppSize == 2) { 4257 /* Reorder hybrid end cap support */ 4258 if (supp[s] == c) { 4259 newsupp[0] = supp[1]; 4260 newsupp[1] = supp[0]; 4261 } else { 4262 newsupp[0] = supp[0]; 4263 newsupp[1] = supp[1]; 4264 } 4265 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); 4266 PetscCall(DMPlexSetSupport(dm, cone[s], newsupp)); 4267 } 4268 } 4269 } 4270 PetscFunctionReturn(PETSC_SUCCESS); 4271 } 4272 4273 /*@ 4274 DMPlexFilter - Extract a subset of mesh cells defined by a label as a separate mesh 4275 4276 Input Parameters: 4277 + dm - The original mesh 4278 . cellLabel - The `DMLabel` marking cells contained in the new mesh 4279 . value - The label value to use 4280 . ignoreLabelHalo - The flag indicating if labeled points that are in the halo are ignored 4281 . 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 4282 - comm - The communicator you want the mesh on (currently supports only a sequential communicator or the same communicator of the original mesh) 4283 4284 Output Parameters: 4285 + ownershipTransferSF - The `PetscSF` representing the ownership transfers between parent local meshes due to submeshing. 4286 - subdm - The new mesh 4287 4288 Level: developer 4289 4290 Note: 4291 This function produces a `DMLabel` mapping original points in the submesh to their depth. This can be obtained using `DMPlexGetSubpointMap()`. 4292 4293 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 4294 the remote locations for these leaves are tuples of rank and point that represent the new owners. 4295 4296 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexGetSubpointMap()`, `DMGetLabel()`, `DMLabelSetValue()`, `DMPlexCreateSubmesh()` 4297 @*/ 4298 PetscErrorCode DMPlexFilter(DM dm, DMLabel cellLabel, PetscInt value, PetscBool ignoreLabelHalo, PetscBool sanitizeSubmesh, MPI_Comm comm, PetscSF *ownershipTransferSF, DM *subdm) 4299 { 4300 PetscInt dim, overlap; 4301 4302 PetscFunctionBegin; 4303 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4304 if (ownershipTransferSF) PetscAssertPointer(ownershipTransferSF, 7); 4305 PetscAssertPointer(subdm, 8); 4306 PetscCall(DMGetDimension(dm, &dim)); 4307 PetscCall(DMCreate(comm, subdm)); 4308 PetscCall(DMSetType(*subdm, DMPLEX)); 4309 /* Extract submesh in place, could be empty on some procs, could have inconsistency if procs do not both extract a shared cell */ 4310 PetscCall(DMPlexCreateSubmeshGeneric_Interpolated(dm, cellLabel, value, PETSC_FALSE, PETSC_FALSE, 0, ignoreLabelHalo, sanitizeSubmesh, ownershipTransferSF, *subdm)); 4311 PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_TRUE, *subdm)); 4312 // It is possible to obtain a surface mesh where some faces are in SF 4313 // We should either mark the mesh as having an overlap, or delete these from the SF 4314 PetscCall(DMPlexGetOverlap(dm, &overlap)); 4315 if (!overlap) { 4316 PetscSF sf; 4317 const PetscInt *leaves; 4318 PetscInt cStart, cEnd, Nl; 4319 PetscBool hasSubcell = PETSC_FALSE, ghasSubcell; 4320 4321 PetscCall(DMPlexGetHeightStratum(*subdm, 0, &cStart, &cEnd)); 4322 PetscCall(DMGetPointSF(*subdm, &sf)); 4323 PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &leaves, NULL)); 4324 for (PetscInt l = 0; l < Nl; ++l) { 4325 const PetscInt point = leaves ? leaves[l] : l; 4326 4327 if (point >= cStart && point < cEnd) { 4328 hasSubcell = PETSC_TRUE; 4329 break; 4330 } 4331 } 4332 PetscCallMPI(MPIU_Allreduce(&hasSubcell, &ghasSubcell, 1, MPI_C_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 4333 if (ghasSubcell) PetscCall(DMPlexSetOverlap(*subdm, NULL, 1)); 4334 } 4335 PetscFunctionReturn(PETSC_SUCCESS); 4336 } 4337 4338 /*@ 4339 DMPlexGetSubpointMap - Returns a `DMLabel` with point dimension as values 4340 4341 Input Parameter: 4342 . dm - The submesh `DM` 4343 4344 Output Parameter: 4345 . subpointMap - The `DMLabel` of all the points from the original mesh in this submesh, or `NULL` if this is not a submesh 4346 4347 Level: developer 4348 4349 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateSubmesh()`, `DMPlexGetSubpointIS()` 4350 @*/ 4351 PetscErrorCode DMPlexGetSubpointMap(DM dm, DMLabel *subpointMap) 4352 { 4353 PetscFunctionBegin; 4354 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4355 PetscAssertPointer(subpointMap, 2); 4356 *subpointMap = ((DM_Plex *)dm->data)->subpointMap; 4357 PetscFunctionReturn(PETSC_SUCCESS); 4358 } 4359 4360 /*@ 4361 DMPlexSetSubpointMap - Sets the `DMLabel` with point dimension as values 4362 4363 Input Parameters: 4364 + dm - The submesh `DM` 4365 - subpointMap - The `DMLabel` of all the points from the original mesh in this submesh 4366 4367 Level: developer 4368 4369 Note: 4370 Should normally not be called by the user, since it is set in `DMPlexCreateSubmesh()` 4371 4372 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateSubmesh()`, `DMPlexGetSubpointIS()` 4373 @*/ 4374 PetscErrorCode DMPlexSetSubpointMap(DM dm, DMLabel subpointMap) 4375 { 4376 DM_Plex *mesh = (DM_Plex *)dm->data; 4377 DMLabel tmp; 4378 4379 PetscFunctionBegin; 4380 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4381 tmp = mesh->subpointMap; 4382 mesh->subpointMap = subpointMap; 4383 PetscCall(PetscObjectReference((PetscObject)mesh->subpointMap)); 4384 PetscCall(DMLabelDestroy(&tmp)); 4385 PetscFunctionReturn(PETSC_SUCCESS); 4386 } 4387 4388 static PetscErrorCode DMPlexCreateSubpointIS_Internal(DM dm, IS *subpointIS) 4389 { 4390 DMLabel spmap; 4391 PetscInt depth, d; 4392 4393 PetscFunctionBegin; 4394 PetscCall(DMPlexGetSubpointMap(dm, &spmap)); 4395 PetscCall(DMPlexGetDepth(dm, &depth)); 4396 if (spmap && depth >= 0) { 4397 DM_Plex *mesh = (DM_Plex *)dm->data; 4398 PetscInt *points, *depths; 4399 PetscInt pStart, pEnd, p, off; 4400 4401 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 4402 PetscCheck(!pStart, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Submeshes must start the point numbering at 0, not %" PetscInt_FMT, pStart); 4403 PetscCall(PetscMalloc1(pEnd, &points)); 4404 PetscCall(DMGetWorkArray(dm, depth + 1, MPIU_INT, &depths)); 4405 depths[0] = depth; 4406 depths[1] = 0; 4407 for (d = 2; d <= depth; ++d) depths[d] = depth + 1 - d; 4408 for (d = 0, off = 0; d <= depth; ++d) { 4409 const PetscInt dep = depths[d]; 4410 PetscInt depStart, depEnd, n; 4411 4412 PetscCall(DMPlexGetDepthStratum(dm, dep, &depStart, &depEnd)); 4413 PetscCall(DMLabelGetStratumSize(spmap, dep, &n)); 4414 if ((d < 2 && depth > 1) || d == 1) { /* Only check vertices and cells for now since the map is broken for others */ 4415 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); 4416 } else { 4417 if (!n) { 4418 if (d == 0) { 4419 /* Missing cells */ 4420 for (p = 0; p < depEnd - depStart; ++p, ++off) points[off] = -1; 4421 } else { 4422 /* Missing faces */ 4423 for (p = 0; p < depEnd - depStart; ++p, ++off) points[off] = PETSC_INT_MAX; 4424 } 4425 } 4426 } 4427 if (n) { 4428 IS is; 4429 const PetscInt *opoints; 4430 4431 PetscCall(DMLabelGetStratumIS(spmap, dep, &is)); 4432 PetscCall(ISGetIndices(is, &opoints)); 4433 for (p = 0; p < n; ++p, ++off) points[off] = opoints[p]; 4434 PetscCall(ISRestoreIndices(is, &opoints)); 4435 PetscCall(ISDestroy(&is)); 4436 } 4437 } 4438 PetscCall(DMRestoreWorkArray(dm, depth + 1, MPIU_INT, &depths)); 4439 PetscCheck(off == pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of mapped submesh points %" PetscInt_FMT " should be %" PetscInt_FMT, off, pEnd); 4440 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, pEnd, points, PETSC_OWN_POINTER, subpointIS)); 4441 PetscCall(PetscObjectStateGet((PetscObject)spmap, &mesh->subpointState)); 4442 } 4443 PetscFunctionReturn(PETSC_SUCCESS); 4444 } 4445 4446 /*@ 4447 DMPlexGetSubpointIS - Returns an `IS` covering the entire subdm chart with the original points as data 4448 4449 Input Parameter: 4450 . dm - The submesh `DM` 4451 4452 Output Parameter: 4453 . subpointIS - The `IS` of all the points from the original mesh in this submesh, or `NULL` if this is not a submesh 4454 4455 Level: developer 4456 4457 Note: 4458 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. 4459 4460 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMPlexCreateSubmesh()`, `DMPlexGetSubpointMap()` 4461 @*/ 4462 PetscErrorCode DMPlexGetSubpointIS(DM dm, IS *subpointIS) 4463 { 4464 DM_Plex *mesh = (DM_Plex *)dm->data; 4465 DMLabel spmap; 4466 PetscObjectState state; 4467 4468 PetscFunctionBegin; 4469 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4470 PetscAssertPointer(subpointIS, 2); 4471 PetscCall(DMPlexGetSubpointMap(dm, &spmap)); 4472 PetscCall(PetscObjectStateGet((PetscObject)spmap, &state)); 4473 if (state != mesh->subpointState || !mesh->subpointIS) PetscCall(DMPlexCreateSubpointIS_Internal(dm, &mesh->subpointIS)); 4474 *subpointIS = mesh->subpointIS; 4475 PetscFunctionReturn(PETSC_SUCCESS); 4476 } 4477 4478 /*@ 4479 DMGetEnclosureRelation - Get the relationship between `dmA` and `dmB` 4480 4481 Input Parameters: 4482 + dmA - The first `DM` 4483 - dmB - The second `DM` 4484 4485 Output Parameter: 4486 . rel - The relation of `dmA` to `dmB` 4487 4488 Level: intermediate 4489 4490 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetEnclosurePoint()` 4491 @*/ 4492 PetscErrorCode DMGetEnclosureRelation(DM dmA, DM dmB, DMEnclosureType *rel) 4493 { 4494 DM plexA, plexB, sdm; 4495 DMLabel spmap; 4496 PetscInt pStartA, pEndA, pStartB, pEndB, NpA, NpB; 4497 4498 PetscFunctionBegin; 4499 PetscAssertPointer(rel, 3); 4500 *rel = DM_ENC_NONE; 4501 if (!dmA || !dmB) PetscFunctionReturn(PETSC_SUCCESS); 4502 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 4503 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 4504 if (dmA == dmB) { 4505 *rel = DM_ENC_EQUALITY; 4506 PetscFunctionReturn(PETSC_SUCCESS); 4507 } 4508 PetscCall(DMConvert(dmA, DMPLEX, &plexA)); 4509 PetscCall(DMConvert(dmB, DMPLEX, &plexB)); 4510 PetscCall(DMPlexGetChart(plexA, &pStartA, &pEndA)); 4511 PetscCall(DMPlexGetChart(plexB, &pStartB, &pEndB)); 4512 /* Assumption 1: subDMs have smaller charts than the DMs that they originate from 4513 - The degenerate case of a subdomain which includes all of the domain on some process can be treated as equality */ 4514 if (pStartA == pStartB && pEndA == pEndB) { 4515 *rel = DM_ENC_EQUALITY; 4516 goto end; 4517 } 4518 NpA = pEndA - pStartA; 4519 NpB = pEndB - pStartB; 4520 if (NpA == NpB) goto end; 4521 sdm = NpA > NpB ? plexB : plexA; /* The other is the original, enclosing dm */ 4522 PetscCall(DMPlexGetSubpointMap(sdm, &spmap)); 4523 if (!spmap) goto end; 4524 /* TODO Check the space mapped to by subpointMap is same size as dm */ 4525 if (NpA > NpB) { 4526 *rel = DM_ENC_SUPERMESH; 4527 } else { 4528 *rel = DM_ENC_SUBMESH; 4529 } 4530 end: 4531 PetscCall(DMDestroy(&plexA)); 4532 PetscCall(DMDestroy(&plexB)); 4533 PetscFunctionReturn(PETSC_SUCCESS); 4534 } 4535 4536 /*@ 4537 DMGetEnclosurePoint - Get the point `pA` in `dmA` which corresponds to the point `pB` in `dmB` 4538 4539 Input Parameters: 4540 + dmA - The first `DM` 4541 . dmB - The second `DM` 4542 . etype - The type of enclosure relation that `dmA` has to `dmB` 4543 - pB - A point of `dmB` 4544 4545 Output Parameter: 4546 . pA - The corresponding point of `dmA` 4547 4548 Level: intermediate 4549 4550 .seealso: [](ch_unstructured), `DM`, `DMPLEX`, `DMGetEnclosureRelation()` 4551 @*/ 4552 PetscErrorCode DMGetEnclosurePoint(DM dmA, DM dmB, DMEnclosureType etype, PetscInt pB, PetscInt *pA) 4553 { 4554 DM sdm; 4555 IS subpointIS; 4556 const PetscInt *subpoints; 4557 PetscInt numSubpoints; 4558 4559 PetscFunctionBegin; 4560 /* TODO Cache the IS, making it look like an index */ 4561 switch (etype) { 4562 case DM_ENC_SUPERMESH: 4563 sdm = dmB; 4564 PetscCall(DMPlexGetSubpointIS(sdm, &subpointIS)); 4565 PetscCall(ISGetIndices(subpointIS, &subpoints)); 4566 *pA = subpoints[pB]; 4567 PetscCall(ISRestoreIndices(subpointIS, &subpoints)); 4568 break; 4569 case DM_ENC_SUBMESH: 4570 sdm = dmA; 4571 PetscCall(DMPlexGetSubpointIS(sdm, &subpointIS)); 4572 PetscCall(ISGetLocalSize(subpointIS, &numSubpoints)); 4573 PetscCall(ISGetIndices(subpointIS, &subpoints)); 4574 PetscCall(PetscFindInt(pB, numSubpoints, subpoints, pA)); 4575 if (*pA < 0) { 4576 PetscCall(DMViewFromOptions(dmA, NULL, "-dm_enc_A_view")); 4577 PetscCall(DMViewFromOptions(dmB, NULL, "-dm_enc_B_view")); 4578 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " not found in submesh", pB); 4579 } 4580 PetscCall(ISRestoreIndices(subpointIS, &subpoints)); 4581 break; 4582 case DM_ENC_EQUALITY: 4583 case DM_ENC_NONE: 4584 *pA = pB; 4585 break; 4586 case DM_ENC_UNKNOWN: { 4587 DMEnclosureType enc; 4588 4589 PetscCall(DMGetEnclosureRelation(dmA, dmB, &enc)); 4590 PetscCall(DMGetEnclosurePoint(dmA, dmB, enc, pB, pA)); 4591 } break; 4592 default: 4593 SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Invalid enclosure type %d", (int)etype); 4594 } 4595 PetscFunctionReturn(PETSC_SUCCESS); 4596 } 4597