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