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