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 %d with %d 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, gdm)); 976 gdm->setfromoptionscalled = dm->setfromoptionscalled; 977 if (numGhostCells) *numGhostCells = Ng; 978 *dmGhosted = gdm; 979 PetscFunctionReturn(0); 980 } 981 982 /* 983 We are adding three kinds of points here: 984 Replicated: Copies of points which exist in the mesh, such as vertices identified across a fault 985 Non-replicated: Points which exist on the fault, but are not replicated 986 Ghost: These are shared fault faces which are not owned by this process. These do not produce hybrid cells and do not replicate 987 Hybrid: Entirely new points, such as cohesive cells 988 989 When creating subsequent cohesive cells, we shift the old hybrid cells to the end of the numbering at 990 each depth so that the new split/hybrid points can be inserted as a block. 991 */ 992 static PetscErrorCode DMPlexConstructCohesiveCells_Internal(DM dm, DMLabel label, DMLabel splitLabel, DM sdm) 993 { 994 MPI_Comm comm; 995 IS valueIS; 996 PetscInt numSP = 0; /* The number of depths for which we have replicated points */ 997 const PetscInt *values; /* List of depths for which we have replicated points */ 998 IS *splitIS; 999 IS *unsplitIS; 1000 IS ghostIS; 1001 PetscInt *numSplitPoints; /* The number of replicated points at each depth */ 1002 PetscInt *numUnsplitPoints; /* The number of non-replicated points at each depth which still give rise to hybrid points */ 1003 PetscInt *numHybridPoints; /* The number of new hybrid points at each depth */ 1004 PetscInt *numHybridPointsOld; /* The number of existing hybrid points at each depth */ 1005 PetscInt numGhostPoints; /* The number of unowned, shared fault faces */ 1006 const PetscInt **splitPoints; /* Replicated points for each depth */ 1007 const PetscInt **unsplitPoints; /* Non-replicated points for each depth */ 1008 const PetscInt *ghostPoints; /* Ghost fault faces */ 1009 PetscSection coordSection; 1010 Vec coordinates; 1011 PetscScalar *coords; 1012 PetscInt *depthMax; /* The first hybrid point at each depth in the original mesh */ 1013 PetscInt *depthEnd; /* The point limit at each depth in the original mesh */ 1014 PetscInt *depthShift; /* Number of replicated+hybrid points at each depth */ 1015 PetscInt *pMaxNew; /* The first replicated point at each depth in the new mesh, hybrids come after this */ 1016 PetscInt *coneNew, *coneONew, *supportNew; 1017 PetscInt shift = 100, shift2 = 200, depth = 0, dep, dim, d, sp, maxConeSize, maxSupportSize, maxConeSizeNew, maxSupportSizeNew, numLabels, vStart, vEnd, pEnd, p, v; 1018 1019 PetscFunctionBegin; 1020 PetscCall(PetscObjectGetComm((PetscObject)dm,&comm)); 1021 PetscCall(DMGetDimension(dm, &dim)); 1022 PetscCall(DMPlexGetDepth(dm, &depth)); 1023 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1024 /* We do not want this label automatically computed, instead we compute it here */ 1025 PetscCall(DMCreateLabel(sdm, "celltype")); 1026 /* Count split points and add cohesive cells */ 1027 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize)); 1028 PetscCall(PetscMalloc5(depth+1,&depthMax,depth+1,&depthEnd,2*(depth+1),&depthShift,depth+1,&pMaxNew,depth+1,&numHybridPointsOld)); 1029 PetscCall(PetscMalloc7(depth+1,&splitIS,depth+1,&unsplitIS,depth+1,&numSplitPoints,depth+1,&numUnsplitPoints,depth+1,&numHybridPoints,depth+1,&splitPoints,depth+1,&unsplitPoints)); 1030 for (d = 0; d <= depth; ++d) { 1031 PetscCall(DMPlexGetDepthStratum(dm, d, NULL, &pMaxNew[d])); 1032 PetscCall(DMPlexGetTensorPrismBounds_Internal(dm, d, &depthMax[d], NULL)); 1033 depthEnd[d] = pMaxNew[d]; 1034 depthMax[d] = depthMax[d] < 0 ? depthEnd[d] : depthMax[d]; 1035 numSplitPoints[d] = 0; 1036 numUnsplitPoints[d] = 0; 1037 numHybridPoints[d] = 0; 1038 numHybridPointsOld[d] = depthMax[d] < 0 ? 0 : depthEnd[d] - depthMax[d]; 1039 splitPoints[d] = NULL; 1040 unsplitPoints[d] = NULL; 1041 splitIS[d] = NULL; 1042 unsplitIS[d] = NULL; 1043 /* we are shifting the existing hybrid points with the stratum behind them, so 1044 * the split comes at the end of the normal points, i.e., at depthMax[d] */ 1045 depthShift[2*d] = depthMax[d]; 1046 depthShift[2*d+1] = 0; 1047 } 1048 numGhostPoints = 0; 1049 ghostPoints = NULL; 1050 if (label) { 1051 PetscCall(DMLabelGetValueIS(label, &valueIS)); 1052 PetscCall(ISGetLocalSize(valueIS, &numSP)); 1053 PetscCall(ISGetIndices(valueIS, &values)); 1054 } 1055 for (sp = 0; sp < numSP; ++sp) { 1056 const PetscInt dep = values[sp]; 1057 1058 if ((dep < 0) || (dep > depth)) continue; 1059 PetscCall(DMLabelGetStratumIS(label, dep, &splitIS[dep])); 1060 if (splitIS[dep]) { 1061 PetscCall(ISGetLocalSize(splitIS[dep], &numSplitPoints[dep])); 1062 PetscCall(ISGetIndices(splitIS[dep], &splitPoints[dep])); 1063 } 1064 PetscCall(DMLabelGetStratumIS(label, shift2+dep, &unsplitIS[dep])); 1065 if (unsplitIS[dep]) { 1066 PetscCall(ISGetLocalSize(unsplitIS[dep], &numUnsplitPoints[dep])); 1067 PetscCall(ISGetIndices(unsplitIS[dep], &unsplitPoints[dep])); 1068 } 1069 } 1070 PetscCall(DMLabelGetStratumIS(label, shift2+dim-1, &ghostIS)); 1071 if (ghostIS) { 1072 PetscCall(ISGetLocalSize(ghostIS, &numGhostPoints)); 1073 PetscCall(ISGetIndices(ghostIS, &ghostPoints)); 1074 } 1075 /* Calculate number of hybrid points */ 1076 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 */ 1077 for (d = 0; d <= depth; ++d) depthShift[2*d+1] = numSplitPoints[d] + numHybridPoints[d]; 1078 PetscCall(DMPlexShiftPointSetUp_Internal(depth,depthShift)); 1079 /* the end of the points in this stratum that come before the new points: 1080 * shifting pMaxNew[d] gets the new start of the next stratum, then count back the old hybrid points and the newly 1081 * added points */ 1082 for (d = 0; d <= depth; ++d) pMaxNew[d] = DMPlexShiftPoint_Internal(pMaxNew[d],depth,depthShift) - (numHybridPointsOld[d] + numSplitPoints[d] + numHybridPoints[d]); 1083 PetscCall(DMPlexShiftSizes_Internal(dm, depthShift, sdm)); 1084 /* Step 3: Set cone/support sizes for new points */ 1085 for (dep = 0; dep <= depth; ++dep) { 1086 for (p = 0; p < numSplitPoints[dep]; ++p) { 1087 const PetscInt oldp = splitPoints[dep][p]; 1088 const PetscInt newp = DMPlexShiftPoint_Internal(oldp, depth, depthShift) /*oldp + depthOffset[dep]*/; 1089 const PetscInt splitp = p + pMaxNew[dep]; 1090 const PetscInt *support; 1091 DMPolytopeType ct; 1092 PetscInt coneSize, supportSize, qf, qn, qp, e; 1093 1094 PetscCall(DMPlexGetConeSize(dm, oldp, &coneSize)); 1095 PetscCall(DMPlexSetConeSize(sdm, splitp, coneSize)); 1096 PetscCall(DMPlexGetSupportSize(dm, oldp, &supportSize)); 1097 PetscCall(DMPlexSetSupportSize(sdm, splitp, supportSize)); 1098 PetscCall(DMPlexGetCellType(dm, oldp, &ct)); 1099 PetscCall(DMPlexSetCellType(sdm, splitp, ct)); 1100 if (dep == depth-1) { 1101 const PetscInt hybcell = p + pMaxNew[dep+1] + numSplitPoints[dep+1]; 1102 1103 /* Add cohesive cells, they are prisms */ 1104 PetscCall(DMPlexSetConeSize(sdm, hybcell, 2 + coneSize)); 1105 switch (coneSize) { 1106 case 2: PetscCall(DMPlexSetCellType(sdm, hybcell, DM_POLYTOPE_SEG_PRISM_TENSOR));break; 1107 case 3: PetscCall(DMPlexSetCellType(sdm, hybcell, DM_POLYTOPE_TRI_PRISM_TENSOR));break; 1108 case 4: PetscCall(DMPlexSetCellType(sdm, hybcell, DM_POLYTOPE_QUAD_PRISM_TENSOR));break; 1109 } 1110 /* Shared fault faces with only one support cell now have two with the cohesive cell */ 1111 /* TODO Check thaat oldp has rootdegree == 1 */ 1112 if (supportSize == 1) { 1113 const PetscInt *support; 1114 PetscInt val; 1115 1116 PetscCall(DMPlexGetSupport(dm, oldp, &support)); 1117 PetscCall(DMLabelGetValue(label, support[0], &val)); 1118 if (val < 0) PetscCall(DMPlexSetSupportSize(sdm, splitp, 2)); 1119 else PetscCall(DMPlexSetSupportSize(sdm, newp, 2)); 1120 } 1121 } else if (dep == 0) { 1122 const PetscInt hybedge = p + pMaxNew[dep+1] + numSplitPoints[dep+1]; 1123 1124 PetscCall(DMPlexGetSupport(dm, oldp, &support)); 1125 for (e = 0, qn = 0, qp = 0, qf = 0; e < supportSize; ++e) { 1126 PetscInt val; 1127 1128 PetscCall(DMLabelGetValue(label, support[e], &val)); 1129 if (val == 1) ++qf; 1130 if ((val == 1) || (val == (shift + 1))) ++qn; 1131 if ((val == 1) || (val == -(shift + 1))) ++qp; 1132 } 1133 /* Split old vertex: Edges into original vertex and new cohesive edge */ 1134 PetscCall(DMPlexSetSupportSize(sdm, newp, qn+1)); 1135 /* Split new vertex: Edges into split vertex and new cohesive edge */ 1136 PetscCall(DMPlexSetSupportSize(sdm, splitp, qp+1)); 1137 /* Add hybrid edge */ 1138 PetscCall(DMPlexSetConeSize(sdm, hybedge, 2)); 1139 PetscCall(DMPlexSetSupportSize(sdm, hybedge, qf)); 1140 PetscCall(DMPlexSetCellType(sdm, hybedge, DM_POLYTOPE_POINT_PRISM_TENSOR)); 1141 } else if (dep == dim-2) { 1142 const PetscInt hybface = p + pMaxNew[dep+1] + numSplitPoints[dep+1]; 1143 1144 PetscCall(DMPlexGetSupport(dm, oldp, &support)); 1145 for (e = 0, qn = 0, qp = 0, qf = 0; e < supportSize; ++e) { 1146 PetscInt val; 1147 1148 PetscCall(DMLabelGetValue(label, support[e], &val)); 1149 if (val == dim-1) ++qf; 1150 if ((val == dim-1) || (val == (shift + dim-1))) ++qn; 1151 if ((val == dim-1) || (val == -(shift + dim-1))) ++qp; 1152 } 1153 /* Split old edge: Faces into original edge and cohesive face (positive side?) */ 1154 PetscCall(DMPlexSetSupportSize(sdm, newp, qn+1)); 1155 /* Split new edge: Faces into split edge and cohesive face (negative side?) */ 1156 PetscCall(DMPlexSetSupportSize(sdm, splitp, qp+1)); 1157 /* Add hybrid face */ 1158 PetscCall(DMPlexSetConeSize(sdm, hybface, 4)); 1159 PetscCall(DMPlexSetSupportSize(sdm, hybface, qf)); 1160 PetscCall(DMPlexSetCellType(sdm, hybface, DM_POLYTOPE_SEG_PRISM_TENSOR)); 1161 } 1162 } 1163 } 1164 for (dep = 0; dep <= depth; ++dep) { 1165 for (p = 0; p < numUnsplitPoints[dep]; ++p) { 1166 const PetscInt oldp = unsplitPoints[dep][p]; 1167 const PetscInt newp = DMPlexShiftPoint_Internal(oldp, depth, depthShift) /*oldp + depthOffset[dep]*/; 1168 const PetscInt *support; 1169 PetscInt coneSize, supportSize, qf, e, s; 1170 1171 PetscCall(DMPlexGetConeSize(dm, oldp, &coneSize)); 1172 PetscCall(DMPlexGetSupportSize(dm, oldp, &supportSize)); 1173 PetscCall(DMPlexGetSupport(dm, oldp, &support)); 1174 if (dep == 0) { 1175 const PetscInt hybedge = p + pMaxNew[dep+1] + numSplitPoints[dep+1] + numSplitPoints[dep]; 1176 1177 /* Unsplit vertex: Edges into original vertex, split edges, and new cohesive edge twice */ 1178 for (s = 0, qf = 0; s < supportSize; ++s, ++qf) { 1179 PetscCall(PetscFindInt(support[s], numSplitPoints[dep+1], splitPoints[dep+1], &e)); 1180 if (e >= 0) ++qf; 1181 } 1182 PetscCall(DMPlexSetSupportSize(sdm, newp, qf+2)); 1183 /* Add hybrid edge */ 1184 PetscCall(DMPlexSetConeSize(sdm, hybedge, 2)); 1185 for (e = 0, qf = 0; e < supportSize; ++e) { 1186 PetscInt val; 1187 1188 PetscCall(DMLabelGetValue(label, support[e], &val)); 1189 /* Split and unsplit edges produce hybrid faces */ 1190 if (val == 1) ++qf; 1191 if (val == (shift2 + 1)) ++qf; 1192 } 1193 PetscCall(DMPlexSetSupportSize(sdm, hybedge, qf)); 1194 PetscCall(DMPlexSetCellType(sdm, hybedge, DM_POLYTOPE_POINT_PRISM_TENSOR)); 1195 } else if (dep == dim-2) { 1196 const PetscInt hybface = p + pMaxNew[dep+1] + numSplitPoints[dep+1] + numSplitPoints[dep]; 1197 PetscInt val; 1198 1199 for (e = 0, qf = 0; e < supportSize; ++e) { 1200 PetscCall(DMLabelGetValue(label, support[e], &val)); 1201 if (val == dim-1) qf += 2; 1202 else ++qf; 1203 } 1204 /* Unsplit edge: Faces into original edge, split face, and cohesive face twice */ 1205 PetscCall(DMPlexSetSupportSize(sdm, newp, qf+2)); 1206 /* Add hybrid face */ 1207 for (e = 0, qf = 0; e < supportSize; ++e) { 1208 PetscCall(DMLabelGetValue(label, support[e], &val)); 1209 if (val == dim-1) ++qf; 1210 } 1211 PetscCall(DMPlexSetConeSize(sdm, hybface, 4)); 1212 PetscCall(DMPlexSetSupportSize(sdm, hybface, qf)); 1213 PetscCall(DMPlexSetCellType(sdm, hybface, DM_POLYTOPE_SEG_PRISM_TENSOR)); 1214 } 1215 } 1216 } 1217 /* Step 4: Setup split DM */ 1218 PetscCall(DMSetUp(sdm)); 1219 PetscCall(DMPlexShiftPoints_Internal(dm, depthShift, sdm)); 1220 PetscCall(DMPlexGetMaxSizes(sdm, &maxConeSizeNew, &maxSupportSizeNew)); 1221 PetscCall(PetscMalloc3(PetscMax(maxConeSize, maxConeSizeNew)*3,&coneNew,PetscMax(maxConeSize, maxConeSizeNew)*3,&coneONew,PetscMax(maxSupportSize, maxSupportSizeNew),&supportNew)); 1222 /* Step 6: Set cones and supports for new points */ 1223 for (dep = 0; dep <= depth; ++dep) { 1224 for (p = 0; p < numSplitPoints[dep]; ++p) { 1225 const PetscInt oldp = splitPoints[dep][p]; 1226 const PetscInt newp = DMPlexShiftPoint_Internal(oldp, depth, depthShift) /*oldp + depthOffset[dep]*/; 1227 const PetscInt splitp = p + pMaxNew[dep]; 1228 const PetscInt *cone, *support, *ornt; 1229 DMPolytopeType ct; 1230 PetscInt coneSize, supportSize, q, qf, qn, qp, v, e, s; 1231 1232 PetscCall(DMPlexGetCellType(dm, oldp, &ct)); 1233 PetscCall(DMPlexGetConeSize(dm, oldp, &coneSize)); 1234 PetscCall(DMPlexGetCone(dm, oldp, &cone)); 1235 PetscCall(DMPlexGetConeOrientation(dm, oldp, &ornt)); 1236 PetscCall(DMPlexGetSupportSize(dm, oldp, &supportSize)); 1237 PetscCall(DMPlexGetSupport(dm, oldp, &support)); 1238 if (dep == depth-1) { 1239 PetscBool hasUnsplit = PETSC_FALSE; 1240 const PetscInt hybcell = p + pMaxNew[dep+1] + numSplitPoints[dep+1]; 1241 const PetscInt *supportF; 1242 1243 coneONew[0] = coneONew[1] = -1000; 1244 /* Split face: copy in old face to new face to start */ 1245 PetscCall(DMPlexGetSupport(sdm, newp, &supportF)); 1246 PetscCall(DMPlexSetSupport(sdm, splitp, supportF)); 1247 /* Split old face: old vertices/edges in cone so no change */ 1248 /* Split new face: new vertices/edges in cone */ 1249 for (q = 0; q < coneSize; ++q) { 1250 PetscCall(PetscFindInt(cone[q], numSplitPoints[dep-1], splitPoints[dep-1], &v)); 1251 if (v < 0) { 1252 PetscCall(PetscFindInt(cone[q], numUnsplitPoints[dep-1], unsplitPoints[dep-1], &v)); 1253 PetscCheck(v >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate point %d in split or unsplit points of depth %d", cone[q], dep-1); 1254 coneNew[2+q] = DMPlexShiftPoint_Internal(cone[q], depth, depthShift) /*cone[q] + depthOffset[dep-1]*/; 1255 hasUnsplit = PETSC_TRUE; 1256 } else { 1257 coneNew[2+q] = v + pMaxNew[dep-1]; 1258 if (dep > 1) { 1259 const PetscInt *econe; 1260 PetscInt econeSize, r, vs, vu; 1261 1262 PetscCall(DMPlexGetConeSize(dm, cone[q], &econeSize)); 1263 PetscCall(DMPlexGetCone(dm, cone[q], &econe)); 1264 for (r = 0; r < econeSize; ++r) { 1265 PetscCall(PetscFindInt(econe[r], numSplitPoints[dep-2], splitPoints[dep-2], &vs)); 1266 PetscCall(PetscFindInt(econe[r], numUnsplitPoints[dep-2], unsplitPoints[dep-2], &vu)); 1267 if (vs >= 0) continue; 1268 PetscCheck(vu >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate point %d in split or unsplit points of depth %d", econe[r], dep-2); 1269 hasUnsplit = PETSC_TRUE; 1270 } 1271 } 1272 } 1273 } 1274 PetscCall(DMPlexSetCone(sdm, splitp, &coneNew[2])); 1275 PetscCall(DMPlexSetConeOrientation(sdm, splitp, ornt)); 1276 /* Face support */ 1277 PetscInt vals[2]; 1278 1279 PetscCall(DMLabelGetValue(label, support[0], &vals[0])); 1280 if (supportSize > 1) PetscCall(DMLabelGetValue(label, support[1], &vals[1])); 1281 else vals[1] = -vals[0]; 1282 PetscCheck(vals[0]*vals[1] < 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid support labels %" PetscInt_FMT " %" PetscInt_FMT, vals[0], vals[1]); 1283 1284 for (s = 0; s < 2; ++s) { 1285 if (s >= supportSize) { 1286 if (vals[s] < 0) { 1287 /* Ghost old face: Replace negative side cell with cohesive cell */ 1288 PetscCall(DMPlexInsertSupport(sdm, newp, 0, hybcell)); 1289 } else { 1290 /* Ghost new face: Replace positive side cell with cohesive cell */ 1291 PetscCall(DMPlexInsertSupport(sdm, splitp, 0, hybcell)); 1292 } 1293 } else { 1294 if (vals[s] < 0) { 1295 /* Split old face: Replace negative side cell with cohesive cell */ 1296 PetscCall(DMPlexInsertSupport(sdm, newp, s, hybcell)); 1297 } else { 1298 /* Split new face: Replace positive side cell with cohesive cell */ 1299 PetscCall(DMPlexInsertSupport(sdm, splitp, s, hybcell)); 1300 } 1301 } 1302 } 1303 /* Get orientation for cohesive face using the positive side cell */ 1304 { 1305 const PetscInt *ncone, *nconeO; 1306 PetscInt nconeSize, nc, ocell; 1307 PetscBool flip; 1308 1309 if (supportSize > 1) {ocell = vals[0] < 0 ? support[1] : support[0];} 1310 else {ocell = support[0]; flip = vals[0] < 0 ? PETSC_TRUE : PETSC_FALSE;} 1311 PetscCall(DMPlexGetConeSize(dm, ocell, &nconeSize)); 1312 PetscCall(DMPlexGetCone(dm, ocell, &ncone)); 1313 PetscCall(DMPlexGetConeOrientation(dm, support[s], &nconeO)); 1314 for (nc = 0; nc < nconeSize; ++nc) { 1315 if (ncone[nc] == oldp) { 1316 coneONew[0] = flip ? -(nconeO[nc]+1) : nconeO[nc]; 1317 break; 1318 } 1319 } 1320 PetscCheck(nc < nconeSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate face %" PetscInt_FMT " in neighboring cell %" PetscInt_FMT, oldp, ocell); 1321 } 1322 /* Cohesive cell: Old and new split face, then new cohesive faces */ 1323 { 1324 const PetscInt No = DMPolytopeTypeGetNumArrangments(ct)/2; 1325 PetscCheck((coneONew[0] >= -No) && (coneONew[0] < No), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid %s orientation %" PetscInt_FMT, DMPolytopeTypes[ct], coneONew[0]); 1326 } 1327 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, coneONew[0]); 1328 1329 coneNew[0] = newp; /* Extracted negative side orientation above */ 1330 coneNew[1] = splitp; 1331 coneONew[1] = coneONew[0]; 1332 for (q = 0; q < coneSize; ++q) { 1333 /* Hybrid faces must follow order from oriented end face */ 1334 const PetscInt qa = arr[q*2+0]; 1335 const PetscInt qo = arr[q*2+1]; 1336 DMPolytopeType ft = dep == 2 ? DM_POLYTOPE_SEGMENT : DM_POLYTOPE_POINT; 1337 1338 PetscCall(PetscFindInt(cone[qa], numSplitPoints[dep-1], splitPoints[dep-1], &v)); 1339 if (v < 0) { 1340 PetscCall(PetscFindInt(cone[qa], numUnsplitPoints[dep-1], unsplitPoints[dep-1], &v)); 1341 coneNew[2+q] = v + pMaxNew[dep] + numSplitPoints[dep] + numSplitPoints[dep-1]; 1342 } else { 1343 coneNew[2+q] = v + pMaxNew[dep] + numSplitPoints[dep]; 1344 } 1345 coneONew[2+q] = DMPolytopeTypeComposeOrientation(ft, qo, ornt[qa]); 1346 } 1347 PetscCall(DMPlexSetCone(sdm, hybcell, coneNew)); 1348 PetscCall(DMPlexSetConeOrientation(sdm, hybcell, coneONew)); 1349 /* Label the hybrid cells on the boundary of the split */ 1350 if (hasUnsplit) PetscCall(DMLabelSetValue(label, -hybcell, dim)); 1351 } else if (dep == 0) { 1352 const PetscInt hybedge = p + pMaxNew[dep+1] + numSplitPoints[dep+1]; 1353 1354 /* Split old vertex: Edges in old split faces and new cohesive edge */ 1355 for (e = 0, qn = 0; e < supportSize; ++e) { 1356 PetscInt val; 1357 1358 PetscCall(DMLabelGetValue(label, support[e], &val)); 1359 if ((val == 1) || (val == (shift + 1))) { 1360 supportNew[qn++] = DMPlexShiftPoint_Internal(support[e], depth, depthShift) /*support[e] + depthOffset[dep+1]*/; 1361 } 1362 } 1363 supportNew[qn] = hybedge; 1364 PetscCall(DMPlexSetSupport(sdm, newp, supportNew)); 1365 /* Split new vertex: Edges in new split faces and new cohesive edge */ 1366 for (e = 0, qp = 0; e < supportSize; ++e) { 1367 PetscInt val, edge; 1368 1369 PetscCall(DMLabelGetValue(label, support[e], &val)); 1370 if (val == 1) { 1371 PetscCall(PetscFindInt(support[e], numSplitPoints[dep+1], splitPoints[dep+1], &edge)); 1372 PetscCheck(edge >= 0,comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a split edge", support[e]); 1373 supportNew[qp++] = edge + pMaxNew[dep+1]; 1374 } else if (val == -(shift + 1)) { 1375 supportNew[qp++] = DMPlexShiftPoint_Internal(support[e], depth, depthShift) /*support[e] + depthOffset[dep+1]*/; 1376 } 1377 } 1378 supportNew[qp] = hybedge; 1379 PetscCall(DMPlexSetSupport(sdm, splitp, supportNew)); 1380 /* Hybrid edge: Old and new split vertex */ 1381 coneNew[0] = newp; 1382 coneNew[1] = splitp; 1383 PetscCall(DMPlexSetCone(sdm, hybedge, coneNew)); 1384 for (e = 0, qf = 0; e < supportSize; ++e) { 1385 PetscInt val, edge; 1386 1387 PetscCall(DMLabelGetValue(label, support[e], &val)); 1388 if (val == 1) { 1389 PetscCall(PetscFindInt(support[e], numSplitPoints[dep+1], splitPoints[dep+1], &edge)); 1390 PetscCheck(edge >= 0,comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a split edge", support[e]); 1391 supportNew[qf++] = edge + pMaxNew[dep+2] + numSplitPoints[dep+2]; 1392 } 1393 } 1394 PetscCall(DMPlexSetSupport(sdm, hybedge, supportNew)); 1395 } else if (dep == dim-2) { 1396 const PetscInt hybface = p + pMaxNew[dep+1] + numSplitPoints[dep+1]; 1397 1398 /* Split old edge: old vertices in cone so no change */ 1399 /* Split new edge: new vertices in cone */ 1400 for (q = 0; q < coneSize; ++q) { 1401 PetscCall(PetscFindInt(cone[q], numSplitPoints[dep-1], splitPoints[dep-1], &v)); 1402 if (v < 0) { 1403 PetscCall(PetscFindInt(cone[q], numUnsplitPoints[dep-1], unsplitPoints[dep-1], &v)); 1404 PetscCheck(v >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate point %d in split or unsplit points of depth %d", cone[q], dep-1); 1405 coneNew[q] = DMPlexShiftPoint_Internal(cone[q], depth, depthShift) /*cone[q] + depthOffset[dep-1]*/; 1406 } else { 1407 coneNew[q] = v + pMaxNew[dep-1]; 1408 } 1409 } 1410 PetscCall(DMPlexSetCone(sdm, splitp, coneNew)); 1411 /* Split old edge: Faces in positive side cells and old split faces */ 1412 for (e = 0, q = 0; e < supportSize; ++e) { 1413 PetscInt val; 1414 1415 PetscCall(DMLabelGetValue(label, support[e], &val)); 1416 if (val == dim-1) { 1417 supportNew[q++] = DMPlexShiftPoint_Internal(support[e], depth, depthShift) /*support[e] + depthOffset[dep+1]*/; 1418 } else if (val == (shift + dim-1)) { 1419 supportNew[q++] = DMPlexShiftPoint_Internal(support[e], depth, depthShift) /*support[e] + depthOffset[dep+1]*/; 1420 } 1421 } 1422 supportNew[q++] = p + pMaxNew[dep+1] + numSplitPoints[dep+1]; 1423 PetscCall(DMPlexSetSupport(sdm, newp, supportNew)); 1424 /* Split new edge: Faces in negative side cells and new split faces */ 1425 for (e = 0, q = 0; e < supportSize; ++e) { 1426 PetscInt val, face; 1427 1428 PetscCall(DMLabelGetValue(label, support[e], &val)); 1429 if (val == dim-1) { 1430 PetscCall(PetscFindInt(support[e], numSplitPoints[dep+1], splitPoints[dep+1], &face)); 1431 PetscCheck(face >= 0,comm, PETSC_ERR_ARG_WRONG, "Face %d is not a split face", support[e]); 1432 supportNew[q++] = face + pMaxNew[dep+1]; 1433 } else if (val == -(shift + dim-1)) { 1434 supportNew[q++] = DMPlexShiftPoint_Internal(support[e], depth, depthShift) /*support[e] + depthOffset[dep+1]*/; 1435 } 1436 } 1437 supportNew[q++] = p + pMaxNew[dep+1] + numSplitPoints[dep+1]; 1438 PetscCall(DMPlexSetSupport(sdm, splitp, supportNew)); 1439 /* Hybrid face */ 1440 coneNew[0] = newp; 1441 coneNew[1] = splitp; 1442 for (v = 0; v < coneSize; ++v) { 1443 PetscInt vertex; 1444 PetscCall(PetscFindInt(cone[v], numSplitPoints[dep-1], splitPoints[dep-1], &vertex)); 1445 if (vertex < 0) { 1446 PetscCall(PetscFindInt(cone[v], numUnsplitPoints[dep-1], unsplitPoints[dep-1], &vertex)); 1447 PetscCheck(vertex >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate point %d in split or unsplit points of depth %d", cone[v], dep-1); 1448 coneNew[2+v] = vertex + pMaxNew[dep] + numSplitPoints[dep] + numSplitPoints[dep-1]; 1449 } else { 1450 coneNew[2+v] = vertex + pMaxNew[dep] + numSplitPoints[dep]; 1451 } 1452 } 1453 PetscCall(DMPlexSetCone(sdm, hybface, coneNew)); 1454 for (e = 0, qf = 0; e < supportSize; ++e) { 1455 PetscInt val, face; 1456 1457 PetscCall(DMLabelGetValue(label, support[e], &val)); 1458 if (val == dim-1) { 1459 PetscCall(PetscFindInt(support[e], numSplitPoints[dep+1], splitPoints[dep+1], &face)); 1460 PetscCheck(face >= 0,comm, PETSC_ERR_ARG_WRONG, "Face %d is not a split face", support[e]); 1461 supportNew[qf++] = face + pMaxNew[dep+2] + numSplitPoints[dep+2]; 1462 } 1463 } 1464 PetscCall(DMPlexSetSupport(sdm, hybface, supportNew)); 1465 } 1466 } 1467 } 1468 for (dep = 0; dep <= depth; ++dep) { 1469 for (p = 0; p < numUnsplitPoints[dep]; ++p) { 1470 const PetscInt oldp = unsplitPoints[dep][p]; 1471 const PetscInt newp = DMPlexShiftPoint_Internal(oldp, depth, depthShift) /*oldp + depthOffset[dep]*/; 1472 const PetscInt *cone, *support; 1473 PetscInt coneSize, supportSize, supportSizeNew, q, qf, e, f, s; 1474 1475 PetscCall(DMPlexGetConeSize(dm, oldp, &coneSize)); 1476 PetscCall(DMPlexGetCone(dm, oldp, &cone)); 1477 PetscCall(DMPlexGetSupportSize(dm, oldp, &supportSize)); 1478 PetscCall(DMPlexGetSupport(dm, oldp, &support)); 1479 if (dep == 0) { 1480 const PetscInt hybedge = p + pMaxNew[dep+1] + numSplitPoints[dep+1] + numSplitPoints[dep]; 1481 1482 /* Unsplit vertex */ 1483 PetscCall(DMPlexGetSupportSize(sdm, newp, &supportSizeNew)); 1484 for (s = 0, q = 0; s < supportSize; ++s) { 1485 supportNew[q++] = DMPlexShiftPoint_Internal(support[s], depth, depthShift) /*support[s] + depthOffset[dep+1]*/; 1486 PetscCall(PetscFindInt(support[s], numSplitPoints[dep+1], splitPoints[dep+1], &e)); 1487 if (e >= 0) { 1488 supportNew[q++] = e + pMaxNew[dep+1]; 1489 } 1490 } 1491 supportNew[q++] = hybedge; 1492 supportNew[q++] = hybedge; 1493 PetscCheck(q == supportSizeNew,comm, PETSC_ERR_ARG_WRONG, "Support size %d != %d for vertex %d", q, supportSizeNew, newp); 1494 PetscCall(DMPlexSetSupport(sdm, newp, supportNew)); 1495 /* Hybrid edge */ 1496 coneNew[0] = newp; 1497 coneNew[1] = newp; 1498 PetscCall(DMPlexSetCone(sdm, hybedge, coneNew)); 1499 for (e = 0, qf = 0; e < supportSize; ++e) { 1500 PetscInt val, edge; 1501 1502 PetscCall(DMLabelGetValue(label, support[e], &val)); 1503 if (val == 1) { 1504 PetscCall(PetscFindInt(support[e], numSplitPoints[dep+1], splitPoints[dep+1], &edge)); 1505 PetscCheck(edge >= 0,comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a split edge", support[e]); 1506 supportNew[qf++] = edge + pMaxNew[dep+2] + numSplitPoints[dep+2]; 1507 } else if (val == (shift2 + 1)) { 1508 PetscCall(PetscFindInt(support[e], numUnsplitPoints[dep+1], unsplitPoints[dep+1], &edge)); 1509 PetscCheck(edge >= 0,comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a unsplit edge", support[e]); 1510 supportNew[qf++] = edge + pMaxNew[dep+2] + numSplitPoints[dep+2] + numSplitPoints[dep+1]; 1511 } 1512 } 1513 PetscCall(DMPlexSetSupport(sdm, hybedge, supportNew)); 1514 } else if (dep == dim-2) { 1515 const PetscInt hybface = p + pMaxNew[dep+1] + numSplitPoints[dep+1] + numSplitPoints[dep]; 1516 1517 /* Unsplit edge: Faces into original edge, split face, and hybrid face twice */ 1518 for (f = 0, qf = 0; f < supportSize; ++f) { 1519 PetscInt val, face; 1520 1521 PetscCall(DMLabelGetValue(label, support[f], &val)); 1522 if (val == dim-1) { 1523 PetscCall(PetscFindInt(support[f], numSplitPoints[dep+1], splitPoints[dep+1], &face)); 1524 PetscCheck(face >= 0,comm, PETSC_ERR_ARG_WRONG, "Face %d is not a split face", support[f]); 1525 supportNew[qf++] = DMPlexShiftPoint_Internal(support[f], depth, depthShift) /*support[f] + depthOffset[dep+1]*/; 1526 supportNew[qf++] = face + pMaxNew[dep+1]; 1527 } else { 1528 supportNew[qf++] = DMPlexShiftPoint_Internal(support[f], depth, depthShift) /*support[f] + depthOffset[dep+1]*/; 1529 } 1530 } 1531 supportNew[qf++] = hybface; 1532 supportNew[qf++] = hybface; 1533 PetscCall(DMPlexGetSupportSize(sdm, newp, &supportSizeNew)); 1534 PetscCheck(qf == supportSizeNew,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Support size for unsplit edge %d is %d != %d", newp, qf, supportSizeNew); 1535 PetscCall(DMPlexSetSupport(sdm, newp, supportNew)); 1536 /* Add hybrid face */ 1537 coneNew[0] = newp; 1538 coneNew[1] = newp; 1539 PetscCall(PetscFindInt(cone[0], numUnsplitPoints[dep-1], unsplitPoints[dep-1], &v)); 1540 PetscCheck(v >= 0,comm, PETSC_ERR_ARG_WRONG, "Vertex %d is not an unsplit vertex", cone[0]); 1541 coneNew[2] = v + pMaxNew[dep] + numSplitPoints[dep] + numSplitPoints[dep-1]; 1542 PetscCall(PetscFindInt(cone[1], numUnsplitPoints[dep-1], unsplitPoints[dep-1], &v)); 1543 PetscCheck(v >= 0,comm, PETSC_ERR_ARG_WRONG, "Vertex %d is not an unsplit vertex", cone[1]); 1544 coneNew[3] = v + pMaxNew[dep] + numSplitPoints[dep] + numSplitPoints[dep-1]; 1545 PetscCall(DMPlexSetCone(sdm, hybface, coneNew)); 1546 for (f = 0, qf = 0; f < supportSize; ++f) { 1547 PetscInt val, face; 1548 1549 PetscCall(DMLabelGetValue(label, support[f], &val)); 1550 if (val == dim-1) { 1551 PetscCall(PetscFindInt(support[f], numSplitPoints[dep+1], splitPoints[dep+1], &face)); 1552 supportNew[qf++] = face + pMaxNew[dep+2] + numSplitPoints[dep+2]; 1553 } 1554 } 1555 PetscCall(DMPlexGetSupportSize(sdm, hybface, &supportSizeNew)); 1556 PetscCheck(qf == supportSizeNew,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Support size for hybrid face %d is %d != %d", hybface, qf, supportSizeNew); 1557 PetscCall(DMPlexSetSupport(sdm, hybface, supportNew)); 1558 } 1559 } 1560 } 1561 /* Step 6b: Replace split points in negative side cones */ 1562 for (sp = 0; sp < numSP; ++sp) { 1563 PetscInt dep = values[sp]; 1564 IS pIS; 1565 PetscInt numPoints; 1566 const PetscInt *points; 1567 1568 if (dep >= 0) continue; 1569 PetscCall(DMLabelGetStratumIS(label, dep, &pIS)); 1570 if (!pIS) continue; 1571 dep = -dep - shift; 1572 PetscCall(ISGetLocalSize(pIS, &numPoints)); 1573 PetscCall(ISGetIndices(pIS, &points)); 1574 for (p = 0; p < numPoints; ++p) { 1575 const PetscInt oldp = points[p]; 1576 const PetscInt newp = DMPlexShiftPoint_Internal(oldp, depth, depthShift) /*depthOffset[dep] + oldp*/; 1577 const PetscInt *cone; 1578 PetscInt coneSize, c; 1579 /* PetscBool replaced = PETSC_FALSE; */ 1580 1581 /* Negative edge: replace split vertex */ 1582 /* Negative cell: replace split face */ 1583 PetscCall(DMPlexGetConeSize(sdm, newp, &coneSize)); 1584 PetscCall(DMPlexGetCone(sdm, newp, &cone)); 1585 for (c = 0; c < coneSize; ++c) { 1586 const PetscInt coldp = DMPlexShiftPointInverse_Internal(cone[c],depth,depthShift); 1587 PetscInt csplitp, cp, val; 1588 1589 PetscCall(DMLabelGetValue(label, coldp, &val)); 1590 if (val == dep-1) { 1591 PetscCall(PetscFindInt(coldp, numSplitPoints[dep-1], splitPoints[dep-1], &cp)); 1592 PetscCheck(cp >= 0,comm, PETSC_ERR_ARG_WRONG, "Point %d is not a split point of dimension %d", oldp, dep-1); 1593 csplitp = pMaxNew[dep-1] + cp; 1594 PetscCall(DMPlexInsertCone(sdm, newp, c, csplitp)); 1595 /* replaced = PETSC_TRUE; */ 1596 } 1597 } 1598 /* Cells with only a vertex or edge on the submesh have no replacement */ 1599 /* PetscCheck(replaced,comm, PETSC_ERR_ARG_WRONG, "The cone of point %d does not contain split points", oldp); */ 1600 } 1601 PetscCall(ISRestoreIndices(pIS, &points)); 1602 PetscCall(ISDestroy(&pIS)); 1603 } 1604 /* Step 7: Coordinates */ 1605 PetscCall(DMPlexShiftCoordinates_Internal(dm, depthShift, sdm)); 1606 PetscCall(DMGetCoordinateSection(sdm, &coordSection)); 1607 PetscCall(DMGetCoordinatesLocal(sdm, &coordinates)); 1608 PetscCall(VecGetArray(coordinates, &coords)); 1609 for (v = 0; v < (numSplitPoints ? numSplitPoints[0] : 0); ++v) { 1610 const PetscInt newp = DMPlexShiftPoint_Internal(splitPoints[0][v], depth, depthShift) /*depthOffset[0] + splitPoints[0][v]*/; 1611 const PetscInt splitp = pMaxNew[0] + v; 1612 PetscInt dof, off, soff, d; 1613 1614 PetscCall(PetscSectionGetDof(coordSection, newp, &dof)); 1615 PetscCall(PetscSectionGetOffset(coordSection, newp, &off)); 1616 PetscCall(PetscSectionGetOffset(coordSection, splitp, &soff)); 1617 for (d = 0; d < dof; ++d) coords[soff+d] = coords[off+d]; 1618 } 1619 PetscCall(VecRestoreArray(coordinates, &coords)); 1620 /* Step 8: SF, if I can figure this out we can split the mesh in parallel */ 1621 PetscCall(DMPlexShiftSF_Internal(dm, depthShift, sdm)); 1622 /* TODO We need to associate the ghost points with the correct replica */ 1623 /* Step 9: Labels */ 1624 PetscCall(DMPlexShiftLabels_Internal(dm, depthShift, sdm)); 1625 PetscCall(DMPlexCreateVTKLabel_Internal(dm, PETSC_FALSE, sdm)); 1626 PetscCall(DMGetNumLabels(sdm, &numLabels)); 1627 for (dep = 0; dep <= depth; ++dep) { 1628 for (p = 0; p < numSplitPoints[dep]; ++p) { 1629 const PetscInt newp = DMPlexShiftPoint_Internal(splitPoints[dep][p], depth, depthShift) /*depthOffset[dep] + splitPoints[dep][p]*/; 1630 const PetscInt splitp = pMaxNew[dep] + p; 1631 PetscInt l; 1632 1633 if (splitLabel) { 1634 const PetscInt val = 100 + dep; 1635 1636 PetscCall(DMLabelSetValue(splitLabel, newp, val)); 1637 PetscCall(DMLabelSetValue(splitLabel, splitp, -val)); 1638 } 1639 for (l = 0; l < numLabels; ++l) { 1640 DMLabel mlabel; 1641 const char *lname; 1642 PetscInt val; 1643 PetscBool isDepth; 1644 1645 PetscCall(DMGetLabelName(sdm, l, &lname)); 1646 PetscCall(PetscStrcmp(lname, "depth", &isDepth)); 1647 if (isDepth) continue; 1648 PetscCall(DMGetLabel(sdm, lname, &mlabel)); 1649 PetscCall(DMLabelGetValue(mlabel, newp, &val)); 1650 if (val >= 0) { 1651 PetscCall(DMLabelSetValue(mlabel, splitp, val)); 1652 } 1653 } 1654 } 1655 } 1656 for (sp = 0; sp < numSP; ++sp) { 1657 const PetscInt dep = values[sp]; 1658 1659 if ((dep < 0) || (dep > depth)) continue; 1660 if (splitIS[dep]) PetscCall(ISRestoreIndices(splitIS[dep], &splitPoints[dep])); 1661 PetscCall(ISDestroy(&splitIS[dep])); 1662 if (unsplitIS[dep]) PetscCall(ISRestoreIndices(unsplitIS[dep], &unsplitPoints[dep])); 1663 PetscCall(ISDestroy(&unsplitIS[dep])); 1664 } 1665 if (ghostIS) PetscCall(ISRestoreIndices(ghostIS, &ghostPoints)); 1666 PetscCall(ISDestroy(&ghostIS)); 1667 if (label) { 1668 PetscCall(ISRestoreIndices(valueIS, &values)); 1669 PetscCall(ISDestroy(&valueIS)); 1670 } 1671 for (d = 0; d <= depth; ++d) { 1672 PetscCall(DMPlexGetDepthStratum(sdm, d, NULL, &pEnd)); 1673 pMaxNew[d] = pEnd - numHybridPoints[d] - numHybridPointsOld[d]; 1674 } 1675 PetscCall(PetscFree3(coneNew, coneONew, supportNew)); 1676 PetscCall(PetscFree5(depthMax, depthEnd, depthShift, pMaxNew, numHybridPointsOld)); 1677 PetscCall(PetscFree7(splitIS, unsplitIS, numSplitPoints, numUnsplitPoints, numHybridPoints, splitPoints, unsplitPoints)); 1678 PetscFunctionReturn(0); 1679 } 1680 1681 /*@C 1682 DMPlexConstructCohesiveCells - Construct cohesive cells which split the face along an internal interface 1683 1684 Collective on dm 1685 1686 Input Parameters: 1687 + dm - The original DM 1688 - label - The label specifying the boundary faces (this could be auto-generated) 1689 1690 Output Parameters: 1691 + splitLabel - The label containing the split points, or NULL if no output is desired 1692 - dmSplit - The new DM 1693 1694 Level: developer 1695 1696 .seealso: DMCreate(), DMPlexLabelCohesiveComplete() 1697 @*/ 1698 PetscErrorCode DMPlexConstructCohesiveCells(DM dm, DMLabel label, DMLabel splitLabel, DM *dmSplit) 1699 { 1700 DM sdm; 1701 PetscInt dim; 1702 1703 PetscFunctionBegin; 1704 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1705 PetscValidPointer(dmSplit, 4); 1706 PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &sdm)); 1707 PetscCall(DMSetType(sdm, DMPLEX)); 1708 PetscCall(DMGetDimension(dm, &dim)); 1709 PetscCall(DMSetDimension(sdm, dim)); 1710 switch (dim) { 1711 case 2: 1712 case 3: 1713 PetscCall(DMPlexConstructCohesiveCells_Internal(dm, label, splitLabel, sdm)); 1714 break; 1715 default: 1716 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct cohesive cells for dimension %d", dim); 1717 } 1718 *dmSplit = sdm; 1719 PetscFunctionReturn(0); 1720 } 1721 1722 /* Returns the side of the surface for a given cell with a face on the surface */ 1723 static PetscErrorCode GetSurfaceSide_Static(DM dm, DM subdm, PetscInt numSubpoints, const PetscInt *subpoints, PetscInt cell, PetscInt face, PetscBool *pos) 1724 { 1725 const PetscInt *cone, *ornt; 1726 PetscInt dim, coneSize, c; 1727 1728 PetscFunctionBegin; 1729 *pos = PETSC_TRUE; 1730 PetscCall(DMGetDimension(dm, &dim)); 1731 PetscCall(DMPlexGetConeSize(dm, cell, &coneSize)); 1732 PetscCall(DMPlexGetCone(dm, cell, &cone)); 1733 PetscCall(DMPlexGetConeOrientation(dm, cell, &ornt)); 1734 for (c = 0; c < coneSize; ++c) { 1735 if (cone[c] == face) { 1736 PetscInt o = ornt[c]; 1737 1738 if (subdm) { 1739 const PetscInt *subcone, *subornt; 1740 PetscInt subpoint, subface, subconeSize, sc; 1741 1742 PetscCall(PetscFindInt(cell, numSubpoints, subpoints, &subpoint)); 1743 PetscCall(PetscFindInt(face, numSubpoints, subpoints, &subface)); 1744 PetscCall(DMPlexGetConeSize(subdm, subpoint, &subconeSize)); 1745 PetscCall(DMPlexGetCone(subdm, subpoint, &subcone)); 1746 PetscCall(DMPlexGetConeOrientation(subdm, subpoint, &subornt)); 1747 for (sc = 0; sc < subconeSize; ++sc) { 1748 if (subcone[sc] == subface) { 1749 o = subornt[0]; 1750 break; 1751 } 1752 } 1753 PetscCheck(sc < subconeSize,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find subpoint %d (%d) in cone for subpoint %d (%d)", subface, face, subpoint, cell); 1754 } 1755 if (o >= 0) *pos = PETSC_TRUE; 1756 else *pos = PETSC_FALSE; 1757 break; 1758 } 1759 } 1760 PetscCheck(c != coneSize,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cell %d in split face %d support does not have it in the cone", cell, face); 1761 PetscFunctionReturn(0); 1762 } 1763 1764 /*@ 1765 DMPlexLabelCohesiveComplete - Starting with a label marking points on an internal surface, we add all other mesh pieces 1766 to complete the surface 1767 1768 Input Parameters: 1769 + dm - The DM 1770 . label - A DMLabel marking the surface 1771 . blabel - A DMLabel marking the vertices on the boundary which will not be duplicated, or NULL to find them automatically 1772 . flip - Flag to flip the submesh normal and replace points on the other side 1773 - subdm - The subDM associated with the label, or NULL 1774 1775 Output Parameter: 1776 . label - A DMLabel marking all surface points 1777 1778 Note: The vertices in blabel are called "unsplit" in the terminology from hybrid cell creation. 1779 1780 Level: developer 1781 1782 .seealso: DMPlexConstructCohesiveCells(), DMPlexLabelComplete() 1783 @*/ 1784 PetscErrorCode DMPlexLabelCohesiveComplete(DM dm, DMLabel label, DMLabel blabel, PetscBool flip, DM subdm) 1785 { 1786 DMLabel depthLabel; 1787 IS dimIS, subpointIS = NULL, facePosIS, faceNegIS, crossEdgeIS = NULL; 1788 const PetscInt *points, *subpoints; 1789 const PetscInt rev = flip ? -1 : 1; 1790 PetscInt shift = 100, shift2 = 200, shift3 = 300, dim, depth, dep, cStart, cEnd, vStart, vEnd, numPoints, numSubpoints, p, val; 1791 1792 PetscFunctionBegin; 1793 PetscCall(DMPlexGetDepth(dm, &depth)); 1794 PetscCall(DMGetDimension(dm, &dim)); 1795 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 1796 if (subdm) { 1797 PetscCall(DMPlexGetSubpointIS(subdm, &subpointIS)); 1798 if (subpointIS) { 1799 PetscCall(ISGetLocalSize(subpointIS, &numSubpoints)); 1800 PetscCall(ISGetIndices(subpointIS, &subpoints)); 1801 } 1802 } 1803 /* Mark cell on the fault, and its faces which touch the fault: cell orientation for face gives the side of the fault */ 1804 PetscCall(DMLabelGetStratumIS(label, dim-1, &dimIS)); 1805 if (!dimIS) PetscFunctionReturn(0); 1806 PetscCall(ISGetLocalSize(dimIS, &numPoints)); 1807 PetscCall(ISGetIndices(dimIS, &points)); 1808 for (p = 0; p < numPoints; ++p) { /* Loop over fault faces */ 1809 const PetscInt *support; 1810 PetscInt supportSize, s; 1811 1812 PetscCall(DMPlexGetSupportSize(dm, points[p], &supportSize)); 1813 #if 0 1814 if (supportSize != 2) { 1815 const PetscInt *lp; 1816 PetscInt Nlp, pind; 1817 1818 /* Check that for a cell with a single support face, that face is in the SF */ 1819 /* THis check only works for the remote side. We would need root side information */ 1820 PetscCall(PetscSFGetGraph(dm->sf, NULL, &Nlp, &lp, NULL)); 1821 PetscCall(PetscFindInt(points[p], Nlp, lp, &pind)); 1822 PetscCheck(pind >= 0,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Split face %d has %d != 2 supports, and the face is not shared with another process", points[p], supportSize); 1823 } 1824 #endif 1825 PetscCall(DMPlexGetSupport(dm, points[p], &support)); 1826 for (s = 0; s < supportSize; ++s) { 1827 const PetscInt *cone; 1828 PetscInt coneSize, c; 1829 PetscBool pos; 1830 1831 PetscCall(GetSurfaceSide_Static(dm, subdm, numSubpoints, subpoints, support[s], points[p], &pos)); 1832 if (pos) PetscCall(DMLabelSetValue(label, support[s], rev*(shift+dim))); 1833 else PetscCall(DMLabelSetValue(label, support[s], -rev*(shift+dim))); 1834 if (rev < 0) pos = !pos ? PETSC_TRUE : PETSC_FALSE; 1835 /* Put faces touching the fault in the label */ 1836 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 1837 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 1838 for (c = 0; c < coneSize; ++c) { 1839 const PetscInt point = cone[c]; 1840 1841 PetscCall(DMLabelGetValue(label, point, &val)); 1842 if (val == -1) { 1843 PetscInt *closure = NULL; 1844 PetscInt closureSize, cl; 1845 1846 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure)); 1847 for (cl = 0; cl < closureSize*2; cl += 2) { 1848 const PetscInt clp = closure[cl]; 1849 PetscInt bval = -1; 1850 1851 PetscCall(DMLabelGetValue(label, clp, &val)); 1852 if (blabel) PetscCall(DMLabelGetValue(blabel, clp, &bval)); 1853 if ((val >= 0) && (val < dim-1) && (bval < 0)) { 1854 PetscCall(DMLabelSetValue(label, point, pos == PETSC_TRUE ? shift+dim-1 : -(shift+dim-1))); 1855 break; 1856 } 1857 } 1858 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure)); 1859 } 1860 } 1861 } 1862 } 1863 /* Mark boundary points as unsplit */ 1864 if (blabel) { 1865 PetscCall(DMLabelGetStratumIS(blabel, 1, &dimIS)); 1866 PetscCall(ISGetLocalSize(dimIS, &numPoints)); 1867 PetscCall(ISGetIndices(dimIS, &points)); 1868 for (p = 0; p < numPoints; ++p) { 1869 const PetscInt point = points[p]; 1870 PetscInt val, bval; 1871 1872 PetscCall(DMLabelGetValue(blabel, point, &bval)); 1873 if (bval >= 0) { 1874 PetscCall(DMLabelGetValue(label, point, &val)); 1875 if ((val < 0) || (val > dim)) { 1876 /* This could be a point added from splitting a vertex on an adjacent fault, otherwise its just wrong */ 1877 PetscCall(DMLabelClearValue(blabel, point, bval)); 1878 } 1879 } 1880 } 1881 for (p = 0; p < numPoints; ++p) { 1882 const PetscInt point = points[p]; 1883 PetscInt val, bval; 1884 1885 PetscCall(DMLabelGetValue(blabel, point, &bval)); 1886 if (bval >= 0) { 1887 const PetscInt *cone, *support; 1888 PetscInt coneSize, supportSize, s, valA, valB, valE; 1889 1890 /* Mark as unsplit */ 1891 PetscCall(DMLabelGetValue(label, point, &val)); 1892 PetscCheck(!(val < 0) && !(val > dim),PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d has label value %d, should be part of the fault", point, val); 1893 PetscCall(DMLabelClearValue(label, point, val)); 1894 PetscCall(DMLabelSetValue(label, point, shift2+val)); 1895 /* Check for cross-edge 1896 A cross-edge has endpoints which are both on the boundary of the surface, but the edge itself is not. */ 1897 if (val != 0) continue; 1898 PetscCall(DMPlexGetSupport(dm, point, &support)); 1899 PetscCall(DMPlexGetSupportSize(dm, point, &supportSize)); 1900 for (s = 0; s < supportSize; ++s) { 1901 PetscCall(DMPlexGetCone(dm, support[s], &cone)); 1902 PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize)); 1903 PetscCheck(coneSize == 2,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Edge %D has %D vertices != 2", support[s], coneSize); 1904 PetscCall(DMLabelGetValue(blabel, cone[0], &valA)); 1905 PetscCall(DMLabelGetValue(blabel, cone[1], &valB)); 1906 PetscCall(DMLabelGetValue(blabel, support[s], &valE)); 1907 if ((valE < 0) && (valA >= 0) && (valB >= 0) && (cone[0] != cone[1])) PetscCall(DMLabelSetValue(blabel, support[s], 2)); 1908 } 1909 } 1910 } 1911 PetscCall(ISRestoreIndices(dimIS, &points)); 1912 PetscCall(ISDestroy(&dimIS)); 1913 } 1914 /* Mark ghost fault cells */ 1915 { 1916 PetscSF sf; 1917 const PetscInt *leaves; 1918 PetscInt Nl, l; 1919 1920 PetscCall(DMGetPointSF(dm, &sf)); 1921 PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &leaves, NULL)); 1922 if (Nl > 0) { 1923 for (p = 0; p < numPoints; ++p) { 1924 const PetscInt point = points[p]; 1925 PetscInt val; 1926 1927 PetscCall(PetscFindInt(point, Nl, leaves, &l)); 1928 if (l >= 0) { 1929 PetscInt *closure = NULL; 1930 PetscInt closureSize, cl; 1931 1932 PetscCall(DMLabelGetValue(label, point, &val)); 1933 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); 1934 PetscCall(DMLabelClearValue(label, point, val)); 1935 PetscCall(DMLabelSetValue(label, point, shift3+val)); 1936 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure)); 1937 for (cl = 0; cl < closureSize*2; cl += 2) { 1938 const PetscInt clp = closure[cl]; 1939 1940 PetscCall(DMLabelGetValue(label, clp, &val)); 1941 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); 1942 PetscCall(DMLabelClearValue(label, clp, val)); 1943 PetscCall(DMLabelSetValue(label, clp, shift3+val)); 1944 } 1945 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure)); 1946 } 1947 } 1948 } 1949 } 1950 PetscCall(ISRestoreIndices(dimIS, &points)); 1951 PetscCall(ISDestroy(&dimIS)); 1952 if (subpointIS) PetscCall(ISRestoreIndices(subpointIS, &subpoints)); 1953 /* Search for other cells/faces/edges connected to the fault by a vertex */ 1954 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1955 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 1956 PetscCall(DMLabelGetStratumIS(label, 0, &dimIS)); 1957 /* TODO Why are we including cross edges here? Shouldn't they be in the star of boundary vertices? */ 1958 if (blabel) PetscCall(DMLabelGetStratumIS(blabel, 2, &crossEdgeIS)); 1959 if (dimIS && crossEdgeIS) { 1960 IS vertIS = dimIS; 1961 1962 PetscCall(ISExpand(vertIS, crossEdgeIS, &dimIS)); 1963 PetscCall(ISDestroy(&crossEdgeIS)); 1964 PetscCall(ISDestroy(&vertIS)); 1965 } 1966 if (!dimIS) { 1967 PetscFunctionReturn(0); 1968 } 1969 PetscCall(ISGetLocalSize(dimIS, &numPoints)); 1970 PetscCall(ISGetIndices(dimIS, &points)); 1971 for (p = 0; p < numPoints; ++p) { /* Loop over fault vertices */ 1972 PetscInt *star = NULL; 1973 PetscInt starSize, s; 1974 PetscInt again = 1; /* 0: Finished 1: Keep iterating after a change 2: No change */ 1975 1976 /* All points connected to the fault are inside a cell, so at the top level we will only check cells */ 1977 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star)); 1978 while (again) { 1979 PetscCheck(again <= 1,PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Could not classify all cells connected to the fault"); 1980 again = 0; 1981 for (s = 0; s < starSize*2; s += 2) { 1982 const PetscInt point = star[s]; 1983 const PetscInt *cone; 1984 PetscInt coneSize, c; 1985 1986 if ((point < cStart) || (point >= cEnd)) continue; 1987 PetscCall(DMLabelGetValue(label, point, &val)); 1988 if (val != -1) continue; 1989 again = again == 1 ? 1 : 2; 1990 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 1991 PetscCall(DMPlexGetCone(dm, point, &cone)); 1992 for (c = 0; c < coneSize; ++c) { 1993 PetscCall(DMLabelGetValue(label, cone[c], &val)); 1994 if (val != -1) { 1995 const PetscInt *ccone; 1996 PetscInt cconeSize, cc, side; 1997 1998 PetscCheck(PetscAbs(val) >= shift,PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Face %d on cell %d has an invalid label %d", cone[c], point, val); 1999 if (val > 0) side = 1; 2000 else side = -1; 2001 PetscCall(DMLabelSetValue(label, point, side*(shift+dim))); 2002 /* Mark cell faces which touch the fault */ 2003 PetscCall(DMPlexGetConeSize(dm, point, &cconeSize)); 2004 PetscCall(DMPlexGetCone(dm, point, &ccone)); 2005 for (cc = 0; cc < cconeSize; ++cc) { 2006 PetscInt *closure = NULL; 2007 PetscInt closureSize, cl; 2008 2009 PetscCall(DMLabelGetValue(label, ccone[cc], &val)); 2010 if (val != -1) continue; 2011 PetscCall(DMPlexGetTransitiveClosure(dm, ccone[cc], PETSC_TRUE, &closureSize, &closure)); 2012 for (cl = 0; cl < closureSize*2; cl += 2) { 2013 const PetscInt clp = closure[cl]; 2014 2015 PetscCall(DMLabelGetValue(label, clp, &val)); 2016 if (val == -1) continue; 2017 PetscCall(DMLabelSetValue(label, ccone[cc], side*(shift+dim-1))); 2018 break; 2019 } 2020 PetscCall(DMPlexRestoreTransitiveClosure(dm, ccone[cc], PETSC_TRUE, &closureSize, &closure)); 2021 } 2022 again = 1; 2023 break; 2024 } 2025 } 2026 } 2027 } 2028 /* Classify the rest by cell membership */ 2029 for (s = 0; s < starSize*2; s += 2) { 2030 const PetscInt point = star[s]; 2031 2032 PetscCall(DMLabelGetValue(label, point, &val)); 2033 if (val == -1) { 2034 PetscInt *sstar = NULL; 2035 PetscInt sstarSize, ss; 2036 PetscBool marked = PETSC_FALSE, isHybrid; 2037 2038 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar)); 2039 for (ss = 0; ss < sstarSize*2; ss += 2) { 2040 const PetscInt spoint = sstar[ss]; 2041 2042 if ((spoint < cStart) || (spoint >= cEnd)) continue; 2043 PetscCall(DMLabelGetValue(label, spoint, &val)); 2044 PetscCheck(val != -1,PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Cell %d in star of %d does not have a valid label", spoint, point); 2045 PetscCall(DMLabelGetValue(depthLabel, point, &dep)); 2046 if (val > 0) { 2047 PetscCall(DMLabelSetValue(label, point, shift+dep)); 2048 } else { 2049 PetscCall(DMLabelSetValue(label, point, -(shift+dep))); 2050 } 2051 marked = PETSC_TRUE; 2052 break; 2053 } 2054 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar)); 2055 PetscCall(DMPlexCellIsHybrid_Internal(dm, point, &isHybrid)); 2056 PetscCheck(isHybrid || marked,PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d could not be classified", point); 2057 } 2058 } 2059 PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star)); 2060 } 2061 PetscCall(ISRestoreIndices(dimIS, &points)); 2062 PetscCall(ISDestroy(&dimIS)); 2063 /* If any faces touching the fault divide cells on either side, split them 2064 This only occurs without a surface boundary */ 2065 PetscCall(DMLabelGetStratumIS(label, shift+dim-1, &facePosIS)); 2066 PetscCall(DMLabelGetStratumIS(label, -(shift+dim-1), &faceNegIS)); 2067 PetscCall(ISExpand(facePosIS, faceNegIS, &dimIS)); 2068 PetscCall(ISDestroy(&facePosIS)); 2069 PetscCall(ISDestroy(&faceNegIS)); 2070 PetscCall(ISGetLocalSize(dimIS, &numPoints)); 2071 PetscCall(ISGetIndices(dimIS, &points)); 2072 for (p = 0; p < numPoints; ++p) { 2073 const PetscInt point = points[p]; 2074 const PetscInt *support; 2075 PetscInt supportSize, valA, valB; 2076 2077 PetscCall(DMPlexGetSupportSize(dm, point, &supportSize)); 2078 if (supportSize != 2) continue; 2079 PetscCall(DMPlexGetSupport(dm, point, &support)); 2080 PetscCall(DMLabelGetValue(label, support[0], &valA)); 2081 PetscCall(DMLabelGetValue(label, support[1], &valB)); 2082 if ((valA == -1) || (valB == -1)) continue; 2083 if (valA*valB > 0) continue; 2084 /* Split the face */ 2085 PetscCall(DMLabelGetValue(label, point, &valA)); 2086 PetscCall(DMLabelClearValue(label, point, valA)); 2087 PetscCall(DMLabelSetValue(label, point, dim-1)); 2088 /* Label its closure: 2089 unmarked: label as unsplit 2090 incident: relabel as split 2091 split: do nothing 2092 */ 2093 { 2094 PetscInt *closure = NULL; 2095 PetscInt closureSize, cl; 2096 2097 PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure)); 2098 for (cl = 0; cl < closureSize*2; cl += 2) { 2099 PetscCall(DMLabelGetValue(label, closure[cl], &valA)); 2100 if (valA == -1) { /* Mark as unsplit */ 2101 PetscCall(DMLabelGetValue(depthLabel, closure[cl], &dep)); 2102 PetscCall(DMLabelSetValue(label, closure[cl], shift2+dep)); 2103 } else if (((valA >= shift) && (valA < shift2)) || ((valA <= -shift) && (valA > -shift2))) { 2104 PetscCall(DMLabelGetValue(depthLabel, closure[cl], &dep)); 2105 PetscCall(DMLabelClearValue(label, closure[cl], valA)); 2106 PetscCall(DMLabelSetValue(label, closure[cl], dep)); 2107 } 2108 } 2109 PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure)); 2110 } 2111 } 2112 PetscCall(ISRestoreIndices(dimIS, &points)); 2113 PetscCall(ISDestroy(&dimIS)); 2114 PetscFunctionReturn(0); 2115 } 2116 2117 /* Check that no cell have all vertices on the fault */ 2118 PetscErrorCode DMPlexCheckValidSubmesh_Private(DM dm, DMLabel label, DM subdm) 2119 { 2120 IS subpointIS; 2121 const PetscInt *dmpoints; 2122 PetscInt defaultValue, cStart, cEnd, c, vStart, vEnd; 2123 2124 PetscFunctionBegin; 2125 if (!label) PetscFunctionReturn(0); 2126 PetscCall(DMLabelGetDefaultValue(label, &defaultValue)); 2127 PetscCall(DMPlexGetSubpointIS(subdm, &subpointIS)); 2128 if (!subpointIS) PetscFunctionReturn(0); 2129 PetscCall(DMPlexGetHeightStratum(subdm, 0, &cStart, &cEnd)); 2130 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 2131 PetscCall(ISGetIndices(subpointIS, &dmpoints)); 2132 for (c = cStart; c < cEnd; ++c) { 2133 PetscBool invalidCell = PETSC_TRUE; 2134 PetscInt *closure = NULL; 2135 PetscInt closureSize, cl; 2136 2137 PetscCall(DMPlexGetTransitiveClosure(dm, dmpoints[c], PETSC_TRUE, &closureSize, &closure)); 2138 for (cl = 0; cl < closureSize*2; cl += 2) { 2139 PetscInt value = 0; 2140 2141 if ((closure[cl] < vStart) || (closure[cl] >= vEnd)) continue; 2142 PetscCall(DMLabelGetValue(label, closure[cl], &value)); 2143 if (value == defaultValue) {invalidCell = PETSC_FALSE; break;} 2144 } 2145 PetscCall(DMPlexRestoreTransitiveClosure(dm, dmpoints[c], PETSC_TRUE, &closureSize, &closure)); 2146 if (invalidCell) { 2147 PetscCall(ISRestoreIndices(subpointIS, &dmpoints)); 2148 PetscCall(ISDestroy(&subpointIS)); 2149 PetscCall(DMDestroy(&subdm)); 2150 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Ambiguous submesh. Cell %D has all of its vertices on the submesh.", dmpoints[c]); 2151 } 2152 } 2153 PetscCall(ISRestoreIndices(subpointIS, &dmpoints)); 2154 PetscFunctionReturn(0); 2155 } 2156 2157 /*@ 2158 DMPlexCreateHybridMesh - Create a mesh with hybrid cells along an internal interface 2159 2160 Collective on dm 2161 2162 Input Parameters: 2163 + dm - The original DM 2164 . label - The label specifying the interface vertices 2165 - bdlabel - The optional label specifying the interface boundary vertices 2166 2167 Output Parameters: 2168 + hybridLabel - The label fully marking the interface, or NULL if no output is desired 2169 . splitLabel - The label containing the split points, or NULL if no output is desired 2170 . dmInterface - The new interface DM, or NULL 2171 - dmHybrid - The new DM with cohesive cells 2172 2173 Note: The hybridLabel indicates what parts of the original mesh impinged on the on division surface. For points 2174 directly on the division surface, they are labeled with their dimension, so an edge 7 on the division surface would be 2175 7 (1) in hybridLabel. For points that impinge from the positive side, they are labeled with 100+dim, so an edge 6 with 2176 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 2177 surface also hits vertex 3, it would be 9 (-101) in hybridLabel. 2178 2179 The splitLabel indicates what points in the new hybrid mesh were the result of splitting points in the original 2180 mesh. The label value is +=100+dim for each point. For example, if two edges 10 and 14 in the hybrid resulting from 2181 splitting an edge in the original mesh, you would have 10 (101) and 14 (-101) in the splitLabel. 2182 2183 The dmInterface is a DM built from the original division surface. It has a label which can be retrieved using 2184 DMPlexGetSubpointMap() which maps each point back to the point in the surface of the original mesh. 2185 2186 Level: developer 2187 2188 .seealso: DMPlexConstructCohesiveCells(), DMPlexLabelCohesiveComplete(), DMPlexGetSubpointMap(), DMCreate() 2189 @*/ 2190 PetscErrorCode DMPlexCreateHybridMesh(DM dm, DMLabel label, DMLabel bdlabel, DMLabel *hybridLabel, DMLabel *splitLabel, DM *dmInterface, DM *dmHybrid) 2191 { 2192 DM idm; 2193 DMLabel subpointMap, hlabel, slabel = NULL; 2194 PetscInt dim; 2195 2196 PetscFunctionBegin; 2197 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2198 if (bdlabel) PetscValidPointer(bdlabel, 3); 2199 if (hybridLabel) PetscValidPointer(hybridLabel, 4); 2200 if (splitLabel) PetscValidPointer(splitLabel, 5); 2201 if (dmInterface) PetscValidPointer(dmInterface, 6); 2202 PetscValidPointer(dmHybrid, 7); 2203 PetscCall(DMGetDimension(dm, &dim)); 2204 PetscCall(DMPlexCreateSubmesh(dm, label, 1, PETSC_FALSE, &idm)); 2205 PetscCall(DMPlexCheckValidSubmesh_Private(dm, label, idm)); 2206 PetscCall(DMPlexOrient(idm)); 2207 PetscCall(DMPlexGetSubpointMap(idm, &subpointMap)); 2208 PetscCall(DMLabelDuplicate(subpointMap, &hlabel)); 2209 PetscCall(DMLabelClearStratum(hlabel, dim)); 2210 if (splitLabel) { 2211 const char *name; 2212 char sname[PETSC_MAX_PATH_LEN]; 2213 2214 PetscCall(PetscObjectGetName((PetscObject) hlabel, &name)); 2215 PetscCall(PetscStrncpy(sname, name, PETSC_MAX_PATH_LEN)); 2216 PetscCall(PetscStrcat(sname, " split")); 2217 PetscCall(DMLabelCreate(PETSC_COMM_SELF, sname, &slabel)); 2218 } 2219 PetscCall(DMPlexLabelCohesiveComplete(dm, hlabel, bdlabel, PETSC_FALSE, idm)); 2220 if (dmInterface) {*dmInterface = idm;} 2221 else PetscCall(DMDestroy(&idm)); 2222 PetscCall(DMPlexConstructCohesiveCells(dm, hlabel, slabel, dmHybrid)); 2223 PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, *dmHybrid)); 2224 if (hybridLabel) *hybridLabel = hlabel; 2225 else PetscCall(DMLabelDestroy(&hlabel)); 2226 if (splitLabel) *splitLabel = slabel; 2227 { 2228 DM cdm; 2229 DMLabel ctLabel; 2230 2231 /* We need to somehow share the celltype label with the coordinate dm */ 2232 PetscCall(DMGetCoordinateDM(*dmHybrid, &cdm)); 2233 PetscCall(DMPlexGetCellTypeLabel(*dmHybrid, &ctLabel)); 2234 PetscCall(DMSetLabel(cdm, ctLabel)); 2235 } 2236 PetscFunctionReturn(0); 2237 } 2238 2239 /* Here we need the explicit assumption that: 2240 2241 For any marked cell, the marked vertices constitute a single face 2242 */ 2243 static PetscErrorCode DMPlexMarkSubmesh_Uninterpolated(DM dm, DMLabel vertexLabel, PetscInt value, DMLabel subpointMap, PetscInt *numFaces, PetscInt *nFV, DM subdm) 2244 { 2245 IS subvertexIS = NULL; 2246 const PetscInt *subvertices; 2247 PetscInt *pStart, *pEnd, pSize; 2248 PetscInt depth, dim, d, numSubVerticesInitial = 0, v; 2249 2250 PetscFunctionBegin; 2251 *numFaces = 0; 2252 *nFV = 0; 2253 PetscCall(DMPlexGetDepth(dm, &depth)); 2254 PetscCall(DMGetDimension(dm, &dim)); 2255 pSize = PetscMax(depth, dim) + 1; 2256 PetscCall(PetscMalloc2(pSize, &pStart, pSize, &pEnd)); 2257 for (d = 0; d <= depth; ++d) { 2258 PetscCall(DMPlexGetSimplexOrBoxCells(dm, depth-d, &pStart[d], &pEnd[d])); 2259 } 2260 /* Loop over initial vertices and mark all faces in the collective star() */ 2261 if (vertexLabel) PetscCall(DMLabelGetStratumIS(vertexLabel, value, &subvertexIS)); 2262 if (subvertexIS) { 2263 PetscCall(ISGetSize(subvertexIS, &numSubVerticesInitial)); 2264 PetscCall(ISGetIndices(subvertexIS, &subvertices)); 2265 } 2266 for (v = 0; v < numSubVerticesInitial; ++v) { 2267 const PetscInt vertex = subvertices[v]; 2268 PetscInt *star = NULL; 2269 PetscInt starSize, s, numCells = 0, c; 2270 2271 PetscCall(DMPlexGetTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star)); 2272 for (s = 0; s < starSize*2; s += 2) { 2273 const PetscInt point = star[s]; 2274 if ((point >= pStart[depth]) && (point < pEnd[depth])) star[numCells++] = point; 2275 } 2276 for (c = 0; c < numCells; ++c) { 2277 const PetscInt cell = star[c]; 2278 PetscInt *closure = NULL; 2279 PetscInt closureSize, cl; 2280 PetscInt cellLoc, numCorners = 0, faceSize = 0; 2281 2282 PetscCall(DMLabelGetValue(subpointMap, cell, &cellLoc)); 2283 if (cellLoc == 2) continue; 2284 PetscCheck(cellLoc < 0,PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Cell %d has dimension %d in the surface label", cell, cellLoc); 2285 PetscCall(DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure)); 2286 for (cl = 0; cl < closureSize*2; cl += 2) { 2287 const PetscInt point = closure[cl]; 2288 PetscInt vertexLoc; 2289 2290 if ((point >= pStart[0]) && (point < pEnd[0])) { 2291 ++numCorners; 2292 PetscCall(DMLabelGetValue(vertexLabel, point, &vertexLoc)); 2293 if (vertexLoc == value) closure[faceSize++] = point; 2294 } 2295 } 2296 if (!(*nFV)) PetscCall(DMPlexGetNumFaceVertices(dm, dim, numCorners, nFV)); 2297 PetscCheck(faceSize <= *nFV,PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize); 2298 if (faceSize == *nFV) { 2299 const PetscInt *cells = NULL; 2300 PetscInt numCells, nc; 2301 2302 ++(*numFaces); 2303 for (cl = 0; cl < faceSize; ++cl) { 2304 PetscCall(DMLabelSetValue(subpointMap, closure[cl], 0)); 2305 } 2306 PetscCall(DMPlexGetJoin(dm, faceSize, closure, &numCells, &cells)); 2307 for (nc = 0; nc < numCells; ++nc) { 2308 PetscCall(DMLabelSetValue(subpointMap, cells[nc], 2)); 2309 } 2310 PetscCall(DMPlexRestoreJoin(dm, faceSize, closure, &numCells, &cells)); 2311 } 2312 PetscCall(DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure)); 2313 } 2314 PetscCall(DMPlexRestoreTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star)); 2315 } 2316 if (subvertexIS) { 2317 PetscCall(ISRestoreIndices(subvertexIS, &subvertices)); 2318 } 2319 PetscCall(ISDestroy(&subvertexIS)); 2320 PetscCall(PetscFree2(pStart, pEnd)); 2321 PetscFunctionReturn(0); 2322 } 2323 2324 static PetscErrorCode DMPlexMarkSubmesh_Interpolated(DM dm, DMLabel vertexLabel, PetscInt value, PetscBool markedFaces, DMLabel subpointMap, DM subdm) 2325 { 2326 IS subvertexIS = NULL; 2327 const PetscInt *subvertices; 2328 PetscInt *pStart, *pEnd; 2329 PetscInt dim, d, numSubVerticesInitial = 0, v; 2330 2331 PetscFunctionBegin; 2332 PetscCall(DMGetDimension(dm, &dim)); 2333 PetscCall(PetscMalloc2(dim+1, &pStart, dim+1, &pEnd)); 2334 for (d = 0; d <= dim; ++d) { 2335 PetscCall(DMPlexGetSimplexOrBoxCells(dm, dim-d, &pStart[d], &pEnd[d])); 2336 } 2337 /* Loop over initial vertices and mark all faces in the collective star() */ 2338 if (vertexLabel) { 2339 PetscCall(DMLabelGetStratumIS(vertexLabel, value, &subvertexIS)); 2340 if (subvertexIS) { 2341 PetscCall(ISGetSize(subvertexIS, &numSubVerticesInitial)); 2342 PetscCall(ISGetIndices(subvertexIS, &subvertices)); 2343 } 2344 } 2345 for (v = 0; v < numSubVerticesInitial; ++v) { 2346 const PetscInt vertex = subvertices[v]; 2347 PetscInt *star = NULL; 2348 PetscInt starSize, s, numFaces = 0, f; 2349 2350 PetscCall(DMPlexGetTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star)); 2351 for (s = 0; s < starSize*2; s += 2) { 2352 const PetscInt point = star[s]; 2353 PetscInt faceLoc; 2354 2355 if ((point >= pStart[dim-1]) && (point < pEnd[dim-1])) { 2356 if (markedFaces) { 2357 PetscCall(DMLabelGetValue(vertexLabel, point, &faceLoc)); 2358 if (faceLoc < 0) continue; 2359 } 2360 star[numFaces++] = point; 2361 } 2362 } 2363 for (f = 0; f < numFaces; ++f) { 2364 const PetscInt face = star[f]; 2365 PetscInt *closure = NULL; 2366 PetscInt closureSize, c; 2367 PetscInt faceLoc; 2368 2369 PetscCall(DMLabelGetValue(subpointMap, face, &faceLoc)); 2370 if (faceLoc == dim-1) continue; 2371 PetscCheck(faceLoc < 0,PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Face %d has dimension %d in the surface label", face, faceLoc); 2372 PetscCall(DMPlexGetTransitiveClosure(dm, face, PETSC_TRUE, &closureSize, &closure)); 2373 for (c = 0; c < closureSize*2; c += 2) { 2374 const PetscInt point = closure[c]; 2375 PetscInt vertexLoc; 2376 2377 if ((point >= pStart[0]) && (point < pEnd[0])) { 2378 PetscCall(DMLabelGetValue(vertexLabel, point, &vertexLoc)); 2379 if (vertexLoc != value) break; 2380 } 2381 } 2382 if (c == closureSize*2) { 2383 const PetscInt *support; 2384 PetscInt supportSize, s; 2385 2386 for (c = 0; c < closureSize*2; c += 2) { 2387 const PetscInt point = closure[c]; 2388 2389 for (d = 0; d < dim; ++d) { 2390 if ((point >= pStart[d]) && (point < pEnd[d])) { 2391 PetscCall(DMLabelSetValue(subpointMap, point, d)); 2392 break; 2393 } 2394 } 2395 } 2396 PetscCall(DMPlexGetSupportSize(dm, face, &supportSize)); 2397 PetscCall(DMPlexGetSupport(dm, face, &support)); 2398 for (s = 0; s < supportSize; ++s) { 2399 PetscCall(DMLabelSetValue(subpointMap, support[s], dim)); 2400 } 2401 } 2402 PetscCall(DMPlexRestoreTransitiveClosure(dm, face, PETSC_TRUE, &closureSize, &closure)); 2403 } 2404 PetscCall(DMPlexRestoreTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star)); 2405 } 2406 if (subvertexIS) PetscCall(ISRestoreIndices(subvertexIS, &subvertices)); 2407 PetscCall(ISDestroy(&subvertexIS)); 2408 PetscCall(PetscFree2(pStart, pEnd)); 2409 PetscFunctionReturn(0); 2410 } 2411 2412 static PetscErrorCode DMPlexMarkCohesiveSubmesh_Uninterpolated(DM dm, PetscBool hasLagrange, const char labelname[], PetscInt value, DMLabel subpointMap, PetscInt *numFaces, PetscInt *nFV, PetscInt *subCells[], DM subdm) 2413 { 2414 DMLabel label = NULL; 2415 const PetscInt *cone; 2416 PetscInt dim, cMax, cEnd, c, subc = 0, p, coneSize = -1; 2417 2418 PetscFunctionBegin; 2419 *numFaces = 0; 2420 *nFV = 0; 2421 if (labelname) PetscCall(DMGetLabel(dm, labelname, &label)); 2422 *subCells = NULL; 2423 PetscCall(DMGetDimension(dm, &dim)); 2424 PetscCall(DMPlexGetTensorPrismBounds_Internal(dm, dim, &cMax, &cEnd)); 2425 if (cMax < 0) PetscFunctionReturn(0); 2426 if (label) { 2427 for (c = cMax; c < cEnd; ++c) { 2428 PetscInt val; 2429 2430 PetscCall(DMLabelGetValue(label, c, &val)); 2431 if (val == value) { 2432 ++(*numFaces); 2433 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 2434 } 2435 } 2436 } else { 2437 *numFaces = cEnd - cMax; 2438 PetscCall(DMPlexGetConeSize(dm, cMax, &coneSize)); 2439 } 2440 PetscCall(PetscMalloc1(*numFaces *2, subCells)); 2441 if (!(*numFaces)) PetscFunctionReturn(0); 2442 *nFV = hasLagrange ? coneSize/3 : coneSize/2; 2443 for (c = cMax; c < cEnd; ++c) { 2444 const PetscInt *cells; 2445 PetscInt numCells; 2446 2447 if (label) { 2448 PetscInt val; 2449 2450 PetscCall(DMLabelGetValue(label, c, &val)); 2451 if (val != value) continue; 2452 } 2453 PetscCall(DMPlexGetCone(dm, c, &cone)); 2454 for (p = 0; p < *nFV; ++p) { 2455 PetscCall(DMLabelSetValue(subpointMap, cone[p], 0)); 2456 } 2457 /* Negative face */ 2458 PetscCall(DMPlexGetJoin(dm, *nFV, cone, &numCells, &cells)); 2459 /* Not true in parallel 2460 PetscCheck(numCells == 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cohesive cells should separate two cells"); */ 2461 for (p = 0; p < numCells; ++p) { 2462 PetscCall(DMLabelSetValue(subpointMap, cells[p], 2)); 2463 (*subCells)[subc++] = cells[p]; 2464 } 2465 PetscCall(DMPlexRestoreJoin(dm, *nFV, cone, &numCells, &cells)); 2466 /* Positive face is not included */ 2467 } 2468 PetscFunctionReturn(0); 2469 } 2470 2471 static PetscErrorCode DMPlexMarkCohesiveSubmesh_Interpolated(DM dm, DMLabel label, PetscInt value, DMLabel subpointMap, DM subdm) 2472 { 2473 PetscInt *pStart, *pEnd; 2474 PetscInt dim, cMax, cEnd, c, d; 2475 2476 PetscFunctionBegin; 2477 PetscCall(DMGetDimension(dm, &dim)); 2478 PetscCall(DMPlexGetTensorPrismBounds_Internal(dm, dim, &cMax, &cEnd)); 2479 if (cMax < 0) PetscFunctionReturn(0); 2480 PetscCall(PetscMalloc2(dim+1,&pStart,dim+1,&pEnd)); 2481 for (d = 0; d <= dim; ++d) PetscCall(DMPlexGetDepthStratum(dm, d, &pStart[d], &pEnd[d])); 2482 for (c = cMax; c < cEnd; ++c) { 2483 const PetscInt *cone; 2484 PetscInt *closure = NULL; 2485 PetscInt fconeSize, coneSize, closureSize, cl, val; 2486 2487 if (label) { 2488 PetscCall(DMLabelGetValue(label, c, &val)); 2489 if (val != value) continue; 2490 } 2491 PetscCall(DMPlexGetConeSize(dm, c, &coneSize)); 2492 PetscCall(DMPlexGetCone(dm, c, &cone)); 2493 PetscCall(DMPlexGetConeSize(dm, cone[0], &fconeSize)); 2494 PetscCheckFalse(coneSize != (fconeSize ? fconeSize : 1) + 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cohesive cells should separate two cells"); 2495 /* Negative face */ 2496 PetscCall(DMPlexGetTransitiveClosure(dm, cone[0], PETSC_TRUE, &closureSize, &closure)); 2497 for (cl = 0; cl < closureSize*2; cl += 2) { 2498 const PetscInt point = closure[cl]; 2499 2500 for (d = 0; d <= dim; ++d) { 2501 if ((point >= pStart[d]) && (point < pEnd[d])) { 2502 PetscCall(DMLabelSetValue(subpointMap, point, d)); 2503 break; 2504 } 2505 } 2506 } 2507 PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], PETSC_TRUE, &closureSize, &closure)); 2508 /* Cells -- positive face is not included */ 2509 for (cl = 0; cl < 1; ++cl) { 2510 const PetscInt *support; 2511 PetscInt supportSize, s; 2512 2513 PetscCall(DMPlexGetSupportSize(dm, cone[cl], &supportSize)); 2514 /* PetscCheck(supportSize == 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cohesive faces should separate two cells"); */ 2515 PetscCall(DMPlexGetSupport(dm, cone[cl], &support)); 2516 for (s = 0; s < supportSize; ++s) { 2517 PetscCall(DMLabelSetValue(subpointMap, support[s], dim)); 2518 } 2519 } 2520 } 2521 PetscCall(PetscFree2(pStart, pEnd)); 2522 PetscFunctionReturn(0); 2523 } 2524 2525 static PetscErrorCode DMPlexGetFaceOrientation(DM dm, PetscInt cell, PetscInt numCorners, PetscInt indices[], PetscInt oppositeVertex, PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented) 2526 { 2527 MPI_Comm comm; 2528 PetscBool posOrient = PETSC_FALSE; 2529 const PetscInt debug = 0; 2530 PetscInt cellDim, faceSize, f; 2531 2532 PetscFunctionBegin; 2533 PetscCall(PetscObjectGetComm((PetscObject)dm,&comm)); 2534 PetscCall(DMGetDimension(dm, &cellDim)); 2535 if (debug) PetscCall(PetscPrintf(comm, "cellDim: %d numCorners: %d\n", cellDim, numCorners)); 2536 2537 if (cellDim == 1 && numCorners == 2) { 2538 /* Triangle */ 2539 faceSize = numCorners-1; 2540 posOrient = !(oppositeVertex%2) ? PETSC_TRUE : PETSC_FALSE; 2541 } else if (cellDim == 2 && numCorners == 3) { 2542 /* Triangle */ 2543 faceSize = numCorners-1; 2544 posOrient = !(oppositeVertex%2) ? PETSC_TRUE : PETSC_FALSE; 2545 } else if (cellDim == 3 && numCorners == 4) { 2546 /* Tetrahedron */ 2547 faceSize = numCorners-1; 2548 posOrient = (oppositeVertex%2) ? PETSC_TRUE : PETSC_FALSE; 2549 } else if (cellDim == 1 && numCorners == 3) { 2550 /* Quadratic line */ 2551 faceSize = 1; 2552 posOrient = PETSC_TRUE; 2553 } else if (cellDim == 2 && numCorners == 4) { 2554 /* Quads */ 2555 faceSize = 2; 2556 if ((indices[1] > indices[0]) && (indices[1] - indices[0] == 1)) { 2557 posOrient = PETSC_TRUE; 2558 } else if ((indices[0] == 3) && (indices[1] == 0)) { 2559 posOrient = PETSC_TRUE; 2560 } else { 2561 if (((indices[0] > indices[1]) && (indices[0] - indices[1] == 1)) || ((indices[0] == 0) && (indices[1] == 3))) { 2562 posOrient = PETSC_FALSE; 2563 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossedge"); 2564 } 2565 } else if (cellDim == 2 && numCorners == 6) { 2566 /* Quadratic triangle (I hate this) */ 2567 /* Edges are determined by the first 2 vertices (corners of edges) */ 2568 const PetscInt faceSizeTri = 3; 2569 PetscInt sortedIndices[3], i, iFace; 2570 PetscBool found = PETSC_FALSE; 2571 PetscInt faceVerticesTriSorted[9] = { 2572 0, 3, 4, /* bottom */ 2573 1, 4, 5, /* right */ 2574 2, 3, 5, /* left */ 2575 }; 2576 PetscInt faceVerticesTri[9] = { 2577 0, 3, 4, /* bottom */ 2578 1, 4, 5, /* right */ 2579 2, 5, 3, /* left */ 2580 }; 2581 2582 for (i = 0; i < faceSizeTri; ++i) sortedIndices[i] = indices[i]; 2583 PetscCall(PetscSortInt(faceSizeTri, sortedIndices)); 2584 for (iFace = 0; iFace < 3; ++iFace) { 2585 const PetscInt ii = iFace*faceSizeTri; 2586 PetscInt fVertex, cVertex; 2587 2588 if ((sortedIndices[0] == faceVerticesTriSorted[ii+0]) && 2589 (sortedIndices[1] == faceVerticesTriSorted[ii+1])) { 2590 for (fVertex = 0; fVertex < faceSizeTri; ++fVertex) { 2591 for (cVertex = 0; cVertex < faceSizeTri; ++cVertex) { 2592 if (indices[cVertex] == faceVerticesTri[ii+fVertex]) { 2593 faceVertices[fVertex] = origVertices[cVertex]; 2594 break; 2595 } 2596 } 2597 } 2598 found = PETSC_TRUE; 2599 break; 2600 } 2601 } 2602 PetscCheck(found,comm, PETSC_ERR_ARG_WRONG, "Invalid tri crossface"); 2603 if (posOriented) *posOriented = PETSC_TRUE; 2604 PetscFunctionReturn(0); 2605 } else if (cellDim == 2 && numCorners == 9) { 2606 /* Quadratic quad (I hate this) */ 2607 /* Edges are determined by the first 2 vertices (corners of edges) */ 2608 const PetscInt faceSizeQuad = 3; 2609 PetscInt sortedIndices[3], i, iFace; 2610 PetscBool found = PETSC_FALSE; 2611 PetscInt faceVerticesQuadSorted[12] = { 2612 0, 1, 4, /* bottom */ 2613 1, 2, 5, /* right */ 2614 2, 3, 6, /* top */ 2615 0, 3, 7, /* left */ 2616 }; 2617 PetscInt faceVerticesQuad[12] = { 2618 0, 1, 4, /* bottom */ 2619 1, 2, 5, /* right */ 2620 2, 3, 6, /* top */ 2621 3, 0, 7, /* left */ 2622 }; 2623 2624 for (i = 0; i < faceSizeQuad; ++i) sortedIndices[i] = indices[i]; 2625 PetscCall(PetscSortInt(faceSizeQuad, sortedIndices)); 2626 for (iFace = 0; iFace < 4; ++iFace) { 2627 const PetscInt ii = iFace*faceSizeQuad; 2628 PetscInt fVertex, cVertex; 2629 2630 if ((sortedIndices[0] == faceVerticesQuadSorted[ii+0]) && 2631 (sortedIndices[1] == faceVerticesQuadSorted[ii+1])) { 2632 for (fVertex = 0; fVertex < faceSizeQuad; ++fVertex) { 2633 for (cVertex = 0; cVertex < faceSizeQuad; ++cVertex) { 2634 if (indices[cVertex] == faceVerticesQuad[ii+fVertex]) { 2635 faceVertices[fVertex] = origVertices[cVertex]; 2636 break; 2637 } 2638 } 2639 } 2640 found = PETSC_TRUE; 2641 break; 2642 } 2643 } 2644 PetscCheck(found,comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossface"); 2645 if (posOriented) *posOriented = PETSC_TRUE; 2646 PetscFunctionReturn(0); 2647 } else if (cellDim == 3 && numCorners == 8) { 2648 /* Hexes 2649 A hex is two oriented quads with the normal of the first 2650 pointing up at the second. 2651 2652 7---6 2653 /| /| 2654 4---5 | 2655 | 1-|-2 2656 |/ |/ 2657 0---3 2658 2659 Faces are determined by the first 4 vertices (corners of faces) */ 2660 const PetscInt faceSizeHex = 4; 2661 PetscInt sortedIndices[4], i, iFace; 2662 PetscBool found = PETSC_FALSE; 2663 PetscInt faceVerticesHexSorted[24] = { 2664 0, 1, 2, 3, /* bottom */ 2665 4, 5, 6, 7, /* top */ 2666 0, 3, 4, 5, /* front */ 2667 2, 3, 5, 6, /* right */ 2668 1, 2, 6, 7, /* back */ 2669 0, 1, 4, 7, /* left */ 2670 }; 2671 PetscInt faceVerticesHex[24] = { 2672 1, 2, 3, 0, /* bottom */ 2673 4, 5, 6, 7, /* top */ 2674 0, 3, 5, 4, /* front */ 2675 3, 2, 6, 5, /* right */ 2676 2, 1, 7, 6, /* back */ 2677 1, 0, 4, 7, /* left */ 2678 }; 2679 2680 for (i = 0; i < faceSizeHex; ++i) sortedIndices[i] = indices[i]; 2681 PetscCall(PetscSortInt(faceSizeHex, sortedIndices)); 2682 for (iFace = 0; iFace < 6; ++iFace) { 2683 const PetscInt ii = iFace*faceSizeHex; 2684 PetscInt fVertex, cVertex; 2685 2686 if ((sortedIndices[0] == faceVerticesHexSorted[ii+0]) && 2687 (sortedIndices[1] == faceVerticesHexSorted[ii+1]) && 2688 (sortedIndices[2] == faceVerticesHexSorted[ii+2]) && 2689 (sortedIndices[3] == faceVerticesHexSorted[ii+3])) { 2690 for (fVertex = 0; fVertex < faceSizeHex; ++fVertex) { 2691 for (cVertex = 0; cVertex < faceSizeHex; ++cVertex) { 2692 if (indices[cVertex] == faceVerticesHex[ii+fVertex]) { 2693 faceVertices[fVertex] = origVertices[cVertex]; 2694 break; 2695 } 2696 } 2697 } 2698 found = PETSC_TRUE; 2699 break; 2700 } 2701 } 2702 PetscCheck(found,comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface"); 2703 if (posOriented) *posOriented = PETSC_TRUE; 2704 PetscFunctionReturn(0); 2705 } else if (cellDim == 3 && numCorners == 10) { 2706 /* Quadratic tet */ 2707 /* Faces are determined by the first 3 vertices (corners of faces) */ 2708 const PetscInt faceSizeTet = 6; 2709 PetscInt sortedIndices[6], i, iFace; 2710 PetscBool found = PETSC_FALSE; 2711 PetscInt faceVerticesTetSorted[24] = { 2712 0, 1, 2, 6, 7, 8, /* bottom */ 2713 0, 3, 4, 6, 7, 9, /* front */ 2714 1, 4, 5, 7, 8, 9, /* right */ 2715 2, 3, 5, 6, 8, 9, /* left */ 2716 }; 2717 PetscInt faceVerticesTet[24] = { 2718 0, 1, 2, 6, 7, 8, /* bottom */ 2719 0, 4, 3, 6, 7, 9, /* front */ 2720 1, 5, 4, 7, 8, 9, /* right */ 2721 2, 3, 5, 8, 6, 9, /* left */ 2722 }; 2723 2724 for (i = 0; i < faceSizeTet; ++i) sortedIndices[i] = indices[i]; 2725 PetscCall(PetscSortInt(faceSizeTet, sortedIndices)); 2726 for (iFace=0; iFace < 4; ++iFace) { 2727 const PetscInt ii = iFace*faceSizeTet; 2728 PetscInt fVertex, cVertex; 2729 2730 if ((sortedIndices[0] == faceVerticesTetSorted[ii+0]) && 2731 (sortedIndices[1] == faceVerticesTetSorted[ii+1]) && 2732 (sortedIndices[2] == faceVerticesTetSorted[ii+2]) && 2733 (sortedIndices[3] == faceVerticesTetSorted[ii+3])) { 2734 for (fVertex = 0; fVertex < faceSizeTet; ++fVertex) { 2735 for (cVertex = 0; cVertex < faceSizeTet; ++cVertex) { 2736 if (indices[cVertex] == faceVerticesTet[ii+fVertex]) { 2737 faceVertices[fVertex] = origVertices[cVertex]; 2738 break; 2739 } 2740 } 2741 } 2742 found = PETSC_TRUE; 2743 break; 2744 } 2745 } 2746 PetscCheck(found,comm, PETSC_ERR_ARG_WRONG, "Invalid tet crossface"); 2747 if (posOriented) *posOriented = PETSC_TRUE; 2748 PetscFunctionReturn(0); 2749 } else if (cellDim == 3 && numCorners == 27) { 2750 /* Quadratic hexes (I hate this) 2751 A hex is two oriented quads with the normal of the first 2752 pointing up at the second. 2753 2754 7---6 2755 /| /| 2756 4---5 | 2757 | 3-|-2 2758 |/ |/ 2759 0---1 2760 2761 Faces are determined by the first 4 vertices (corners of faces) */ 2762 const PetscInt faceSizeQuadHex = 9; 2763 PetscInt sortedIndices[9], i, iFace; 2764 PetscBool found = PETSC_FALSE; 2765 PetscInt faceVerticesQuadHexSorted[54] = { 2766 0, 1, 2, 3, 8, 9, 10, 11, 24, /* bottom */ 2767 4, 5, 6, 7, 12, 13, 14, 15, 25, /* top */ 2768 0, 1, 4, 5, 8, 12, 16, 17, 22, /* front */ 2769 1, 2, 5, 6, 9, 13, 17, 18, 21, /* right */ 2770 2, 3, 6, 7, 10, 14, 18, 19, 23, /* back */ 2771 0, 3, 4, 7, 11, 15, 16, 19, 20, /* left */ 2772 }; 2773 PetscInt faceVerticesQuadHex[54] = { 2774 3, 2, 1, 0, 10, 9, 8, 11, 24, /* bottom */ 2775 4, 5, 6, 7, 12, 13, 14, 15, 25, /* top */ 2776 0, 1, 5, 4, 8, 17, 12, 16, 22, /* front */ 2777 1, 2, 6, 5, 9, 18, 13, 17, 21, /* right */ 2778 2, 3, 7, 6, 10, 19, 14, 18, 23, /* back */ 2779 3, 0, 4, 7, 11, 16, 15, 19, 20 /* left */ 2780 }; 2781 2782 for (i = 0; i < faceSizeQuadHex; ++i) sortedIndices[i] = indices[i]; 2783 PetscCall(PetscSortInt(faceSizeQuadHex, sortedIndices)); 2784 for (iFace = 0; iFace < 6; ++iFace) { 2785 const PetscInt ii = iFace*faceSizeQuadHex; 2786 PetscInt fVertex, cVertex; 2787 2788 if ((sortedIndices[0] == faceVerticesQuadHexSorted[ii+0]) && 2789 (sortedIndices[1] == faceVerticesQuadHexSorted[ii+1]) && 2790 (sortedIndices[2] == faceVerticesQuadHexSorted[ii+2]) && 2791 (sortedIndices[3] == faceVerticesQuadHexSorted[ii+3])) { 2792 for (fVertex = 0; fVertex < faceSizeQuadHex; ++fVertex) { 2793 for (cVertex = 0; cVertex < faceSizeQuadHex; ++cVertex) { 2794 if (indices[cVertex] == faceVerticesQuadHex[ii+fVertex]) { 2795 faceVertices[fVertex] = origVertices[cVertex]; 2796 break; 2797 } 2798 } 2799 } 2800 found = PETSC_TRUE; 2801 break; 2802 } 2803 } 2804 PetscCheck(found,comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface"); 2805 if (posOriented) *posOriented = PETSC_TRUE; 2806 PetscFunctionReturn(0); 2807 } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Unknown cell type for faceOrientation()."); 2808 if (!posOrient) { 2809 if (debug) PetscCall(PetscPrintf(comm, " Reversing initial face orientation\n")); 2810 for (f = 0; f < faceSize; ++f) faceVertices[f] = origVertices[faceSize-1 - f]; 2811 } else { 2812 if (debug) PetscCall(PetscPrintf(comm, " Keeping initial face orientation\n")); 2813 for (f = 0; f < faceSize; ++f) faceVertices[f] = origVertices[f]; 2814 } 2815 if (posOriented) *posOriented = posOrient; 2816 PetscFunctionReturn(0); 2817 } 2818 2819 /*@ 2820 DMPlexGetOrientedFace - Given a cell and a face, as a set of vertices, return the oriented face, as a set of vertices, 2821 in faceVertices. The orientation is such that the face normal points out of the cell 2822 2823 Not collective 2824 2825 Input Parameters: 2826 + dm - The original mesh 2827 . cell - The cell mesh point 2828 . faceSize - The number of vertices on the face 2829 . face - The face vertices 2830 . numCorners - The number of vertices on the cell 2831 . indices - Local numbering of face vertices in cell cone 2832 - origVertices - Original face vertices 2833 2834 Output Parameters: 2835 + faceVertices - The face vertices properly oriented 2836 - posOriented - PETSC_TRUE if the face was oriented with outward normal 2837 2838 Level: developer 2839 2840 .seealso: DMPlexGetCone() 2841 @*/ 2842 PetscErrorCode DMPlexGetOrientedFace(DM dm, PetscInt cell, PetscInt faceSize, const PetscInt face[], PetscInt numCorners, PetscInt indices[], PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented) 2843 { 2844 const PetscInt *cone = NULL; 2845 PetscInt coneSize, v, f, v2; 2846 PetscInt oppositeVertex = -1; 2847 2848 PetscFunctionBegin; 2849 PetscCall(DMPlexGetConeSize(dm, cell, &coneSize)); 2850 PetscCall(DMPlexGetCone(dm, cell, &cone)); 2851 for (v = 0, v2 = 0; v < coneSize; ++v) { 2852 PetscBool found = PETSC_FALSE; 2853 2854 for (f = 0; f < faceSize; ++f) { 2855 if (face[f] == cone[v]) { 2856 found = PETSC_TRUE; break; 2857 } 2858 } 2859 if (found) { 2860 indices[v2] = v; 2861 origVertices[v2] = cone[v]; 2862 ++v2; 2863 } else { 2864 oppositeVertex = v; 2865 } 2866 } 2867 PetscCall(DMPlexGetFaceOrientation(dm, cell, numCorners, indices, oppositeVertex, origVertices, faceVertices, posOriented)); 2868 PetscFunctionReturn(0); 2869 } 2870 2871 /* 2872 DMPlexInsertFace_Internal - Puts a face into the mesh 2873 2874 Not collective 2875 2876 Input Parameters: 2877 + dm - The DMPlex 2878 . numFaceVertex - The number of vertices in the face 2879 . faceVertices - The vertices in the face for dm 2880 . subfaceVertices - The vertices in the face for subdm 2881 . numCorners - The number of vertices in the cell 2882 . cell - A cell in dm containing the face 2883 . subcell - A cell in subdm containing the face 2884 . firstFace - First face in the mesh 2885 - newFacePoint - Next face in the mesh 2886 2887 Output Parameters: 2888 . newFacePoint - Contains next face point number on input, updated on output 2889 2890 Level: developer 2891 */ 2892 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) 2893 { 2894 MPI_Comm comm; 2895 DM_Plex *submesh = (DM_Plex*) subdm->data; 2896 const PetscInt *faces; 2897 PetscInt numFaces, coneSize; 2898 2899 PetscFunctionBegin; 2900 PetscCall(PetscObjectGetComm((PetscObject)dm,&comm)); 2901 PetscCall(DMPlexGetConeSize(subdm, subcell, &coneSize)); 2902 PetscCheck(coneSize == 1,comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size of cell %d is %d != 1", cell, coneSize); 2903 #if 0 2904 /* Cannot use this because support() has not been constructed yet */ 2905 PetscCall(DMPlexGetJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces)); 2906 #else 2907 { 2908 PetscInt f; 2909 2910 numFaces = 0; 2911 PetscCall(DMGetWorkArray(subdm, 1, MPIU_INT, (void **) &faces)); 2912 for (f = firstFace; f < *newFacePoint; ++f) { 2913 PetscInt dof, off, d; 2914 2915 PetscCall(PetscSectionGetDof(submesh->coneSection, f, &dof)); 2916 PetscCall(PetscSectionGetOffset(submesh->coneSection, f, &off)); 2917 /* Yes, I know this is quadratic, but I expect the sizes to be <5 */ 2918 for (d = 0; d < dof; ++d) { 2919 const PetscInt p = submesh->cones[off+d]; 2920 PetscInt v; 2921 2922 for (v = 0; v < numFaceVertices; ++v) { 2923 if (subfaceVertices[v] == p) break; 2924 } 2925 if (v == numFaceVertices) break; 2926 } 2927 if (d == dof) { 2928 numFaces = 1; 2929 ((PetscInt*) faces)[0] = f; 2930 } 2931 } 2932 } 2933 #endif 2934 PetscCheck(numFaces <= 1,comm, PETSC_ERR_ARG_WRONG, "Vertex set had %d faces, not one", numFaces); 2935 else if (numFaces == 1) { 2936 /* Add the other cell neighbor for this face */ 2937 PetscCall(DMPlexSetCone(subdm, subcell, faces)); 2938 } else { 2939 PetscInt *indices, *origVertices, *orientedVertices, *orientedSubVertices, v, ov; 2940 PetscBool posOriented; 2941 2942 PetscCall(DMGetWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), MPIU_INT, &orientedVertices)); 2943 origVertices = &orientedVertices[numFaceVertices]; 2944 indices = &orientedVertices[numFaceVertices*2]; 2945 orientedSubVertices = &orientedVertices[numFaceVertices*3]; 2946 PetscCall(DMPlexGetOrientedFace(dm, cell, numFaceVertices, faceVertices, numCorners, indices, origVertices, orientedVertices, &posOriented)); 2947 /* TODO: I know that routine should return a permutation, not the indices */ 2948 for (v = 0; v < numFaceVertices; ++v) { 2949 const PetscInt vertex = faceVertices[v], subvertex = subfaceVertices[v]; 2950 for (ov = 0; ov < numFaceVertices; ++ov) { 2951 if (orientedVertices[ov] == vertex) { 2952 orientedSubVertices[ov] = subvertex; 2953 break; 2954 } 2955 } 2956 PetscCheck(ov != numFaceVertices,comm, PETSC_ERR_PLIB, "Could not find face vertex %d in orientated set", vertex); 2957 } 2958 PetscCall(DMPlexSetCone(subdm, *newFacePoint, orientedSubVertices)); 2959 PetscCall(DMPlexSetCone(subdm, subcell, newFacePoint)); 2960 PetscCall(DMRestoreWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), MPIU_INT, &orientedVertices)); 2961 ++(*newFacePoint); 2962 } 2963 #if 0 2964 PetscCall(DMPlexRestoreJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces)); 2965 #else 2966 PetscCall(DMRestoreWorkArray(subdm, 1, MPIU_INT, (void **) &faces)); 2967 #endif 2968 PetscFunctionReturn(0); 2969 } 2970 2971 static PetscErrorCode DMPlexCreateSubmesh_Uninterpolated(DM dm, DMLabel vertexLabel, PetscInt value, DM subdm) 2972 { 2973 MPI_Comm comm; 2974 DMLabel subpointMap; 2975 IS subvertexIS, subcellIS; 2976 const PetscInt *subVertices, *subCells; 2977 PetscInt numSubVertices, firstSubVertex, numSubCells; 2978 PetscInt *subface, maxConeSize, numSubFaces = 0, firstSubFace, newFacePoint, nFV = 0; 2979 PetscInt vStart, vEnd, c, f; 2980 2981 PetscFunctionBegin; 2982 PetscCall(PetscObjectGetComm((PetscObject)dm,&comm)); 2983 /* Create subpointMap which marks the submesh */ 2984 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "subpoint_map", &subpointMap)); 2985 PetscCall(DMPlexSetSubpointMap(subdm, subpointMap)); 2986 PetscCall(DMLabelDestroy(&subpointMap)); 2987 if (vertexLabel) PetscCall(DMPlexMarkSubmesh_Uninterpolated(dm, vertexLabel, value, subpointMap, &numSubFaces, &nFV, subdm)); 2988 /* Setup chart */ 2989 PetscCall(DMLabelGetStratumSize(subpointMap, 0, &numSubVertices)); 2990 PetscCall(DMLabelGetStratumSize(subpointMap, 2, &numSubCells)); 2991 PetscCall(DMPlexSetChart(subdm, 0, numSubCells+numSubFaces+numSubVertices)); 2992 PetscCall(DMPlexSetVTKCellHeight(subdm, 1)); 2993 /* Set cone sizes */ 2994 firstSubVertex = numSubCells; 2995 firstSubFace = numSubCells+numSubVertices; 2996 newFacePoint = firstSubFace; 2997 PetscCall(DMLabelGetStratumIS(subpointMap, 0, &subvertexIS)); 2998 if (subvertexIS) PetscCall(ISGetIndices(subvertexIS, &subVertices)); 2999 PetscCall(DMLabelGetStratumIS(subpointMap, 2, &subcellIS)); 3000 if (subcellIS) PetscCall(ISGetIndices(subcellIS, &subCells)); 3001 for (c = 0; c < numSubCells; ++c) { 3002 PetscCall(DMPlexSetConeSize(subdm, c, 1)); 3003 } 3004 for (f = firstSubFace; f < firstSubFace+numSubFaces; ++f) { 3005 PetscCall(DMPlexSetConeSize(subdm, f, nFV)); 3006 } 3007 PetscCall(DMSetUp(subdm)); 3008 /* Create face cones */ 3009 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 3010 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, NULL)); 3011 PetscCall(DMGetWorkArray(subdm, maxConeSize, MPIU_INT, (void**) &subface)); 3012 for (c = 0; c < numSubCells; ++c) { 3013 const PetscInt cell = subCells[c]; 3014 const PetscInt subcell = c; 3015 PetscInt *closure = NULL; 3016 PetscInt closureSize, cl, numCorners = 0, faceSize = 0; 3017 3018 PetscCall(DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure)); 3019 for (cl = 0; cl < closureSize*2; cl += 2) { 3020 const PetscInt point = closure[cl]; 3021 PetscInt subVertex; 3022 3023 if ((point >= vStart) && (point < vEnd)) { 3024 ++numCorners; 3025 PetscCall(PetscFindInt(point, numSubVertices, subVertices, &subVertex)); 3026 if (subVertex >= 0) { 3027 closure[faceSize] = point; 3028 subface[faceSize] = firstSubVertex+subVertex; 3029 ++faceSize; 3030 } 3031 } 3032 } 3033 PetscCheck(faceSize <= nFV,comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize); 3034 if (faceSize == nFV) { 3035 PetscCall(DMPlexInsertFace_Internal(dm, subdm, faceSize, closure, subface, numCorners, cell, subcell, firstSubFace, &newFacePoint)); 3036 } 3037 PetscCall(DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure)); 3038 } 3039 PetscCall(DMRestoreWorkArray(subdm, maxConeSize, MPIU_INT, (void**) &subface)); 3040 PetscCall(DMPlexSymmetrize(subdm)); 3041 PetscCall(DMPlexStratify(subdm)); 3042 /* Build coordinates */ 3043 { 3044 PetscSection coordSection, subCoordSection; 3045 Vec coordinates, subCoordinates; 3046 PetscScalar *coords, *subCoords; 3047 PetscInt numComp, coordSize, v; 3048 const char *name; 3049 3050 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 3051 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 3052 PetscCall(DMGetCoordinateSection(subdm, &subCoordSection)); 3053 PetscCall(PetscSectionSetNumFields(subCoordSection, 1)); 3054 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &numComp)); 3055 PetscCall(PetscSectionSetFieldComponents(subCoordSection, 0, numComp)); 3056 PetscCall(PetscSectionSetChart(subCoordSection, firstSubVertex, firstSubVertex+numSubVertices)); 3057 for (v = 0; v < numSubVertices; ++v) { 3058 const PetscInt vertex = subVertices[v]; 3059 const PetscInt subvertex = firstSubVertex+v; 3060 PetscInt dof; 3061 3062 PetscCall(PetscSectionGetDof(coordSection, vertex, &dof)); 3063 PetscCall(PetscSectionSetDof(subCoordSection, subvertex, dof)); 3064 PetscCall(PetscSectionSetFieldDof(subCoordSection, subvertex, 0, dof)); 3065 } 3066 PetscCall(PetscSectionSetUp(subCoordSection)); 3067 PetscCall(PetscSectionGetStorageSize(subCoordSection, &coordSize)); 3068 PetscCall(VecCreate(PETSC_COMM_SELF, &subCoordinates)); 3069 PetscCall(PetscObjectGetName((PetscObject)coordinates,&name)); 3070 PetscCall(PetscObjectSetName((PetscObject)subCoordinates,name)); 3071 PetscCall(VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE)); 3072 PetscCall(VecSetType(subCoordinates,VECSTANDARD)); 3073 if (coordSize) { 3074 PetscCall(VecGetArray(coordinates, &coords)); 3075 PetscCall(VecGetArray(subCoordinates, &subCoords)); 3076 for (v = 0; v < numSubVertices; ++v) { 3077 const PetscInt vertex = subVertices[v]; 3078 const PetscInt subvertex = firstSubVertex+v; 3079 PetscInt dof, off, sdof, soff, d; 3080 3081 PetscCall(PetscSectionGetDof(coordSection, vertex, &dof)); 3082 PetscCall(PetscSectionGetOffset(coordSection, vertex, &off)); 3083 PetscCall(PetscSectionGetDof(subCoordSection, subvertex, &sdof)); 3084 PetscCall(PetscSectionGetOffset(subCoordSection, subvertex, &soff)); 3085 PetscCheck(dof == sdof,comm, PETSC_ERR_PLIB, "Coordinate dimension %d on subvertex %d, vertex %d should be %d", sdof, subvertex, vertex, dof); 3086 for (d = 0; d < dof; ++d) subCoords[soff+d] = coords[off+d]; 3087 } 3088 PetscCall(VecRestoreArray(coordinates, &coords)); 3089 PetscCall(VecRestoreArray(subCoordinates, &subCoords)); 3090 } 3091 PetscCall(DMSetCoordinatesLocal(subdm, subCoordinates)); 3092 PetscCall(VecDestroy(&subCoordinates)); 3093 } 3094 /* Cleanup */ 3095 if (subvertexIS) PetscCall(ISRestoreIndices(subvertexIS, &subVertices)); 3096 PetscCall(ISDestroy(&subvertexIS)); 3097 if (subcellIS) PetscCall(ISRestoreIndices(subcellIS, &subCells)); 3098 PetscCall(ISDestroy(&subcellIS)); 3099 PetscFunctionReturn(0); 3100 } 3101 3102 /* TODO: Fix this to properly propogate up error conditions it may find */ 3103 static inline PetscInt DMPlexFilterPoint_Internal(PetscInt point, PetscInt firstSubPoint, PetscInt numSubPoints, const PetscInt subPoints[]) 3104 { 3105 PetscInt subPoint; 3106 PetscErrorCode ierr; 3107 3108 ierr = PetscFindInt(point, numSubPoints, subPoints, &subPoint); if (ierr) return -1; 3109 return subPoint < 0 ? subPoint : firstSubPoint+subPoint; 3110 } 3111 3112 static PetscErrorCode DMPlexFilterLabels_Internal(DM dm, const PetscInt numSubPoints[], const PetscInt *subpoints[], const PetscInt firstSubPoint[], DM subdm) 3113 { 3114 PetscInt Nl, l, d; 3115 3116 PetscFunctionBegin; 3117 PetscCall(DMGetNumLabels(dm, &Nl)); 3118 for (l = 0; l < Nl; ++l) { 3119 DMLabel label, newlabel; 3120 const char *lname; 3121 PetscBool isDepth, isDim, isCelltype, isVTK; 3122 IS valueIS; 3123 const PetscInt *values; 3124 PetscInt Nv, v; 3125 3126 PetscCall(DMGetLabelName(dm, l, &lname)); 3127 PetscCall(PetscStrcmp(lname, "depth", &isDepth)); 3128 PetscCall(PetscStrcmp(lname, "dim", &isDim)); 3129 PetscCall(PetscStrcmp(lname, "celltype", &isCelltype)); 3130 PetscCall(PetscStrcmp(lname, "vtk", &isVTK)); 3131 if (isDepth || isDim || isCelltype || isVTK) continue; 3132 PetscCall(DMCreateLabel(subdm, lname)); 3133 PetscCall(DMGetLabel(dm, lname, &label)); 3134 PetscCall(DMGetLabel(subdm, lname, &newlabel)); 3135 PetscCall(DMLabelGetDefaultValue(label, &v)); 3136 PetscCall(DMLabelSetDefaultValue(newlabel, v)); 3137 PetscCall(DMLabelGetValueIS(label, &valueIS)); 3138 PetscCall(ISGetLocalSize(valueIS, &Nv)); 3139 PetscCall(ISGetIndices(valueIS, &values)); 3140 for (v = 0; v < Nv; ++v) { 3141 IS pointIS; 3142 const PetscInt *points; 3143 PetscInt Np, p; 3144 3145 PetscCall(DMLabelGetStratumIS(label, values[v], &pointIS)); 3146 PetscCall(ISGetLocalSize(pointIS, &Np)); 3147 PetscCall(ISGetIndices(pointIS, &points)); 3148 for (p = 0; p < Np; ++p) { 3149 const PetscInt point = points[p]; 3150 PetscInt subp; 3151 3152 PetscCall(DMPlexGetPointDepth(dm, point, &d)); 3153 subp = DMPlexFilterPoint_Internal(point, firstSubPoint[d], numSubPoints[d], subpoints[d]); 3154 if (subp >= 0) PetscCall(DMLabelSetValue(newlabel, subp, values[v])); 3155 } 3156 PetscCall(ISRestoreIndices(pointIS, &points)); 3157 PetscCall(ISDestroy(&pointIS)); 3158 } 3159 PetscCall(ISRestoreIndices(valueIS, &values)); 3160 PetscCall(ISDestroy(&valueIS)); 3161 } 3162 PetscFunctionReturn(0); 3163 } 3164 3165 static PetscErrorCode DMPlexCreateSubmeshGeneric_Interpolated(DM dm, DMLabel label, PetscInt value, PetscBool markedFaces, PetscBool isCohesive, PetscInt cellHeight, DM subdm) 3166 { 3167 MPI_Comm comm; 3168 DMLabel subpointMap; 3169 IS *subpointIS; 3170 const PetscInt **subpoints; 3171 PetscInt *numSubPoints, *firstSubPoint, *coneNew, *orntNew; 3172 PetscInt totSubPoints = 0, maxConeSize, dim, p, d, v; 3173 PetscMPIInt rank; 3174 3175 PetscFunctionBegin; 3176 PetscCall(PetscObjectGetComm((PetscObject)dm,&comm)); 3177 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 3178 /* Create subpointMap which marks the submesh */ 3179 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "subpoint_map", &subpointMap)); 3180 PetscCall(DMPlexSetSubpointMap(subdm, subpointMap)); 3181 if (cellHeight) { 3182 if (isCohesive) PetscCall(DMPlexMarkCohesiveSubmesh_Interpolated(dm, label, value, subpointMap, subdm)); 3183 else PetscCall(DMPlexMarkSubmesh_Interpolated(dm, label, value, markedFaces, subpointMap, subdm)); 3184 } else { 3185 DMLabel depth; 3186 IS pointIS; 3187 const PetscInt *points; 3188 PetscInt numPoints=0; 3189 3190 PetscCall(DMPlexGetDepthLabel(dm, &depth)); 3191 PetscCall(DMLabelGetStratumIS(label, value, &pointIS)); 3192 if (pointIS) { 3193 PetscCall(ISGetIndices(pointIS, &points)); 3194 PetscCall(ISGetLocalSize(pointIS, &numPoints)); 3195 } 3196 for (p = 0; p < numPoints; ++p) { 3197 PetscInt *closure = NULL; 3198 PetscInt closureSize, c, pdim; 3199 3200 PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closure)); 3201 for (c = 0; c < closureSize*2; c += 2) { 3202 PetscCall(DMLabelGetValue(depth, closure[c], &pdim)); 3203 PetscCall(DMLabelSetValue(subpointMap, closure[c], pdim)); 3204 } 3205 PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closure)); 3206 } 3207 if (pointIS) PetscCall(ISRestoreIndices(pointIS, &points)); 3208 PetscCall(ISDestroy(&pointIS)); 3209 } 3210 /* Setup chart */ 3211 PetscCall(DMGetDimension(dm, &dim)); 3212 PetscCall(PetscMalloc4(dim+1,&numSubPoints,dim+1,&firstSubPoint,dim+1,&subpointIS,dim+1,&subpoints)); 3213 for (d = 0; d <= dim; ++d) { 3214 PetscCall(DMLabelGetStratumSize(subpointMap, d, &numSubPoints[d])); 3215 totSubPoints += numSubPoints[d]; 3216 } 3217 PetscCall(DMPlexSetChart(subdm, 0, totSubPoints)); 3218 PetscCall(DMPlexSetVTKCellHeight(subdm, cellHeight)); 3219 /* Set cone sizes */ 3220 firstSubPoint[dim] = 0; 3221 firstSubPoint[0] = firstSubPoint[dim] + numSubPoints[dim]; 3222 if (dim > 1) {firstSubPoint[dim-1] = firstSubPoint[0] + numSubPoints[0];} 3223 if (dim > 2) {firstSubPoint[dim-2] = firstSubPoint[dim-1] + numSubPoints[dim-1];} 3224 for (d = 0; d <= dim; ++d) { 3225 PetscCall(DMLabelGetStratumIS(subpointMap, d, &subpointIS[d])); 3226 if (subpointIS[d]) PetscCall(ISGetIndices(subpointIS[d], &subpoints[d])); 3227 } 3228 /* We do not want this label automatically computed, instead we compute it here */ 3229 PetscCall(DMCreateLabel(subdm, "celltype")); 3230 for (d = 0; d <= dim; ++d) { 3231 for (p = 0; p < numSubPoints[d]; ++p) { 3232 const PetscInt point = subpoints[d][p]; 3233 const PetscInt subpoint = firstSubPoint[d] + p; 3234 const PetscInt *cone; 3235 PetscInt coneSize; 3236 3237 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 3238 if (cellHeight && (d == dim)) { 3239 PetscInt coneSizeNew, c, val; 3240 3241 PetscCall(DMPlexGetCone(dm, point, &cone)); 3242 for (c = 0, coneSizeNew = 0; c < coneSize; ++c) { 3243 PetscCall(DMLabelGetValue(subpointMap, cone[c], &val)); 3244 if (val >= 0) coneSizeNew++; 3245 } 3246 PetscCall(DMPlexSetConeSize(subdm, subpoint, coneSizeNew)); 3247 PetscCall(DMPlexSetCellType(subdm, subpoint, DM_POLYTOPE_FV_GHOST)); 3248 } else { 3249 DMPolytopeType ct; 3250 3251 PetscCall(DMPlexSetConeSize(subdm, subpoint, coneSize)); 3252 PetscCall(DMPlexGetCellType(dm, point, &ct)); 3253 PetscCall(DMPlexSetCellType(subdm, subpoint, ct)); 3254 } 3255 } 3256 } 3257 PetscCall(DMLabelDestroy(&subpointMap)); 3258 PetscCall(DMSetUp(subdm)); 3259 /* Set cones */ 3260 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, NULL)); 3261 PetscCall(PetscMalloc2(maxConeSize,&coneNew,maxConeSize,&orntNew)); 3262 for (d = 0; d <= dim; ++d) { 3263 for (p = 0; p < numSubPoints[d]; ++p) { 3264 const PetscInt point = subpoints[d][p]; 3265 const PetscInt subpoint = firstSubPoint[d] + p; 3266 const PetscInt *cone, *ornt; 3267 PetscInt coneSize, subconeSize, coneSizeNew, c, subc, fornt = 0; 3268 3269 if (d == dim-1) { 3270 const PetscInt *support, *cone, *ornt; 3271 PetscInt supportSize, coneSize, s, subc; 3272 3273 PetscCall(DMPlexGetSupport(dm, point, &support)); 3274 PetscCall(DMPlexGetSupportSize(dm, point, &supportSize)); 3275 for (s = 0; s < supportSize; ++s) { 3276 PetscBool isHybrid; 3277 3278 PetscCall(DMPlexCellIsHybrid_Internal(dm, support[s], &isHybrid)); 3279 if (!isHybrid) continue; 3280 PetscCall(PetscFindInt(support[s], numSubPoints[d+1], subpoints[d+1], &subc)); 3281 if (subc >= 0) { 3282 const PetscInt ccell = subpoints[d+1][subc]; 3283 3284 PetscCall(DMPlexGetCone(dm, ccell, &cone)); 3285 PetscCall(DMPlexGetConeSize(dm, ccell, &coneSize)); 3286 PetscCall(DMPlexGetConeOrientation(dm, ccell, &ornt)); 3287 for (c = 0; c < coneSize; ++c) { 3288 if (cone[c] == point) { 3289 fornt = ornt[c]; 3290 break; 3291 } 3292 } 3293 break; 3294 } 3295 } 3296 } 3297 PetscCall(DMPlexGetConeSize(dm, point, &coneSize)); 3298 PetscCall(DMPlexGetConeSize(subdm, subpoint, &subconeSize)); 3299 PetscCall(DMPlexGetCone(dm, point, &cone)); 3300 PetscCall(DMPlexGetConeOrientation(dm, point, &ornt)); 3301 for (c = 0, coneSizeNew = 0; c < coneSize; ++c) { 3302 PetscCall(PetscFindInt(cone[c], numSubPoints[d-1], subpoints[d-1], &subc)); 3303 if (subc >= 0) { 3304 coneNew[coneSizeNew] = firstSubPoint[d-1] + subc; 3305 orntNew[coneSizeNew] = ornt[c]; 3306 ++coneSizeNew; 3307 } 3308 } 3309 PetscCheck(coneSizeNew == subconeSize,comm, PETSC_ERR_PLIB, "Number of cone points located %d does not match subcone size %d", coneSizeNew, subconeSize); 3310 PetscCall(DMPlexSetCone(subdm, subpoint, coneNew)); 3311 PetscCall(DMPlexSetConeOrientation(subdm, subpoint, orntNew)); 3312 if (fornt < 0) PetscCall(DMPlexOrientPoint(subdm, subpoint, fornt)); 3313 } 3314 } 3315 PetscCall(PetscFree2(coneNew,orntNew)); 3316 PetscCall(DMPlexSymmetrize(subdm)); 3317 PetscCall(DMPlexStratify(subdm)); 3318 /* Build coordinates */ 3319 { 3320 PetscSection coordSection, subCoordSection; 3321 Vec coordinates, subCoordinates; 3322 PetscScalar *coords, *subCoords; 3323 PetscInt cdim, numComp, coordSize; 3324 const char *name; 3325 3326 PetscCall(DMGetCoordinateDim(dm, &cdim)); 3327 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 3328 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 3329 PetscCall(DMGetCoordinateSection(subdm, &subCoordSection)); 3330 PetscCall(PetscSectionSetNumFields(subCoordSection, 1)); 3331 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &numComp)); 3332 PetscCall(PetscSectionSetFieldComponents(subCoordSection, 0, numComp)); 3333 PetscCall(PetscSectionSetChart(subCoordSection, firstSubPoint[0], firstSubPoint[0]+numSubPoints[0])); 3334 for (v = 0; v < numSubPoints[0]; ++v) { 3335 const PetscInt vertex = subpoints[0][v]; 3336 const PetscInt subvertex = firstSubPoint[0]+v; 3337 PetscInt dof; 3338 3339 PetscCall(PetscSectionGetDof(coordSection, vertex, &dof)); 3340 PetscCall(PetscSectionSetDof(subCoordSection, subvertex, dof)); 3341 PetscCall(PetscSectionSetFieldDof(subCoordSection, subvertex, 0, dof)); 3342 } 3343 PetscCall(PetscSectionSetUp(subCoordSection)); 3344 PetscCall(PetscSectionGetStorageSize(subCoordSection, &coordSize)); 3345 PetscCall(VecCreate(PETSC_COMM_SELF, &subCoordinates)); 3346 PetscCall(PetscObjectGetName((PetscObject)coordinates,&name)); 3347 PetscCall(PetscObjectSetName((PetscObject)subCoordinates,name)); 3348 PetscCall(VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE)); 3349 PetscCall(VecSetBlockSize(subCoordinates, cdim)); 3350 PetscCall(VecSetType(subCoordinates,VECSTANDARD)); 3351 PetscCall(VecGetArray(coordinates, &coords)); 3352 PetscCall(VecGetArray(subCoordinates, &subCoords)); 3353 for (v = 0; v < numSubPoints[0]; ++v) { 3354 const PetscInt vertex = subpoints[0][v]; 3355 const PetscInt subvertex = firstSubPoint[0]+v; 3356 PetscInt dof, off, sdof, soff, d; 3357 3358 PetscCall(PetscSectionGetDof(coordSection, vertex, &dof)); 3359 PetscCall(PetscSectionGetOffset(coordSection, vertex, &off)); 3360 PetscCall(PetscSectionGetDof(subCoordSection, subvertex, &sdof)); 3361 PetscCall(PetscSectionGetOffset(subCoordSection, subvertex, &soff)); 3362 PetscCheck(dof == sdof,comm, PETSC_ERR_PLIB, "Coordinate dimension %d on subvertex %d, vertex %d should be %d", sdof, subvertex, vertex, dof); 3363 for (d = 0; d < dof; ++d) subCoords[soff+d] = coords[off+d]; 3364 } 3365 PetscCall(VecRestoreArray(coordinates, &coords)); 3366 PetscCall(VecRestoreArray(subCoordinates, &subCoords)); 3367 PetscCall(DMSetCoordinatesLocal(subdm, subCoordinates)); 3368 PetscCall(VecDestroy(&subCoordinates)); 3369 } 3370 /* Build SF: We need this complexity because subpoints might not be selected on the owning process */ 3371 { 3372 PetscSF sfPoint, sfPointSub; 3373 IS subpIS; 3374 const PetscSFNode *remotePoints; 3375 PetscSFNode *sremotePoints, *newLocalPoints, *newOwners; 3376 const PetscInt *localPoints, *subpoints; 3377 PetscInt *slocalPoints; 3378 PetscInt numRoots, numLeaves, numSubpoints = 0, numSubroots, numSubleaves = 0, l, sl, ll, pStart, pEnd, p; 3379 PetscMPIInt rank; 3380 3381 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 3382 PetscCall(DMGetPointSF(dm, &sfPoint)); 3383 PetscCall(DMGetPointSF(subdm, &sfPointSub)); 3384 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3385 PetscCall(DMPlexGetChart(subdm, NULL, &numSubroots)); 3386 PetscCall(DMPlexGetSubpointIS(subdm, &subpIS)); 3387 if (subpIS) { 3388 PetscCall(ISGetIndices(subpIS, &subpoints)); 3389 PetscCall(ISGetLocalSize(subpIS, &numSubpoints)); 3390 } 3391 PetscCall(PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints)); 3392 if (numRoots >= 0) { 3393 PetscCall(PetscMalloc2(pEnd-pStart,&newLocalPoints,numRoots,&newOwners)); 3394 for (p = 0; p < pEnd-pStart; ++p) { 3395 newLocalPoints[p].rank = -2; 3396 newLocalPoints[p].index = -2; 3397 } 3398 /* Set subleaves */ 3399 for (l = 0; l < numLeaves; ++l) { 3400 const PetscInt point = localPoints[l]; 3401 const PetscInt subpoint = DMPlexFilterPoint_Internal(point, 0, numSubpoints, subpoints); 3402 3403 if (subpoint < 0) continue; 3404 newLocalPoints[point-pStart].rank = rank; 3405 newLocalPoints[point-pStart].index = subpoint; 3406 ++numSubleaves; 3407 } 3408 /* Must put in owned subpoints */ 3409 for (p = pStart; p < pEnd; ++p) { 3410 const PetscInt subpoint = DMPlexFilterPoint_Internal(p, 0, numSubpoints, subpoints); 3411 3412 if (subpoint < 0) { 3413 newOwners[p-pStart].rank = -3; 3414 newOwners[p-pStart].index = -3; 3415 } else { 3416 newOwners[p-pStart].rank = rank; 3417 newOwners[p-pStart].index = subpoint; 3418 } 3419 } 3420 PetscCall(PetscSFReduceBegin(sfPoint, MPIU_2INT, newLocalPoints, newOwners, MPI_MAXLOC)); 3421 PetscCall(PetscSFReduceEnd(sfPoint, MPIU_2INT, newLocalPoints, newOwners, MPI_MAXLOC)); 3422 PetscCall(PetscSFBcastBegin(sfPoint, MPIU_2INT, newOwners, newLocalPoints,MPI_REPLACE)); 3423 PetscCall(PetscSFBcastEnd(sfPoint, MPIU_2INT, newOwners, newLocalPoints,MPI_REPLACE)); 3424 PetscCall(PetscMalloc1(numSubleaves, &slocalPoints)); 3425 PetscCall(PetscMalloc1(numSubleaves, &sremotePoints)); 3426 for (l = 0, sl = 0, ll = 0; l < numLeaves; ++l) { 3427 const PetscInt point = localPoints[l]; 3428 const PetscInt subpoint = DMPlexFilterPoint_Internal(point, 0, numSubpoints, subpoints); 3429 3430 if (subpoint < 0) continue; 3431 if (newLocalPoints[point].rank == rank) {++ll; continue;} 3432 slocalPoints[sl] = subpoint; 3433 sremotePoints[sl].rank = newLocalPoints[point].rank; 3434 sremotePoints[sl].index = newLocalPoints[point].index; 3435 PetscCheck(sremotePoints[sl].rank >= 0,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid remote rank for local point %d", point); 3436 PetscCheck(sremotePoints[sl].index >= 0,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid remote subpoint for local point %d", point); 3437 ++sl; 3438 } 3439 PetscCheckFalse(sl + ll != numSubleaves,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatch in number of subleaves %d + %d != %d", sl, ll, numSubleaves); 3440 PetscCall(PetscFree2(newLocalPoints,newOwners)); 3441 PetscCall(PetscSFSetGraph(sfPointSub, numSubroots, sl, slocalPoints, PETSC_OWN_POINTER, sremotePoints, PETSC_OWN_POINTER)); 3442 } 3443 if (subpIS) { 3444 PetscCall(ISRestoreIndices(subpIS, &subpoints)); 3445 } 3446 } 3447 /* Filter labels */ 3448 PetscCall(DMPlexFilterLabels_Internal(dm, numSubPoints, subpoints, firstSubPoint, subdm)); 3449 /* Cleanup */ 3450 for (d = 0; d <= dim; ++d) { 3451 if (subpointIS[d]) PetscCall(ISRestoreIndices(subpointIS[d], &subpoints[d])); 3452 PetscCall(ISDestroy(&subpointIS[d])); 3453 } 3454 PetscCall(PetscFree4(numSubPoints,firstSubPoint,subpointIS,subpoints)); 3455 PetscFunctionReturn(0); 3456 } 3457 3458 static PetscErrorCode DMPlexCreateSubmesh_Interpolated(DM dm, DMLabel vertexLabel, PetscInt value, PetscBool markedFaces, DM subdm) 3459 { 3460 PetscFunctionBegin; 3461 PetscCall(DMPlexCreateSubmeshGeneric_Interpolated(dm, vertexLabel, value, markedFaces, PETSC_FALSE, 1, subdm)); 3462 PetscFunctionReturn(0); 3463 } 3464 3465 /*@ 3466 DMPlexCreateSubmesh - Extract a hypersurface from the mesh using vertices defined by a label 3467 3468 Input Parameters: 3469 + dm - The original mesh 3470 . vertexLabel - The DMLabel marking points contained in the surface 3471 . value - The label value to use 3472 - markedFaces - PETSC_TRUE if surface faces are marked in addition to vertices, PETSC_FALSE if only vertices are marked 3473 3474 Output Parameter: 3475 . subdm - The surface mesh 3476 3477 Note: This function produces a DMLabel mapping original points in the submesh to their depth. This can be obtained using DMPlexGetSubpointMap(). 3478 3479 Level: developer 3480 3481 .seealso: DMPlexGetSubpointMap(), DMGetLabel(), DMLabelSetValue() 3482 @*/ 3483 PetscErrorCode DMPlexCreateSubmesh(DM dm, DMLabel vertexLabel, PetscInt value, PetscBool markedFaces, DM *subdm) 3484 { 3485 DMPlexInterpolatedFlag interpolated; 3486 PetscInt dim, cdim; 3487 3488 PetscFunctionBegin; 3489 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3490 PetscValidPointer(subdm, 5); 3491 PetscCall(DMGetDimension(dm, &dim)); 3492 PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), subdm)); 3493 PetscCall(DMSetType(*subdm, DMPLEX)); 3494 PetscCall(DMSetDimension(*subdm, dim-1)); 3495 PetscCall(DMGetCoordinateDim(dm, &cdim)); 3496 PetscCall(DMSetCoordinateDim(*subdm, cdim)); 3497 PetscCall(DMPlexIsInterpolated(dm, &interpolated)); 3498 PetscCheck(interpolated != DMPLEX_INTERPOLATED_PARTIAL,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not for partially interpolated meshes"); 3499 if (interpolated) { 3500 PetscCall(DMPlexCreateSubmesh_Interpolated(dm, vertexLabel, value, markedFaces, *subdm)); 3501 } else { 3502 PetscCall(DMPlexCreateSubmesh_Uninterpolated(dm, vertexLabel, value, *subdm)); 3503 } 3504 PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, *subdm)); 3505 PetscFunctionReturn(0); 3506 } 3507 3508 static PetscErrorCode DMPlexCreateCohesiveSubmesh_Uninterpolated(DM dm, PetscBool hasLagrange, const char label[], PetscInt value, DM subdm) 3509 { 3510 MPI_Comm comm; 3511 DMLabel subpointMap; 3512 IS subvertexIS; 3513 const PetscInt *subVertices; 3514 PetscInt numSubVertices, firstSubVertex, numSubCells, *subCells = NULL; 3515 PetscInt *subface, maxConeSize, numSubFaces, firstSubFace, newFacePoint, nFV; 3516 PetscInt c, f; 3517 3518 PetscFunctionBegin; 3519 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 3520 /* Create subpointMap which marks the submesh */ 3521 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "subpoint_map", &subpointMap)); 3522 PetscCall(DMPlexSetSubpointMap(subdm, subpointMap)); 3523 PetscCall(DMLabelDestroy(&subpointMap)); 3524 PetscCall(DMPlexMarkCohesiveSubmesh_Uninterpolated(dm, hasLagrange, label, value, subpointMap, &numSubFaces, &nFV, &subCells, subdm)); 3525 /* Setup chart */ 3526 PetscCall(DMLabelGetStratumSize(subpointMap, 0, &numSubVertices)); 3527 PetscCall(DMLabelGetStratumSize(subpointMap, 2, &numSubCells)); 3528 PetscCall(DMPlexSetChart(subdm, 0, numSubCells+numSubFaces+numSubVertices)); 3529 PetscCall(DMPlexSetVTKCellHeight(subdm, 1)); 3530 /* Set cone sizes */ 3531 firstSubVertex = numSubCells; 3532 firstSubFace = numSubCells+numSubVertices; 3533 newFacePoint = firstSubFace; 3534 PetscCall(DMLabelGetStratumIS(subpointMap, 0, &subvertexIS)); 3535 if (subvertexIS) PetscCall(ISGetIndices(subvertexIS, &subVertices)); 3536 for (c = 0; c < numSubCells; ++c) { 3537 PetscCall(DMPlexSetConeSize(subdm, c, 1)); 3538 } 3539 for (f = firstSubFace; f < firstSubFace+numSubFaces; ++f) { 3540 PetscCall(DMPlexSetConeSize(subdm, f, nFV)); 3541 } 3542 PetscCall(DMSetUp(subdm)); 3543 /* Create face cones */ 3544 PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, NULL)); 3545 PetscCall(DMGetWorkArray(subdm, maxConeSize, MPIU_INT, (void**) &subface)); 3546 for (c = 0; c < numSubCells; ++c) { 3547 const PetscInt cell = subCells[c]; 3548 const PetscInt subcell = c; 3549 const PetscInt *cone, *cells; 3550 PetscBool isHybrid; 3551 PetscInt numCells, subVertex, p, v; 3552 3553 PetscCall(DMPlexCellIsHybrid_Internal(dm, cell, &isHybrid)); 3554 if (!isHybrid) continue; 3555 PetscCall(DMPlexGetCone(dm, cell, &cone)); 3556 for (v = 0; v < nFV; ++v) { 3557 PetscCall(PetscFindInt(cone[v], numSubVertices, subVertices, &subVertex)); 3558 subface[v] = firstSubVertex+subVertex; 3559 } 3560 PetscCall(DMPlexSetCone(subdm, newFacePoint, subface)); 3561 PetscCall(DMPlexSetCone(subdm, subcell, &newFacePoint)); 3562 PetscCall(DMPlexGetJoin(dm, nFV, cone, &numCells, &cells)); 3563 /* Not true in parallel 3564 PetscCheck(numCells == 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cohesive cells should separate two cells"); */ 3565 for (p = 0; p < numCells; ++p) { 3566 PetscInt negsubcell; 3567 PetscBool isHybrid; 3568 3569 PetscCall(DMPlexCellIsHybrid_Internal(dm, cells[p], &isHybrid)); 3570 if (isHybrid) continue; 3571 /* I know this is a crap search */ 3572 for (negsubcell = 0; negsubcell < numSubCells; ++negsubcell) { 3573 if (subCells[negsubcell] == cells[p]) break; 3574 } 3575 PetscCheck(negsubcell != numSubCells,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find negative face neighbor for cohesive cell %d", cell); 3576 PetscCall(DMPlexSetCone(subdm, negsubcell, &newFacePoint)); 3577 } 3578 PetscCall(DMPlexRestoreJoin(dm, nFV, cone, &numCells, &cells)); 3579 ++newFacePoint; 3580 } 3581 PetscCall(DMRestoreWorkArray(subdm, maxConeSize, MPIU_INT, (void**) &subface)); 3582 PetscCall(DMPlexSymmetrize(subdm)); 3583 PetscCall(DMPlexStratify(subdm)); 3584 /* Build coordinates */ 3585 { 3586 PetscSection coordSection, subCoordSection; 3587 Vec coordinates, subCoordinates; 3588 PetscScalar *coords, *subCoords; 3589 PetscInt cdim, numComp, coordSize, v; 3590 const char *name; 3591 3592 PetscCall(DMGetCoordinateDim(dm, &cdim)); 3593 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 3594 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 3595 PetscCall(DMGetCoordinateSection(subdm, &subCoordSection)); 3596 PetscCall(PetscSectionSetNumFields(subCoordSection, 1)); 3597 PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &numComp)); 3598 PetscCall(PetscSectionSetFieldComponents(subCoordSection, 0, numComp)); 3599 PetscCall(PetscSectionSetChart(subCoordSection, firstSubVertex, firstSubVertex+numSubVertices)); 3600 for (v = 0; v < numSubVertices; ++v) { 3601 const PetscInt vertex = subVertices[v]; 3602 const PetscInt subvertex = firstSubVertex+v; 3603 PetscInt dof; 3604 3605 PetscCall(PetscSectionGetDof(coordSection, vertex, &dof)); 3606 PetscCall(PetscSectionSetDof(subCoordSection, subvertex, dof)); 3607 PetscCall(PetscSectionSetFieldDof(subCoordSection, subvertex, 0, dof)); 3608 } 3609 PetscCall(PetscSectionSetUp(subCoordSection)); 3610 PetscCall(PetscSectionGetStorageSize(subCoordSection, &coordSize)); 3611 PetscCall(VecCreate(PETSC_COMM_SELF, &subCoordinates)); 3612 PetscCall(PetscObjectGetName((PetscObject)coordinates,&name)); 3613 PetscCall(PetscObjectSetName((PetscObject)subCoordinates,name)); 3614 PetscCall(VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE)); 3615 PetscCall(VecSetBlockSize(subCoordinates, cdim)); 3616 PetscCall(VecSetType(subCoordinates,VECSTANDARD)); 3617 PetscCall(VecGetArray(coordinates, &coords)); 3618 PetscCall(VecGetArray(subCoordinates, &subCoords)); 3619 for (v = 0; v < numSubVertices; ++v) { 3620 const PetscInt vertex = subVertices[v]; 3621 const PetscInt subvertex = firstSubVertex+v; 3622 PetscInt dof, off, sdof, soff, d; 3623 3624 PetscCall(PetscSectionGetDof(coordSection, vertex, &dof)); 3625 PetscCall(PetscSectionGetOffset(coordSection, vertex, &off)); 3626 PetscCall(PetscSectionGetDof(subCoordSection, subvertex, &sdof)); 3627 PetscCall(PetscSectionGetOffset(subCoordSection, subvertex, &soff)); 3628 PetscCheck(dof == sdof,comm, PETSC_ERR_PLIB, "Coordinate dimension %d on subvertex %d, vertex %d should be %d", sdof, subvertex, vertex, dof); 3629 for (d = 0; d < dof; ++d) subCoords[soff+d] = coords[off+d]; 3630 } 3631 PetscCall(VecRestoreArray(coordinates, &coords)); 3632 PetscCall(VecRestoreArray(subCoordinates, &subCoords)); 3633 PetscCall(DMSetCoordinatesLocal(subdm, subCoordinates)); 3634 PetscCall(VecDestroy(&subCoordinates)); 3635 } 3636 /* Build SF */ 3637 CHKMEMQ; 3638 { 3639 PetscSF sfPoint, sfPointSub; 3640 const PetscSFNode *remotePoints; 3641 PetscSFNode *sremotePoints, *newLocalPoints, *newOwners; 3642 const PetscInt *localPoints; 3643 PetscInt *slocalPoints; 3644 PetscInt numRoots, numLeaves, numSubRoots = numSubCells+numSubFaces+numSubVertices, numSubLeaves = 0, l, sl, ll, pStart, pEnd, p, vStart, vEnd; 3645 PetscMPIInt rank; 3646 3647 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank)); 3648 PetscCall(DMGetPointSF(dm, &sfPoint)); 3649 PetscCall(DMGetPointSF(subdm, &sfPointSub)); 3650 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3651 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 3652 PetscCall(PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints)); 3653 if (numRoots >= 0) { 3654 /* Only vertices should be shared */ 3655 PetscCall(PetscMalloc2(pEnd-pStart,&newLocalPoints,numRoots,&newOwners)); 3656 for (p = 0; p < pEnd-pStart; ++p) { 3657 newLocalPoints[p].rank = -2; 3658 newLocalPoints[p].index = -2; 3659 } 3660 /* Set subleaves */ 3661 for (l = 0; l < numLeaves; ++l) { 3662 const PetscInt point = localPoints[l]; 3663 const PetscInt subPoint = DMPlexFilterPoint_Internal(point, firstSubVertex, numSubVertices, subVertices); 3664 3665 PetscCheck(!(point < vStart) || !(point >= vEnd),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Should not be mapping anything but vertices, %d", point); 3666 if (subPoint < 0) continue; 3667 newLocalPoints[point-pStart].rank = rank; 3668 newLocalPoints[point-pStart].index = subPoint; 3669 ++numSubLeaves; 3670 } 3671 /* Must put in owned subpoints */ 3672 for (p = pStart; p < pEnd; ++p) { 3673 const PetscInt subPoint = DMPlexFilterPoint_Internal(p, firstSubVertex, numSubVertices, subVertices); 3674 3675 if (subPoint < 0) { 3676 newOwners[p-pStart].rank = -3; 3677 newOwners[p-pStart].index = -3; 3678 } else { 3679 newOwners[p-pStart].rank = rank; 3680 newOwners[p-pStart].index = subPoint; 3681 } 3682 } 3683 PetscCall(PetscSFReduceBegin(sfPoint, MPIU_2INT, newLocalPoints, newOwners, MPI_MAXLOC)); 3684 PetscCall(PetscSFReduceEnd(sfPoint, MPIU_2INT, newLocalPoints, newOwners, MPI_MAXLOC)); 3685 PetscCall(PetscSFBcastBegin(sfPoint, MPIU_2INT, newOwners, newLocalPoints,MPI_REPLACE)); 3686 PetscCall(PetscSFBcastEnd(sfPoint, MPIU_2INT, newOwners, newLocalPoints,MPI_REPLACE)); 3687 PetscCall(PetscMalloc1(numSubLeaves, &slocalPoints)); 3688 PetscCall(PetscMalloc1(numSubLeaves, &sremotePoints)); 3689 for (l = 0, sl = 0, ll = 0; l < numLeaves; ++l) { 3690 const PetscInt point = localPoints[l]; 3691 const PetscInt subPoint = DMPlexFilterPoint_Internal(point, firstSubVertex, numSubVertices, subVertices); 3692 3693 if (subPoint < 0) continue; 3694 if (newLocalPoints[point].rank == rank) {++ll; continue;} 3695 slocalPoints[sl] = subPoint; 3696 sremotePoints[sl].rank = newLocalPoints[point].rank; 3697 sremotePoints[sl].index = newLocalPoints[point].index; 3698 PetscCheck(sremotePoints[sl].rank >= 0,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid remote rank for local point %d", point); 3699 PetscCheck(sremotePoints[sl].index >= 0,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid remote subpoint for local point %d", point); 3700 ++sl; 3701 } 3702 PetscCall(PetscFree2(newLocalPoints,newOwners)); 3703 PetscCheckFalse(sl + ll != numSubLeaves,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatch in number of subleaves %d + %d != %d", sl, ll, numSubLeaves); 3704 PetscCall(PetscSFSetGraph(sfPointSub, numSubRoots, sl, slocalPoints, PETSC_OWN_POINTER, sremotePoints, PETSC_OWN_POINTER)); 3705 } 3706 } 3707 CHKMEMQ; 3708 /* Cleanup */ 3709 if (subvertexIS) PetscCall(ISRestoreIndices(subvertexIS, &subVertices)); 3710 PetscCall(ISDestroy(&subvertexIS)); 3711 PetscCall(PetscFree(subCells)); 3712 PetscFunctionReturn(0); 3713 } 3714 3715 static PetscErrorCode DMPlexCreateCohesiveSubmesh_Interpolated(DM dm, const char labelname[], PetscInt value, DM subdm) 3716 { 3717 DMLabel label = NULL; 3718 3719 PetscFunctionBegin; 3720 if (labelname) PetscCall(DMGetLabel(dm, labelname, &label)); 3721 PetscCall(DMPlexCreateSubmeshGeneric_Interpolated(dm, label, value, PETSC_FALSE, PETSC_TRUE, 1, subdm)); 3722 PetscFunctionReturn(0); 3723 } 3724 3725 /*@C 3726 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. 3727 3728 Input Parameters: 3729 + dm - The original mesh 3730 . hasLagrange - The mesh has Lagrange unknowns in the cohesive cells 3731 . label - A label name, or NULL 3732 - value - A label value 3733 3734 Output Parameter: 3735 . subdm - The surface mesh 3736 3737 Note: This function produces a DMLabel mapping original points in the submesh to their depth. This can be obtained using DMPlexGetSubpointMap(). 3738 3739 Level: developer 3740 3741 .seealso: DMPlexGetSubpointMap(), DMPlexCreateSubmesh() 3742 @*/ 3743 PetscErrorCode DMPlexCreateCohesiveSubmesh(DM dm, PetscBool hasLagrange, const char label[], PetscInt value, DM *subdm) 3744 { 3745 PetscInt dim, cdim, depth; 3746 3747 PetscFunctionBegin; 3748 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3749 PetscValidPointer(subdm, 5); 3750 PetscCall(DMGetDimension(dm, &dim)); 3751 PetscCall(DMPlexGetDepth(dm, &depth)); 3752 PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), subdm)); 3753 PetscCall(DMSetType(*subdm, DMPLEX)); 3754 PetscCall(DMSetDimension(*subdm, dim-1)); 3755 PetscCall(DMGetCoordinateDim(dm, &cdim)); 3756 PetscCall(DMSetCoordinateDim(*subdm, cdim)); 3757 if (depth == dim) { 3758 PetscCall(DMPlexCreateCohesiveSubmesh_Interpolated(dm, label, value, *subdm)); 3759 } else { 3760 PetscCall(DMPlexCreateCohesiveSubmesh_Uninterpolated(dm, hasLagrange, label, value, *subdm)); 3761 } 3762 PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, *subdm)); 3763 PetscFunctionReturn(0); 3764 } 3765 3766 /*@ 3767 DMPlexFilter - Extract a subset of mesh cells defined by a label as a separate mesh 3768 3769 Input Parameters: 3770 + dm - The original mesh 3771 . cellLabel - The DMLabel marking cells contained in the new mesh 3772 - value - The label value to use 3773 3774 Output Parameter: 3775 . subdm - The new mesh 3776 3777 Note: This function produces a DMLabel mapping original points in the submesh to their depth. This can be obtained using DMPlexGetSubpointMap(). 3778 3779 Level: developer 3780 3781 .seealso: DMPlexGetSubpointMap(), DMGetLabel(), DMLabelSetValue() 3782 @*/ 3783 PetscErrorCode DMPlexFilter(DM dm, DMLabel cellLabel, PetscInt value, DM *subdm) 3784 { 3785 PetscInt dim; 3786 3787 PetscFunctionBegin; 3788 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3789 PetscValidPointer(subdm, 4); 3790 PetscCall(DMGetDimension(dm, &dim)); 3791 PetscCall(DMCreate(PetscObjectComm((PetscObject) dm), subdm)); 3792 PetscCall(DMSetType(*subdm, DMPLEX)); 3793 PetscCall(DMSetDimension(*subdm, dim)); 3794 /* Extract submesh in place, could be empty on some procs, could have inconsistency if procs do not both extract a shared cell */ 3795 PetscCall(DMPlexCreateSubmeshGeneric_Interpolated(dm, cellLabel, value, PETSC_FALSE, PETSC_FALSE, 0, *subdm)); 3796 PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, *subdm)); 3797 PetscFunctionReturn(0); 3798 } 3799 3800 /*@ 3801 DMPlexGetSubpointMap - Returns a DMLabel with point dimension as values 3802 3803 Input Parameter: 3804 . dm - The submesh DM 3805 3806 Output Parameter: 3807 . subpointMap - The DMLabel of all the points from the original mesh in this submesh, or NULL if this is not a submesh 3808 3809 Level: developer 3810 3811 .seealso: DMPlexCreateSubmesh(), DMPlexGetSubpointIS() 3812 @*/ 3813 PetscErrorCode DMPlexGetSubpointMap(DM dm, DMLabel *subpointMap) 3814 { 3815 PetscFunctionBegin; 3816 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3817 PetscValidPointer(subpointMap, 2); 3818 *subpointMap = ((DM_Plex*) dm->data)->subpointMap; 3819 PetscFunctionReturn(0); 3820 } 3821 3822 /*@ 3823 DMPlexSetSubpointMap - Sets the DMLabel with point dimension as values 3824 3825 Input Parameters: 3826 + dm - The submesh DM 3827 - subpointMap - The DMLabel of all the points from the original mesh in this submesh 3828 3829 Note: Should normally not be called by the user, since it is set in DMPlexCreateSubmesh() 3830 3831 Level: developer 3832 3833 .seealso: DMPlexCreateSubmesh(), DMPlexGetSubpointIS() 3834 @*/ 3835 PetscErrorCode DMPlexSetSubpointMap(DM dm, DMLabel subpointMap) 3836 { 3837 DM_Plex *mesh = (DM_Plex *) dm->data; 3838 DMLabel tmp; 3839 3840 PetscFunctionBegin; 3841 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3842 tmp = mesh->subpointMap; 3843 mesh->subpointMap = subpointMap; 3844 PetscCall(PetscObjectReference((PetscObject) mesh->subpointMap)); 3845 PetscCall(DMLabelDestroy(&tmp)); 3846 PetscFunctionReturn(0); 3847 } 3848 3849 static PetscErrorCode DMPlexCreateSubpointIS_Internal(DM dm, IS *subpointIS) 3850 { 3851 DMLabel spmap; 3852 PetscInt depth, d; 3853 3854 PetscFunctionBegin; 3855 PetscCall(DMPlexGetSubpointMap(dm, &spmap)); 3856 PetscCall(DMPlexGetDepth(dm, &depth)); 3857 if (spmap && depth >= 0) { 3858 DM_Plex *mesh = (DM_Plex *) dm->data; 3859 PetscInt *points, *depths; 3860 PetscInt pStart, pEnd, p, off; 3861 3862 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 3863 PetscCheck(!pStart,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Submeshes must start the point numbering at 0, not %d", pStart); 3864 PetscCall(PetscMalloc1(pEnd, &points)); 3865 PetscCall(DMGetWorkArray(dm, depth+1, MPIU_INT, &depths)); 3866 depths[0] = depth; 3867 depths[1] = 0; 3868 for (d = 2; d <= depth; ++d) {depths[d] = depth+1 - d;} 3869 for (d = 0, off = 0; d <= depth; ++d) { 3870 const PetscInt dep = depths[d]; 3871 PetscInt depStart, depEnd, n; 3872 3873 PetscCall(DMPlexGetDepthStratum(dm, dep, &depStart, &depEnd)); 3874 PetscCall(DMLabelGetStratumSize(spmap, dep, &n)); 3875 if (((d < 2) && (depth > 1)) || (d == 1)) { /* Only check vertices and cells for now since the map is broken for others */ 3876 PetscCheck(n == depEnd-depStart,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of mapped submesh points %d at depth %d should be %d", n, dep, depEnd-depStart); 3877 } else { 3878 if (!n) { 3879 if (d == 0) { 3880 /* Missing cells */ 3881 for (p = 0; p < depEnd-depStart; ++p, ++off) points[off] = -1; 3882 } else { 3883 /* Missing faces */ 3884 for (p = 0; p < depEnd-depStart; ++p, ++off) points[off] = PETSC_MAX_INT; 3885 } 3886 } 3887 } 3888 if (n) { 3889 IS is; 3890 const PetscInt *opoints; 3891 3892 PetscCall(DMLabelGetStratumIS(spmap, dep, &is)); 3893 PetscCall(ISGetIndices(is, &opoints)); 3894 for (p = 0; p < n; ++p, ++off) points[off] = opoints[p]; 3895 PetscCall(ISRestoreIndices(is, &opoints)); 3896 PetscCall(ISDestroy(&is)); 3897 } 3898 } 3899 PetscCall(DMRestoreWorkArray(dm, depth+1, MPIU_INT, &depths)); 3900 PetscCheck(off == pEnd,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of mapped submesh points %d should be %d", off, pEnd); 3901 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, pEnd, points, PETSC_OWN_POINTER, subpointIS)); 3902 PetscCall(PetscObjectStateGet((PetscObject) spmap, &mesh->subpointState)); 3903 } 3904 PetscFunctionReturn(0); 3905 } 3906 3907 /*@ 3908 DMPlexGetSubpointIS - Returns an IS covering the entire subdm chart with the original points as data 3909 3910 Input Parameter: 3911 . dm - The submesh DM 3912 3913 Output Parameter: 3914 . subpointIS - The IS of all the points from the original mesh in this submesh, or NULL if this is not a submesh 3915 3916 Note: This IS is guaranteed to be sorted by the construction of the submesh 3917 3918 Level: developer 3919 3920 .seealso: DMPlexCreateSubmesh(), DMPlexGetSubpointMap() 3921 @*/ 3922 PetscErrorCode DMPlexGetSubpointIS(DM dm, IS *subpointIS) 3923 { 3924 DM_Plex *mesh = (DM_Plex *) dm->data; 3925 DMLabel spmap; 3926 PetscObjectState state; 3927 3928 PetscFunctionBegin; 3929 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3930 PetscValidPointer(subpointIS, 2); 3931 PetscCall(DMPlexGetSubpointMap(dm, &spmap)); 3932 PetscCall(PetscObjectStateGet((PetscObject) spmap, &state)); 3933 if (state != mesh->subpointState || !mesh->subpointIS) PetscCall(DMPlexCreateSubpointIS_Internal(dm, &mesh->subpointIS)); 3934 *subpointIS = mesh->subpointIS; 3935 PetscFunctionReturn(0); 3936 } 3937 3938 /*@ 3939 DMGetEnclosureRelation - Get the relationship between dmA and dmB 3940 3941 Input Parameters: 3942 + dmA - The first DM 3943 - dmB - The second DM 3944 3945 Output Parameter: 3946 . rel - The relation of dmA to dmB 3947 3948 Level: intermediate 3949 3950 .seealso: DMGetEnclosurePoint() 3951 @*/ 3952 PetscErrorCode DMGetEnclosureRelation(DM dmA, DM dmB, DMEnclosureType *rel) 3953 { 3954 DM plexA, plexB, sdm; 3955 DMLabel spmap; 3956 PetscInt pStartA, pEndA, pStartB, pEndB, NpA, NpB; 3957 3958 PetscFunctionBegin; 3959 PetscValidPointer(rel, 3); 3960 *rel = DM_ENC_NONE; 3961 if (!dmA || !dmB) PetscFunctionReturn(0); 3962 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 3963 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 3964 if (dmA == dmB) {*rel = DM_ENC_EQUALITY; PetscFunctionReturn(0);} 3965 PetscCall(DMConvert(dmA, DMPLEX, &plexA)); 3966 PetscCall(DMConvert(dmB, DMPLEX, &plexB)); 3967 PetscCall(DMPlexGetChart(plexA, &pStartA, &pEndA)); 3968 PetscCall(DMPlexGetChart(plexB, &pStartB, &pEndB)); 3969 /* Assumption 1: subDMs have smaller charts than the DMs that they originate from 3970 - The degenerate case of a subdomain which includes all of the domain on some process can be treated as equality */ 3971 if ((pStartA == pStartB) && (pEndA == pEndB)) { 3972 *rel = DM_ENC_EQUALITY; 3973 goto end; 3974 } 3975 NpA = pEndA - pStartA; 3976 NpB = pEndB - pStartB; 3977 if (NpA == NpB) goto end; 3978 sdm = NpA > NpB ? plexB : plexA; /* The other is the original, enclosing dm */ 3979 PetscCall(DMPlexGetSubpointMap(sdm, &spmap)); 3980 if (!spmap) goto end; 3981 /* TODO Check the space mapped to by subpointMap is same size as dm */ 3982 if (NpA > NpB) { 3983 *rel = DM_ENC_SUPERMESH; 3984 } else { 3985 *rel = DM_ENC_SUBMESH; 3986 } 3987 end: 3988 PetscCall(DMDestroy(&plexA)); 3989 PetscCall(DMDestroy(&plexB)); 3990 PetscFunctionReturn(0); 3991 } 3992 3993 /*@ 3994 DMGetEnclosurePoint - Get the point pA in dmA which corresponds to the point pB in dmB 3995 3996 Input Parameters: 3997 + dmA - The first DM 3998 . dmB - The second DM 3999 . etype - The type of enclosure relation that dmA has to dmB 4000 - pB - A point of dmB 4001 4002 Output Parameter: 4003 . pA - The corresponding point of dmA 4004 4005 Level: intermediate 4006 4007 .seealso: DMGetEnclosureRelation() 4008 @*/ 4009 PetscErrorCode DMGetEnclosurePoint(DM dmA, DM dmB, DMEnclosureType etype, PetscInt pB, PetscInt *pA) 4010 { 4011 DM sdm; 4012 IS subpointIS; 4013 const PetscInt *subpoints; 4014 PetscInt numSubpoints; 4015 4016 PetscFunctionBegin; 4017 /* TODO Cache the IS, making it look like an index */ 4018 switch (etype) { 4019 case DM_ENC_SUPERMESH: 4020 sdm = dmB; 4021 PetscCall(DMPlexGetSubpointIS(sdm, &subpointIS)); 4022 PetscCall(ISGetIndices(subpointIS, &subpoints)); 4023 *pA = subpoints[pB]; 4024 PetscCall(ISRestoreIndices(subpointIS, &subpoints)); 4025 break; 4026 case DM_ENC_SUBMESH: 4027 sdm = dmA; 4028 PetscCall(DMPlexGetSubpointIS(sdm, &subpointIS)); 4029 PetscCall(ISGetLocalSize(subpointIS, &numSubpoints)); 4030 PetscCall(ISGetIndices(subpointIS, &subpoints)); 4031 PetscCall(PetscFindInt(pB, numSubpoints, subpoints, pA)); 4032 if (*pA < 0) { 4033 PetscCall(DMViewFromOptions(dmA, NULL, "-dm_enc_A_view")); 4034 PetscCall(DMViewFromOptions(dmB, NULL, "-dm_enc_B_view")); 4035 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %d not found in submesh", pB); 4036 } 4037 PetscCall(ISRestoreIndices(subpointIS, &subpoints)); 4038 break; 4039 case DM_ENC_EQUALITY: 4040 case DM_ENC_NONE: 4041 *pA = pB;break; 4042 case DM_ENC_UNKNOWN: 4043 { 4044 DMEnclosureType enc; 4045 4046 PetscCall(DMGetEnclosureRelation(dmA, dmB, &enc)); 4047 PetscCall(DMGetEnclosurePoint(dmA, dmB, enc, pB, pA)); 4048 } 4049 break; 4050 default: SETERRQ(PetscObjectComm((PetscObject) dmA), PETSC_ERR_ARG_OUTOFRANGE, "Invalid enclosure type %d", (int) etype); 4051 } 4052 PetscFunctionReturn(0); 4053 } 4054