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