Actual source code: plexsubmesh.c

  1: #include <petsc/private/dmpleximpl.h>
  2: #include <petsc/private/dmlabelimpl.h>
  3: #include <petscsf.h>

  5: static PetscErrorCode DMPlexCellIsHybrid_Internal(DM dm, PetscInt p, PetscBool *isHybrid)
  6: {
  7:   DMPolytopeType ct;

  9:   PetscFunctionBegin;
 10:   PetscCall(DMPlexGetCellType(dm, p, &ct));
 11:   switch (ct) {
 12:   case DM_POLYTOPE_POINT_PRISM_TENSOR:
 13:   case DM_POLYTOPE_SEG_PRISM_TENSOR:
 14:   case DM_POLYTOPE_TRI_PRISM_TENSOR:
 15:   case DM_POLYTOPE_QUAD_PRISM_TENSOR:
 16:     *isHybrid = PETSC_TRUE;
 17:     break;
 18:   default:
 19:     *isHybrid = PETSC_FALSE;
 20:     break;
 21:   }
 22:   PetscFunctionReturn(PETSC_SUCCESS);
 23: }

 25: static PetscErrorCode DMPlexGetTensorPrismBounds_Internal(DM dm, PetscInt dim, PetscInt *cStart, PetscInt *cEnd)
 26: {
 27:   DMLabel ctLabel;

 29:   PetscFunctionBegin;
 30:   if (cStart) *cStart = -1;
 31:   if (cEnd) *cEnd = -1;
 32:   PetscCall(DMPlexGetCellTypeLabel(dm, &ctLabel));
 33:   switch (dim) {
 34:   case 1:
 35:     PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_POINT_PRISM_TENSOR, cStart, cEnd));
 36:     break;
 37:   case 2:
 38:     PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_SEG_PRISM_TENSOR, cStart, cEnd));
 39:     break;
 40:   case 3:
 41:     PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_TRI_PRISM_TENSOR, cStart, cEnd));
 42:     if (*cStart < 0) PetscCall(DMLabelGetStratumBounds(ctLabel, DM_POLYTOPE_QUAD_PRISM_TENSOR, cStart, cEnd));
 43:     break;
 44:   default:
 45:     PetscFunctionReturn(PETSC_SUCCESS);
 46:   }
 47:   PetscFunctionReturn(PETSC_SUCCESS);
 48: }

 50: static PetscErrorCode DMPlexMarkBoundaryFaces_Internal(DM dm, PetscInt val, PetscInt cellHeight, DMLabel label)
 51: {
 52:   PetscSF         sf;
 53:   const PetscInt *rootdegree, *leaves;
 54:   PetscInt        overlap, Nr = -1, Nl, pStart, fStart, fEnd;

 56:   PetscFunctionBegin;
 57:   PetscCall(DMGetPointSF(dm, &sf));
 58:   PetscCall(DMPlexGetOverlap(dm, &overlap));
 59:   if (sf && !overlap) PetscCall(PetscSFGetGraph(sf, &Nr, &Nl, &leaves, NULL));
 60:   if (Nr > 0) {
 61:     PetscCall(PetscSFComputeDegreeBegin(sf, &rootdegree));
 62:     PetscCall(PetscSFComputeDegreeEnd(sf, &rootdegree));
 63:   } else rootdegree = NULL;
 64:   PetscCall(DMPlexGetChart(dm, &pStart, NULL));
 65:   PetscCall(DMPlexGetHeightStratum(dm, cellHeight + 1, &fStart, &fEnd));
 66:   for (PetscInt f = fStart; f < fEnd; ++f) {
 67:     PetscInt supportSize, loc = -1;

 69:     PetscCall(DMPlexGetSupportSize(dm, f, &supportSize));
 70:     if (supportSize == 1) {
 71:       /* Do not mark faces which are shared, meaning
 72:            they are  present in the pointSF, or
 73:            they have rootdegree > 0
 74:          since they presumably have cells on the other side */
 75:       if (Nr > 0) {
 76:         PetscCall(PetscFindInt(f, Nl, leaves, &loc));
 77:         if (rootdegree[f - pStart] || loc >= 0) continue;
 78:       }
 79:       if (val < 0) {
 80:         PetscInt *closure = NULL;
 81:         PetscInt  clSize, cl, cval;

 83:         PetscCall(DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &clSize, &closure));
 84:         for (cl = 0; cl < clSize * 2; cl += 2) {
 85:           PetscCall(DMLabelGetValue(label, closure[cl], &cval));
 86:           if (cval < 0) continue;
 87:           PetscCall(DMLabelSetValue(label, f, cval));
 88:           break;
 89:         }
 90:         if (cl == clSize * 2) PetscCall(DMLabelSetValue(label, f, 1));
 91:         PetscCall(DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &clSize, &closure));
 92:       } else {
 93:         PetscCall(DMLabelSetValue(label, f, val));
 94:       }
 95:     }
 96:   }
 97:   PetscFunctionReturn(PETSC_SUCCESS);
 98: }

100: /*@
101:   DMPlexMarkBoundaryFaces - Mark all faces on the boundary

103:   Not Collective

105:   Input Parameters:
106: + dm - The original `DM`
107: - val - The marker value, or PETSC_DETERMINE to use some value in the closure (or 1 if none are found)

109:   Output Parameter:
110: . label - The DMLabel marking boundary faces with the given value

112:   Note:
113:   This function will use the point `PetscSF` from the input `DM` to exclude points on the partition boundary from being marked, unless the partition overlap is greater than zero. If you also wish to mark the partition boundary, you can use `DMSetPointSF()` to temporarily set it to NULL, and then reset it to the original object after the call.

115:   Level: developer

117: .seealso: `DMLabelCreate()`, `DMCreateLabel()`
118: @*/
119: PetscErrorCode DMPlexMarkBoundaryFaces(DM dm, PetscInt val, DMLabel label)
120: {
121:   DMPlexInterpolatedFlag flg;

123:   PetscFunctionBegin;
125:   PetscCall(DMPlexIsInterpolated(dm, &flg));
126:   PetscCheck(flg == DMPLEX_INTERPOLATED_FULL, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "DM is not fully interpolated on this rank");
127:   PetscCall(DMPlexMarkBoundaryFaces_Internal(dm, val, 0, label));
128:   PetscFunctionReturn(PETSC_SUCCESS);
129: }

131: static PetscErrorCode DMPlexLabelComplete_Internal(DM dm, DMLabel label, PetscBool completeCells)
132: {
133:   IS              valueIS;
134:   PetscSF         sfPoint;
135:   const PetscInt *values;
136:   PetscInt        numValues, v, cStart, cEnd, nroots;

138:   PetscFunctionBegin;
139:   PetscCall(DMLabelGetNumValues(label, &numValues));
140:   PetscCall(DMLabelGetValueIS(label, &valueIS));
141:   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
142:   PetscCall(ISGetIndices(valueIS, &values));
143:   for (v = 0; v < numValues; ++v) {
144:     IS              pointIS;
145:     const PetscInt *points;
146:     PetscInt        numPoints, p;

148:     PetscCall(DMLabelGetStratumSize(label, values[v], &numPoints));
149:     PetscCall(DMLabelGetStratumIS(label, values[v], &pointIS));
150:     PetscCall(ISGetIndices(pointIS, &points));
151:     for (p = 0; p < numPoints; ++p) {
152:       PetscInt  q       = points[p];
153:       PetscInt *closure = NULL;
154:       PetscInt  closureSize, c;

156:       if (cStart <= q && q < cEnd && !completeCells) { /* skip cells */
157:         continue;
158:       }
159:       PetscCall(DMPlexGetTransitiveClosure(dm, q, PETSC_TRUE, &closureSize, &closure));
160:       for (c = 0; c < closureSize * 2; c += 2) PetscCall(DMLabelSetValue(label, closure[c], values[v]));
161:       PetscCall(DMPlexRestoreTransitiveClosure(dm, q, PETSC_TRUE, &closureSize, &closure));
162:     }
163:     PetscCall(ISRestoreIndices(pointIS, &points));
164:     PetscCall(ISDestroy(&pointIS));
165:   }
166:   PetscCall(ISRestoreIndices(valueIS, &values));
167:   PetscCall(ISDestroy(&valueIS));
168:   PetscCall(DMGetPointSF(dm, &sfPoint));
169:   PetscCall(PetscSFGetGraph(sfPoint, &nroots, NULL, NULL, NULL));
170:   if (nroots >= 0) {
171:     DMLabel         lblRoots, lblLeaves;
172:     IS              valueIS, pointIS;
173:     const PetscInt *values;
174:     PetscInt        numValues, v;

176:     /* Pull point contributions from remote leaves into local roots */
177:     PetscCall(DMLabelGather(label, sfPoint, &lblLeaves));
178:     PetscCall(DMLabelGetValueIS(lblLeaves, &valueIS));
179:     PetscCall(ISGetLocalSize(valueIS, &numValues));
180:     PetscCall(ISGetIndices(valueIS, &values));
181:     for (v = 0; v < numValues; ++v) {
182:       const PetscInt value = values[v];

184:       PetscCall(DMLabelGetStratumIS(lblLeaves, value, &pointIS));
185:       PetscCall(DMLabelInsertIS(label, pointIS, value));
186:       PetscCall(ISDestroy(&pointIS));
187:     }
188:     PetscCall(ISRestoreIndices(valueIS, &values));
189:     PetscCall(ISDestroy(&valueIS));
190:     PetscCall(DMLabelDestroy(&lblLeaves));
191:     /* Push point contributions from roots into remote leaves */
192:     PetscCall(DMLabelDistribute(label, sfPoint, &lblRoots));
193:     PetscCall(DMLabelGetValueIS(lblRoots, &valueIS));
194:     PetscCall(ISGetLocalSize(valueIS, &numValues));
195:     PetscCall(ISGetIndices(valueIS, &values));
196:     for (v = 0; v < numValues; ++v) {
197:       const PetscInt value = values[v];

199:       PetscCall(DMLabelGetStratumIS(lblRoots, value, &pointIS));
200:       PetscCall(DMLabelInsertIS(label, pointIS, value));
201:       PetscCall(ISDestroy(&pointIS));
202:     }
203:     PetscCall(ISRestoreIndices(valueIS, &values));
204:     PetscCall(ISDestroy(&valueIS));
205:     PetscCall(DMLabelDestroy(&lblRoots));
206:   }
207:   PetscFunctionReturn(PETSC_SUCCESS);
208: }

210: /*@
211:   DMPlexLabelComplete - Starting with a label marking points on a surface, we add the transitive closure to the surface

213:   Input Parameters:
214: + dm - The DM
215: - label - A DMLabel marking the surface points

217:   Output Parameter:
218: . label - A DMLabel marking all surface points in the transitive closure

220:   Level: developer

222: .seealso: `DMPlexLabelCohesiveComplete()`
223: @*/
224: PetscErrorCode DMPlexLabelComplete(DM dm, DMLabel label)
225: {
226:   PetscFunctionBegin;
227:   PetscCall(DMPlexLabelComplete_Internal(dm, label, PETSC_TRUE));
228:   PetscFunctionReturn(PETSC_SUCCESS);
229: }

231: /*@
232:   DMPlexLabelAddCells - Starting with a label marking points on a surface, we add a cell for each point

234:   Input Parameters:
235: + dm - The DM
236: - label - A DMLabel marking the surface points

238:   Output Parameter:
239: . label - A DMLabel incorporating cells

241:   Level: developer

243:   Note: The cells allow FEM boundary conditions to be applied using the cell geometry

245: .seealso: `DMPlexLabelAddFaceCells()`, `DMPlexLabelComplete()`, `DMPlexLabelCohesiveComplete()`
246: @*/
247: PetscErrorCode DMPlexLabelAddCells(DM dm, DMLabel label)
248: {
249:   IS              valueIS;
250:   const PetscInt *values;
251:   PetscInt        numValues, v, csStart, csEnd, chStart, chEnd;

253:   PetscFunctionBegin;
254:   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &csStart, &csEnd));
255:   PetscCall(DMPlexGetHeightStratum(dm, 0, &chStart, &chEnd));
256:   PetscCall(DMLabelGetNumValues(label, &numValues));
257:   PetscCall(DMLabelGetValueIS(label, &valueIS));
258:   PetscCall(ISGetIndices(valueIS, &values));
259:   for (v = 0; v < numValues; ++v) {
260:     IS              pointIS;
261:     const PetscInt *points;
262:     PetscInt        numPoints, p;

264:     PetscCall(DMLabelGetStratumSize(label, values[v], &numPoints));
265:     PetscCall(DMLabelGetStratumIS(label, values[v], &pointIS));
266:     PetscCall(ISGetIndices(pointIS, &points));
267:     for (p = 0; p < numPoints; ++p) {
268:       const PetscInt point   = points[p];
269:       PetscInt      *closure = NULL;
270:       PetscInt       closureSize, cl, h, pStart, pEnd, cStart, cEnd;

272:       // If the point is a hybrid, allow hybrid cells
273:       PetscCall(DMPlexGetPointHeight(dm, point, &h));
274:       PetscCall(DMPlexGetSimplexOrBoxCells(dm, h, &pStart, &pEnd));
275:       if (point >= pStart && point < pEnd) {
276:         cStart = csStart;
277:         cEnd   = csEnd;
278:       } else {
279:         cStart = chStart;
280:         cEnd   = chEnd;
281:       }

283:       PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closure));
284:       for (cl = closureSize - 1; cl > 0; --cl) {
285:         const PetscInt cell = closure[cl * 2];
286:         if ((cell >= cStart) && (cell < cEnd)) {
287:           PetscCall(DMLabelSetValue(label, cell, values[v]));
288:           break;
289:         }
290:       }
291:       PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closure));
292:     }
293:     PetscCall(ISRestoreIndices(pointIS, &points));
294:     PetscCall(ISDestroy(&pointIS));
295:   }
296:   PetscCall(ISRestoreIndices(valueIS, &values));
297:   PetscCall(ISDestroy(&valueIS));
298:   PetscFunctionReturn(PETSC_SUCCESS);
299: }

301: /*@
302:   DMPlexLabelAddFaceCells - Starting with a label marking faces on a surface, we add a cell for each face

304:   Input Parameters:
305: + dm - The DM
306: - label - A DMLabel marking the surface points

308:   Output Parameter:
309: . label - A DMLabel incorporating cells

311:   Level: developer

313:   Note: The cells allow FEM boundary conditions to be applied using the cell geometry

315: .seealso: `DMPlexLabelAddCells()`, `DMPlexLabelComplete()`, `DMPlexLabelCohesiveComplete()`
316: @*/
317: PetscErrorCode DMPlexLabelAddFaceCells(DM dm, DMLabel label)
318: {
319:   IS              valueIS;
320:   const PetscInt *values;
321:   PetscInt        numValues, v, cStart, cEnd, fStart, fEnd;

323:   PetscFunctionBegin;
324:   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
325:   PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
326:   PetscCall(DMLabelGetNumValues(label, &numValues));
327:   PetscCall(DMLabelGetValueIS(label, &valueIS));
328:   PetscCall(ISGetIndices(valueIS, &values));
329:   for (v = 0; v < numValues; ++v) {
330:     IS              pointIS;
331:     const PetscInt *points;
332:     PetscInt        numPoints, p;

334:     PetscCall(DMLabelGetStratumSize(label, values[v], &numPoints));
335:     PetscCall(DMLabelGetStratumIS(label, values[v], &pointIS));
336:     PetscCall(ISGetIndices(pointIS, &points));
337:     for (p = 0; p < numPoints; ++p) {
338:       const PetscInt face    = points[p];
339:       PetscInt      *closure = NULL;
340:       PetscInt       closureSize, cl;

342:       if ((face < fStart) || (face >= fEnd)) continue;
343:       PetscCall(DMPlexGetTransitiveClosure(dm, face, PETSC_FALSE, &closureSize, &closure));
344:       for (cl = closureSize - 1; cl > 0; --cl) {
345:         const PetscInt cell = closure[cl * 2];
346:         if ((cell >= cStart) && (cell < cEnd)) {
347:           PetscCall(DMLabelSetValue(label, cell, values[v]));
348:           break;
349:         }
350:       }
351:       PetscCall(DMPlexRestoreTransitiveClosure(dm, face, PETSC_FALSE, &closureSize, &closure));
352:     }
353:     PetscCall(ISRestoreIndices(pointIS, &points));
354:     PetscCall(ISDestroy(&pointIS));
355:   }
356:   PetscCall(ISRestoreIndices(valueIS, &values));
357:   PetscCall(ISDestroy(&valueIS));
358:   PetscFunctionReturn(PETSC_SUCCESS);
359: }

361: /*@
362:   DMPlexLabelClearCells - Remove cells from a label

364:   Input Parameters:
365: + dm - The DM
366: - label - A DMLabel marking surface points and their adjacent cells

368:   Output Parameter:
369: . label - A DMLabel without cells

371:   Level: developer

373:   Note: This undoes DMPlexLabelAddCells() or DMPlexLabelAddFaceCells()

375: .seealso: `DMPlexLabelComplete()`, `DMPlexLabelCohesiveComplete()`, `DMPlexLabelAddCells()`
376: @*/
377: PetscErrorCode DMPlexLabelClearCells(DM dm, DMLabel label)
378: {
379:   IS              valueIS;
380:   const PetscInt *values;
381:   PetscInt        numValues, v, cStart, cEnd;

383:   PetscFunctionBegin;
384:   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
385:   PetscCall(DMLabelGetNumValues(label, &numValues));
386:   PetscCall(DMLabelGetValueIS(label, &valueIS));
387:   PetscCall(ISGetIndices(valueIS, &values));
388:   for (v = 0; v < numValues; ++v) {
389:     IS              pointIS;
390:     const PetscInt *points;
391:     PetscInt        numPoints, p;

393:     PetscCall(DMLabelGetStratumSize(label, values[v], &numPoints));
394:     PetscCall(DMLabelGetStratumIS(label, values[v], &pointIS));
395:     PetscCall(ISGetIndices(pointIS, &points));
396:     for (p = 0; p < numPoints; ++p) {
397:       PetscInt point = points[p];

399:       if (point >= cStart && point < cEnd) PetscCall(DMLabelClearValue(label, point, values[v]));
400:     }
401:     PetscCall(ISRestoreIndices(pointIS, &points));
402:     PetscCall(ISDestroy(&pointIS));
403:   }
404:   PetscCall(ISRestoreIndices(valueIS, &values));
405:   PetscCall(ISDestroy(&valueIS));
406:   PetscFunctionReturn(PETSC_SUCCESS);
407: }

409: /* take (oldEnd, added) pairs, ordered by height and convert them to (oldstart, newstart) pairs, ordered by ascending
410:  * index (skipping first, which is (0,0)) */
411: static inline PetscErrorCode DMPlexShiftPointSetUp_Internal(PetscInt depth, PetscInt depthShift[])
412: {
413:   PetscInt d, off = 0;

415:   PetscFunctionBegin;
416:   /* sort by (oldend): yes this is an O(n^2) sort, we expect depth <= 3 */
417:   for (d = 0; d < depth; d++) {
418:     PetscInt firstd     = d;
419:     PetscInt firstStart = depthShift[2 * d];
420:     PetscInt e;

422:     for (e = d + 1; e <= depth; e++) {
423:       if (depthShift[2 * e] < firstStart) {
424:         firstd     = e;
425:         firstStart = depthShift[2 * d];
426:       }
427:     }
428:     if (firstd != d) {
429:       PetscInt swap[2];

431:       e                     = firstd;
432:       swap[0]               = depthShift[2 * d];
433:       swap[1]               = depthShift[2 * d + 1];
434:       depthShift[2 * d]     = depthShift[2 * e];
435:       depthShift[2 * d + 1] = depthShift[2 * e + 1];
436:       depthShift[2 * e]     = swap[0];
437:       depthShift[2 * e + 1] = swap[1];
438:     }
439:   }
440:   /* convert (oldstart, added) to (oldstart, newstart) */
441:   for (d = 0; d <= depth; d++) {
442:     off += depthShift[2 * d + 1];
443:     depthShift[2 * d + 1] = depthShift[2 * d] + off;
444:   }
445:   PetscFunctionReturn(PETSC_SUCCESS);
446: }

448: /* depthShift is a list of (old, new) pairs */
449: static inline PetscInt DMPlexShiftPoint_Internal(PetscInt p, PetscInt depth, PetscInt depthShift[])
450: {
451:   PetscInt d;
452:   PetscInt newOff = 0;

454:   for (d = 0; d <= depth; d++) {
455:     if (p < depthShift[2 * d]) return p + newOff;
456:     else newOff = depthShift[2 * d + 1] - depthShift[2 * d];
457:   }
458:   return p + newOff;
459: }

461: /* depthShift is a list of (old, new) pairs */
462: static inline PetscInt DMPlexShiftPointInverse_Internal(PetscInt p, PetscInt depth, PetscInt depthShift[])
463: {
464:   PetscInt d;
465:   PetscInt newOff = 0;

467:   for (d = 0; d <= depth; d++) {
468:     if (p < depthShift[2 * d + 1]) return p + newOff;
469:     else newOff = depthShift[2 * d] - depthShift[2 * d + 1];
470:   }
471:   return p + newOff;
472: }

474: static PetscErrorCode DMPlexShiftSizes_Internal(DM dm, PetscInt depthShift[], DM dmNew)
475: {
476:   PetscInt depth = 0, d, pStart, pEnd, p;
477:   DMLabel  depthLabel;

479:   PetscFunctionBegin;
480:   PetscCall(DMPlexGetDepth(dm, &depth));
481:   if (depth < 0) PetscFunctionReturn(PETSC_SUCCESS);
482:   /* Step 1: Expand chart */
483:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
484:   pEnd = DMPlexShiftPoint_Internal(pEnd, depth, depthShift);
485:   PetscCall(DMPlexSetChart(dmNew, pStart, pEnd));
486:   PetscCall(DMCreateLabel(dmNew, "depth"));
487:   PetscCall(DMPlexGetDepthLabel(dmNew, &depthLabel));
488:   PetscCall(DMCreateLabel(dmNew, "celltype"));
489:   /* Step 2: Set cone and support sizes */
490:   for (d = 0; d <= depth; ++d) {
491:     PetscInt pStartNew, pEndNew;
492:     IS       pIS;

494:     PetscCall(DMPlexGetDepthStratum(dm, d, &pStart, &pEnd));
495:     pStartNew = DMPlexShiftPoint_Internal(pStart, depth, depthShift);
496:     pEndNew   = DMPlexShiftPoint_Internal(pEnd, depth, depthShift);
497:     PetscCall(ISCreateStride(PETSC_COMM_SELF, pEndNew - pStartNew, pStartNew, 1, &pIS));
498:     PetscCall(DMLabelSetStratumIS(depthLabel, d, pIS));
499:     PetscCall(ISDestroy(&pIS));
500:     for (p = pStart; p < pEnd; ++p) {
501:       PetscInt       newp = DMPlexShiftPoint_Internal(p, depth, depthShift);
502:       PetscInt       size;
503:       DMPolytopeType ct;

505:       PetscCall(DMPlexGetConeSize(dm, p, &size));
506:       PetscCall(DMPlexSetConeSize(dmNew, newp, size));
507:       PetscCall(DMPlexGetSupportSize(dm, p, &size));
508:       PetscCall(DMPlexSetSupportSize(dmNew, newp, size));
509:       PetscCall(DMPlexGetCellType(dm, p, &ct));
510:       PetscCall(DMPlexSetCellType(dmNew, newp, ct));
511:     }
512:   }
513:   PetscFunctionReturn(PETSC_SUCCESS);
514: }

516: static PetscErrorCode DMPlexShiftPoints_Internal(DM dm, PetscInt depthShift[], DM dmNew)
517: {
518:   PetscInt *newpoints;
519:   PetscInt  depth = 0, maxConeSize, maxSupportSize, maxConeSizeNew, maxSupportSizeNew, pStart, pEnd, p;

521:   PetscFunctionBegin;
522:   PetscCall(DMPlexGetDepth(dm, &depth));
523:   if (depth < 0) PetscFunctionReturn(PETSC_SUCCESS);
524:   PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
525:   PetscCall(DMPlexGetMaxSizes(dmNew, &maxConeSizeNew, &maxSupportSizeNew));
526:   PetscCall(PetscMalloc1(PetscMax(PetscMax(maxConeSize, maxSupportSize), PetscMax(maxConeSizeNew, maxSupportSizeNew)), &newpoints));
527:   /* Step 5: Set cones and supports */
528:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
529:   for (p = pStart; p < pEnd; ++p) {
530:     const PetscInt *points = NULL, *orientations = NULL;
531:     PetscInt        size, sizeNew, i, newp = DMPlexShiftPoint_Internal(p, depth, depthShift);

533:     PetscCall(DMPlexGetConeSize(dm, p, &size));
534:     PetscCall(DMPlexGetCone(dm, p, &points));
535:     PetscCall(DMPlexGetConeOrientation(dm, p, &orientations));
536:     for (i = 0; i < size; ++i) newpoints[i] = DMPlexShiftPoint_Internal(points[i], depth, depthShift);
537:     PetscCall(DMPlexSetCone(dmNew, newp, newpoints));
538:     PetscCall(DMPlexSetConeOrientation(dmNew, newp, orientations));
539:     PetscCall(DMPlexGetSupportSize(dm, p, &size));
540:     PetscCall(DMPlexGetSupportSize(dmNew, newp, &sizeNew));
541:     PetscCall(DMPlexGetSupport(dm, p, &points));
542:     for (i = 0; i < size; ++i) newpoints[i] = DMPlexShiftPoint_Internal(points[i], depth, depthShift);
543:     for (i = size; i < sizeNew; ++i) newpoints[i] = 0;
544:     PetscCall(DMPlexSetSupport(dmNew, newp, newpoints));
545:   }
546:   PetscCall(PetscFree(newpoints));
547:   PetscFunctionReturn(PETSC_SUCCESS);
548: }

550: static PetscErrorCode DMPlexShiftCoordinates_Internal(DM dm, PetscInt depthShift[], DM dmNew)
551: {
552:   PetscSection coordSection, newCoordSection;
553:   Vec          coordinates, newCoordinates;
554:   PetscScalar *coords, *newCoords;
555:   PetscInt     coordSize, sStart, sEnd;
556:   PetscInt     dim, depth = 0, cStart, cEnd, cStartNew, cEndNew, c, vStart, vEnd, vStartNew, vEndNew, v;
557:   PetscBool    hasCells;

559:   PetscFunctionBegin;
560:   PetscCall(DMGetCoordinateDim(dm, &dim));
561:   PetscCall(DMSetCoordinateDim(dmNew, dim));
562:   PetscCall(DMPlexGetDepth(dm, &depth));
563:   /* Step 8: Convert coordinates */
564:   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
565:   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
566:   PetscCall(DMPlexGetDepthStratum(dmNew, 0, &vStartNew, &vEndNew));
567:   PetscCall(DMPlexGetHeightStratum(dmNew, 0, &cStartNew, &cEndNew));
568:   PetscCall(DMGetCoordinateSection(dm, &coordSection));
569:   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &newCoordSection));
570:   PetscCall(PetscSectionSetNumFields(newCoordSection, 1));
571:   PetscCall(PetscSectionSetFieldComponents(newCoordSection, 0, dim));
572:   PetscCall(PetscSectionGetChart(coordSection, &sStart, &sEnd));
573:   hasCells = sStart == cStart ? PETSC_TRUE : PETSC_FALSE;
574:   PetscCall(PetscSectionSetChart(newCoordSection, hasCells ? cStartNew : vStartNew, vEndNew));
575:   if (hasCells) {
576:     for (c = cStart; c < cEnd; ++c) {
577:       PetscInt cNew = DMPlexShiftPoint_Internal(c, depth, depthShift), dof;

579:       PetscCall(PetscSectionGetDof(coordSection, c, &dof));
580:       PetscCall(PetscSectionSetDof(newCoordSection, cNew, dof));
581:       PetscCall(PetscSectionSetFieldDof(newCoordSection, cNew, 0, dof));
582:     }
583:   }
584:   for (v = vStartNew; v < vEndNew; ++v) {
585:     PetscCall(PetscSectionSetDof(newCoordSection, v, dim));
586:     PetscCall(PetscSectionSetFieldDof(newCoordSection, v, 0, dim));
587:   }
588:   PetscCall(PetscSectionSetUp(newCoordSection));
589:   PetscCall(DMSetCoordinateSection(dmNew, PETSC_DETERMINE, newCoordSection));
590:   PetscCall(PetscSectionGetStorageSize(newCoordSection, &coordSize));
591:   PetscCall(VecCreate(PETSC_COMM_SELF, &newCoordinates));
592:   PetscCall(PetscObjectSetName((PetscObject)newCoordinates, "coordinates"));
593:   PetscCall(VecSetSizes(newCoordinates, coordSize, PETSC_DETERMINE));
594:   PetscCall(VecSetBlockSize(newCoordinates, dim));
595:   PetscCall(VecSetType(newCoordinates, VECSTANDARD));
596:   PetscCall(DMSetCoordinatesLocal(dmNew, newCoordinates));
597:   PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
598:   PetscCall(VecGetArray(coordinates, &coords));
599:   PetscCall(VecGetArray(newCoordinates, &newCoords));
600:   if (hasCells) {
601:     for (c = cStart; c < cEnd; ++c) {
602:       PetscInt cNew = DMPlexShiftPoint_Internal(c, depth, depthShift), dof, off, noff, d;

604:       PetscCall(PetscSectionGetDof(coordSection, c, &dof));
605:       PetscCall(PetscSectionGetOffset(coordSection, c, &off));
606:       PetscCall(PetscSectionGetOffset(newCoordSection, cNew, &noff));
607:       for (d = 0; d < dof; ++d) newCoords[noff + d] = coords[off + d];
608:     }
609:   }
610:   for (v = vStart; v < vEnd; ++v) {
611:     PetscInt dof, off, noff, d;

613:     PetscCall(PetscSectionGetDof(coordSection, v, &dof));
614:     PetscCall(PetscSectionGetOffset(coordSection, v, &off));
615:     PetscCall(PetscSectionGetOffset(newCoordSection, DMPlexShiftPoint_Internal(v, depth, depthShift), &noff));
616:     for (d = 0; d < dof; ++d) newCoords[noff + d] = coords[off + d];
617:   }
618:   PetscCall(VecRestoreArray(coordinates, &coords));
619:   PetscCall(VecRestoreArray(newCoordinates, &newCoords));
620:   PetscCall(VecDestroy(&newCoordinates));
621:   PetscCall(PetscSectionDestroy(&newCoordSection));
622:   PetscFunctionReturn(PETSC_SUCCESS);
623: }

625: static PetscErrorCode DMPlexShiftSF_Single(DM dm, PetscInt depthShift[], PetscSF sf, PetscSF sfNew)
626: {
627:   const PetscSFNode *remotePoints;
628:   PetscSFNode       *gremotePoints;
629:   const PetscInt    *localPoints;
630:   PetscInt          *glocalPoints, *newLocation, *newRemoteLocation;
631:   PetscInt           numRoots, numLeaves, l, pStart, pEnd, depth = 0, totShift = 0;

633:   PetscFunctionBegin;
634:   PetscCall(DMPlexGetDepth(dm, &depth));
635:   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
636:   PetscCall(PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints));
637:   totShift = DMPlexShiftPoint_Internal(pEnd, depth, depthShift) - pEnd;
638:   if (numRoots >= 0) {
639:     PetscCall(PetscMalloc2(numRoots, &newLocation, pEnd - pStart, &newRemoteLocation));
640:     for (l = 0; l < numRoots; ++l) newLocation[l] = DMPlexShiftPoint_Internal(l, depth, depthShift);
641:     PetscCall(PetscSFBcastBegin(sf, MPIU_INT, newLocation, newRemoteLocation, MPI_REPLACE));
642:     PetscCall(PetscSFBcastEnd(sf, MPIU_INT, newLocation, newRemoteLocation, MPI_REPLACE));
643:     PetscCall(PetscMalloc1(numLeaves, &glocalPoints));
644:     PetscCall(PetscMalloc1(numLeaves, &gremotePoints));
645:     for (l = 0; l < numLeaves; ++l) {
646:       glocalPoints[l]        = DMPlexShiftPoint_Internal(localPoints[l], depth, depthShift);
647:       gremotePoints[l].rank  = remotePoints[l].rank;
648:       gremotePoints[l].index = newRemoteLocation[localPoints[l]];
649:     }
650:     PetscCall(PetscFree2(newLocation, newRemoteLocation));
651:     PetscCall(PetscSFSetGraph(sfNew, numRoots + totShift, numLeaves, glocalPoints, PETSC_OWN_POINTER, gremotePoints, PETSC_OWN_POINTER));
652:   }
653:   PetscFunctionReturn(PETSC_SUCCESS);
654: }

656: static PetscErrorCode DMPlexShiftSF_Internal(DM dm, PetscInt depthShift[], DM dmNew)
657: {
658:   PetscSF   sfPoint, sfPointNew;
659:   PetscBool useNatural;

661:   PetscFunctionBegin;
662:   /* Step 9: Convert pointSF */
663:   PetscCall(DMGetPointSF(dm, &sfPoint));
664:   PetscCall(DMGetPointSF(dmNew, &sfPointNew));
665:   PetscCall(DMPlexShiftSF_Single(dm, depthShift, sfPoint, sfPointNew));
666:   /* Step 9b: Convert naturalSF */
667:   PetscCall(DMGetUseNatural(dm, &useNatural));
668:   if (useNatural) {
669:     PetscSF sfNat, sfNatNew;

671:     PetscCall(DMSetUseNatural(dmNew, useNatural));
672:     PetscCall(DMGetNaturalSF(dm, &sfNat));
673:     PetscCall(DMGetNaturalSF(dmNew, &sfNatNew));
674:     PetscCall(DMPlexShiftSF_Single(dm, depthShift, sfNat, sfNatNew));
675:   }
676:   PetscFunctionReturn(PETSC_SUCCESS);
677: }

679: static PetscErrorCode DMPlexShiftLabels_Internal(DM dm, PetscInt depthShift[], DM dmNew)
680: {
681:   PetscInt depth = 0, numLabels, l;

683:   PetscFunctionBegin;
684:   PetscCall(DMPlexGetDepth(dm, &depth));
685:   /* Step 10: Convert labels */
686:   PetscCall(DMGetNumLabels(dm, &numLabels));
687:   for (l = 0; l < numLabels; ++l) {
688:     DMLabel         label, newlabel;
689:     const char     *lname;
690:     PetscBool       isDepth, isDim;
691:     IS              valueIS;
692:     const PetscInt *values;
693:     PetscInt        numValues, val;

695:     PetscCall(DMGetLabelName(dm, l, &lname));
696:     PetscCall(PetscStrcmp(lname, "depth", &isDepth));
697:     if (isDepth) continue;
698:     PetscCall(PetscStrcmp(lname, "dim", &isDim));
699:     if (isDim) continue;
700:     PetscCall(DMCreateLabel(dmNew, lname));
701:     PetscCall(DMGetLabel(dm, lname, &label));
702:     PetscCall(DMGetLabel(dmNew, lname, &newlabel));
703:     PetscCall(DMLabelGetDefaultValue(label, &val));
704:     PetscCall(DMLabelSetDefaultValue(newlabel, val));
705:     PetscCall(DMLabelGetValueIS(label, &valueIS));
706:     PetscCall(ISGetLocalSize(valueIS, &numValues));
707:     PetscCall(ISGetIndices(valueIS, &values));
708:     for (val = 0; val < numValues; ++val) {
709:       IS              pointIS;
710:       const PetscInt *points;
711:       PetscInt        numPoints, p;

713:       PetscCall(DMLabelGetStratumIS(label, values[val], &pointIS));
714:       PetscCall(ISGetLocalSize(pointIS, &numPoints));
715:       PetscCall(ISGetIndices(pointIS, &points));
716:       for (p = 0; p < numPoints; ++p) {
717:         const PetscInt newpoint = DMPlexShiftPoint_Internal(points[p], depth, depthShift);

719:         PetscCall(DMLabelSetValue(newlabel, newpoint, values[val]));
720:       }
721:       PetscCall(ISRestoreIndices(pointIS, &points));
722:       PetscCall(ISDestroy(&pointIS));
723:     }
724:     PetscCall(ISRestoreIndices(valueIS, &values));
725:     PetscCall(ISDestroy(&valueIS));
726:   }
727:   PetscFunctionReturn(PETSC_SUCCESS);
728: }

730: static PetscErrorCode DMPlexCreateVTKLabel_Internal(DM dm, PetscBool createGhostLabel, DM dmNew)
731: {
732:   PetscSF            sfPoint;
733:   DMLabel            vtkLabel, ghostLabel = NULL;
734:   const PetscSFNode *leafRemote;
735:   const PetscInt    *leafLocal;
736:   PetscInt           cellHeight, cStart, cEnd, c, fStart, fEnd, f, numLeaves, l;
737:   PetscMPIInt        rank;

739:   PetscFunctionBegin;
740:   /* Step 11: Make label for output (vtk) and to mark ghost points (ghost) */
741:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
742:   PetscCall(DMGetPointSF(dm, &sfPoint));
743:   PetscCall(DMPlexGetVTKCellHeight(dmNew, &cellHeight));
744:   PetscCall(DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd));
745:   PetscCall(PetscSFGetGraph(sfPoint, NULL, &numLeaves, &leafLocal, &leafRemote));
746:   PetscCall(DMCreateLabel(dmNew, "vtk"));
747:   PetscCall(DMGetLabel(dmNew, "vtk", &vtkLabel));
748:   if (createGhostLabel) {
749:     PetscCall(DMCreateLabel(dmNew, "ghost"));
750:     PetscCall(DMGetLabel(dmNew, "ghost", &ghostLabel));
751:   }
752:   for (l = 0, c = cStart; l < numLeaves && c < cEnd; ++l, ++c) {
753:     for (; c < leafLocal[l] && c < cEnd; ++c) PetscCall(DMLabelSetValue(vtkLabel, c, 1));
754:     if (leafLocal[l] >= cEnd) break;
755:     if (leafRemote[l].rank == rank) {
756:       PetscCall(DMLabelSetValue(vtkLabel, c, 1));
757:     } else if (ghostLabel) PetscCall(DMLabelSetValue(ghostLabel, c, 2));
758:   }
759:   for (; c < cEnd; ++c) PetscCall(DMLabelSetValue(vtkLabel, c, 1));
760:   if (ghostLabel) {
761:     PetscCall(DMPlexGetHeightStratum(dmNew, 1, &fStart, &fEnd));
762:     for (f = fStart; f < fEnd; ++f) {
763:       PetscInt numCells;

765:       PetscCall(DMPlexGetSupportSize(dmNew, f, &numCells));
766:       if (numCells < 2) {
767:         PetscCall(DMLabelSetValue(ghostLabel, f, 1));
768:       } else {
769:         const PetscInt *cells = NULL;
770:         PetscInt        vA, vB;

772:         PetscCall(DMPlexGetSupport(dmNew, f, &cells));
773:         PetscCall(DMLabelGetValue(vtkLabel, cells[0], &vA));
774:         PetscCall(DMLabelGetValue(vtkLabel, cells[1], &vB));
775:         if (vA != 1 && vB != 1) PetscCall(DMLabelSetValue(ghostLabel, f, 1));
776:       }
777:     }
778:   }
779:   PetscFunctionReturn(PETSC_SUCCESS);
780: }

782: static PetscErrorCode DMPlexShiftTree_Internal(DM dm, PetscInt depthShift[], DM dmNew)
783: {
784:   DM           refTree;
785:   PetscSection pSec;
786:   PetscInt    *parents, *childIDs;

788:   PetscFunctionBegin;
789:   PetscCall(DMPlexGetReferenceTree(dm, &refTree));
790:   PetscCall(DMPlexSetReferenceTree(dmNew, refTree));
791:   PetscCall(DMPlexGetTree(dm, &pSec, &parents, &childIDs, NULL, NULL));
792:   if (pSec) {
793:     PetscInt     p, pStart, pEnd, *parentsShifted, pStartShifted, pEndShifted, depth;
794:     PetscInt    *childIDsShifted;
795:     PetscSection pSecShifted;

797:     PetscCall(PetscSectionGetChart(pSec, &pStart, &pEnd));
798:     PetscCall(DMPlexGetDepth(dm, &depth));
799:     pStartShifted = DMPlexShiftPoint_Internal(pStart, depth, depthShift);
800:     pEndShifted   = DMPlexShiftPoint_Internal(pEnd, depth, depthShift);
801:     PetscCall(PetscMalloc2(pEndShifted - pStartShifted, &parentsShifted, pEndShifted - pStartShifted, &childIDsShifted));
802:     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dmNew), &pSecShifted));
803:     PetscCall(PetscSectionSetChart(pSecShifted, pStartShifted, pEndShifted));
804:     for (p = pStartShifted; p < pEndShifted; p++) {
805:       /* start off assuming no children */
806:       PetscCall(PetscSectionSetDof(pSecShifted, p, 0));
807:     }
808:     for (p = pStart; p < pEnd; p++) {
809:       PetscInt dof;
810:       PetscInt pNew = DMPlexShiftPoint_Internal(p, depth, depthShift);

812:       PetscCall(PetscSectionGetDof(pSec, p, &dof));
813:       PetscCall(PetscSectionSetDof(pSecShifted, pNew, dof));
814:     }
815:     PetscCall(PetscSectionSetUp(pSecShifted));
816:     for (p = pStart; p < pEnd; p++) {
817:       PetscInt dof;
818:       PetscInt pNew = DMPlexShiftPoint_Internal(p, depth, depthShift);

820:       PetscCall(PetscSectionGetDof(pSec, p, &dof));
821:       if (dof) {
822:         PetscInt off, offNew;

824:         PetscCall(PetscSectionGetOffset(pSec, p, &off));
825:         PetscCall(PetscSectionGetOffset(pSecShifted, pNew, &offNew));
826:         parentsShifted[offNew]  = DMPlexShiftPoint_Internal(parents[off], depth, depthShift);
827:         childIDsShifted[offNew] = childIDs[off];
828:       }
829:     }
830:     PetscCall(DMPlexSetTree(dmNew, pSecShifted, parentsShifted, childIDsShifted));
831:     PetscCall(PetscFree2(parentsShifted, childIDsShifted));
832:     PetscCall(PetscSectionDestroy(&pSecShifted));
833:   }
834:   PetscFunctionReturn(PETSC_SUCCESS);
835: }

837: static PetscErrorCode DMPlexConstructGhostCells_Internal(DM dm, DMLabel label, PetscInt *numGhostCells, DM gdm)
838: {
839:   PetscSF          sf;
840:   IS               valueIS;
841:   const PetscInt  *values, *leaves;
842:   PetscInt        *depthShift;
843:   PetscInt         d, depth = 0, nleaves, loc, Ng, numFS, fs, fStart, fEnd, ghostCell, cEnd, c;
844:   const PetscReal *maxCell, *Lstart, *L;

846:   PetscFunctionBegin;
847:   PetscCall(DMGetPointSF(dm, &sf));
848:   PetscCall(PetscSFGetGraph(sf, NULL, &nleaves, &leaves, NULL));
849:   nleaves = PetscMax(0, nleaves);
850:   PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd));
851:   /* Count ghost cells */
852:   PetscCall(DMLabelGetValueIS(label, &valueIS));
853:   PetscCall(ISGetLocalSize(valueIS, &numFS));
854:   PetscCall(ISGetIndices(valueIS, &values));
855:   Ng = 0;
856:   for (fs = 0; fs < numFS; ++fs) {
857:     IS              faceIS;
858:     const PetscInt *faces;
859:     PetscInt        numFaces, f, numBdFaces = 0;

861:     PetscCall(DMLabelGetStratumIS(label, values[fs], &faceIS));
862:     PetscCall(ISGetLocalSize(faceIS, &numFaces));
863:     PetscCall(ISGetIndices(faceIS, &faces));
864:     for (f = 0; f < numFaces; ++f) {
865:       PetscInt numChildren;

867:       PetscCall(PetscFindInt(faces[f], nleaves, leaves, &loc));
868:       PetscCall(DMPlexGetTreeChildren(dm, faces[f], &numChildren, NULL));
869:       /* non-local and ancestors points don't get to register ghosts */
870:       if (loc >= 0 || numChildren) continue;
871:       if ((faces[f] >= fStart) && (faces[f] < fEnd)) ++numBdFaces;
872:     }
873:     Ng += numBdFaces;
874:     PetscCall(ISRestoreIndices(faceIS, &faces));
875:     PetscCall(ISDestroy(&faceIS));
876:   }
877:   PetscCall(DMPlexGetDepth(dm, &depth));
878:   PetscCall(PetscMalloc1(2 * (depth + 1), &depthShift));
879:   for (d = 0; d <= depth; d++) {
880:     PetscInt dEnd;

882:     PetscCall(DMPlexGetDepthStratum(dm, d, NULL, &dEnd));
883:     depthShift[2 * d]     = dEnd;
884:     depthShift[2 * d + 1] = 0;
885:   }
886:   if (depth >= 0) depthShift[2 * depth + 1] = Ng;
887:   PetscCall(DMPlexShiftPointSetUp_Internal(depth, depthShift));
888:   PetscCall(DMPlexShiftSizes_Internal(dm, depthShift, gdm));
889:   /* Step 3: Set cone/support sizes for new points */
890:   PetscCall(DMPlexGetHeightStratum(dm, 0, NULL, &cEnd));
891:   for (c = cEnd; c < cEnd + Ng; ++c) PetscCall(DMPlexSetConeSize(gdm, c, 1));
892:   for (fs = 0; fs < numFS; ++fs) {
893:     IS              faceIS;
894:     const PetscInt *faces;
895:     PetscInt        numFaces, f;

897:     PetscCall(DMLabelGetStratumIS(label, values[fs], &faceIS));
898:     PetscCall(ISGetLocalSize(faceIS, &numFaces));
899:     PetscCall(ISGetIndices(faceIS, &faces));
900:     for (f = 0; f < numFaces; ++f) {
901:       PetscInt size, numChildren;

903:       PetscCall(PetscFindInt(faces[f], nleaves, leaves, &loc));
904:       PetscCall(DMPlexGetTreeChildren(dm, faces[f], &numChildren, NULL));
905:       if (loc >= 0 || numChildren) continue;
906:       if ((faces[f] < fStart) || (faces[f] >= fEnd)) continue;
907:       PetscCall(DMPlexGetSupportSize(dm, faces[f], &size));
908:       PetscCheck(size == 1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "DM has boundary face %" PetscInt_FMT " with %" PetscInt_FMT " support cells", faces[f], size);
909:       PetscCall(DMPlexSetSupportSize(gdm, faces[f] + Ng, 2));
910:     }
911:     PetscCall(ISRestoreIndices(faceIS, &faces));
912:     PetscCall(ISDestroy(&faceIS));
913:   }
914:   /* Step 4: Setup ghosted DM */
915:   PetscCall(DMSetUp(gdm));
916:   PetscCall(DMPlexShiftPoints_Internal(dm, depthShift, gdm));
917:   /* Step 6: Set cones and supports for new points */
918:   ghostCell = cEnd;
919:   for (fs = 0; fs < numFS; ++fs) {
920:     IS              faceIS;
921:     const PetscInt *faces;
922:     PetscInt        numFaces, f;

924:     PetscCall(DMLabelGetStratumIS(label, values[fs], &faceIS));
925:     PetscCall(ISGetLocalSize(faceIS, &numFaces));
926:     PetscCall(ISGetIndices(faceIS, &faces));
927:     for (f = 0; f < numFaces; ++f) {
928:       PetscInt newFace = faces[f] + Ng, numChildren;

930:       PetscCall(PetscFindInt(faces[f], nleaves, leaves, &loc));
931:       PetscCall(DMPlexGetTreeChildren(dm, faces[f], &numChildren, NULL));
932:       if (loc >= 0 || numChildren) continue;
933:       if ((faces[f] < fStart) || (faces[f] >= fEnd)) continue;
934:       PetscCall(DMPlexSetCone(gdm, ghostCell, &newFace));
935:       PetscCall(DMPlexInsertSupport(gdm, newFace, 1, ghostCell));
936:       ++ghostCell;
937:     }
938:     PetscCall(ISRestoreIndices(faceIS, &faces));
939:     PetscCall(ISDestroy(&faceIS));
940:   }
941:   PetscCall(ISRestoreIndices(valueIS, &values));
942:   PetscCall(ISDestroy(&valueIS));
943:   PetscCall(DMPlexShiftCoordinates_Internal(dm, depthShift, gdm));
944:   PetscCall(DMPlexShiftSF_Internal(dm, depthShift, gdm));
945:   PetscCall(DMPlexShiftLabels_Internal(dm, depthShift, gdm));
946:   PetscCall(DMPlexCreateVTKLabel_Internal(dm, PETSC_TRUE, gdm));
947:   PetscCall(DMPlexShiftTree_Internal(dm, depthShift, gdm));
948:   PetscCall(PetscFree(depthShift));
949:   for (c = cEnd; c < cEnd + Ng; ++c) PetscCall(DMPlexSetCellType(gdm, c, DM_POLYTOPE_FV_GHOST));
950:   /* Step 7: Periodicity */
951:   PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L));
952:   PetscCall(DMSetPeriodicity(gdm, maxCell, Lstart, L));
953:   if (numGhostCells) *numGhostCells = Ng;
954:   PetscFunctionReturn(PETSC_SUCCESS);
955: }

957: /*@C
958:   DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face

960:   Collective on dm

962:   Input Parameters:
963: + dm - The original DM
964: - labelName - The label specifying the boundary faces, or "Face Sets" if this is NULL

966:   Output Parameters:
967: + numGhostCells - The number of ghost cells added to the DM
968: - dmGhosted - The new DM

970:   Note: If no label exists of that name, one will be created marking all boundary faces

972:   Level: developer

974: .seealso: `DMCreate()`
975: @*/
976: PetscErrorCode DMPlexConstructGhostCells(DM dm, const char labelName[], PetscInt *numGhostCells, DM *dmGhosted)
977: {
978:   DM          gdm;
979:   DMLabel     label;
980:   const char *name = labelName ? labelName : "Face Sets";
981:   PetscInt    dim, Ng = 0;
982:   PetscBool   useCone, useClosure;

984:   PetscFunctionBegin;
988:   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &gdm));
989:   PetscCall(DMSetType(gdm, DMPLEX));
990:   PetscCall(DMGetDimension(dm, &dim));
991:   PetscCall(DMSetDimension(gdm, dim));
992:   PetscCall(DMGetBasicAdjacency(dm, &useCone, &useClosure));
993:   PetscCall(DMSetBasicAdjacency(gdm, useCone, useClosure));
994:   PetscCall(DMGetLabel(dm, name, &label));
995:   if (!label) {
996:     /* Get label for boundary faces */
997:     PetscCall(DMCreateLabel(dm, name));
998:     PetscCall(DMGetLabel(dm, name, &label));
999:     PetscCall(DMPlexMarkBoundaryFaces(dm, 1, label));
1000:   }
1001:   PetscCall(DMPlexConstructGhostCells_Internal(dm, label, &Ng, gdm));
1002:   PetscCall(DMCopyDisc(dm, gdm));
1003:   PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_TRUE, gdm));
1004:   gdm->setfromoptionscalled = dm->setfromoptionscalled;
1005:   if (numGhostCells) *numGhostCells = Ng;
1006:   *dmGhosted = gdm;
1007:   PetscFunctionReturn(PETSC_SUCCESS);
1008: }

1010: static PetscErrorCode DivideCells_Private(DM dm, DMLabel label, DMPlexPointQueue queue)
1011: {
1012:   PetscInt dim, d, shift = 100, *pStart, *pEnd;

1014:   PetscFunctionBegin;
1015:   PetscCall(DMGetDimension(dm, &dim));
1016:   PetscCall(PetscMalloc2(dim, &pStart, dim, &pEnd));
1017:   for (d = 0; d < dim; ++d) PetscCall(DMPlexGetDepthStratum(dm, d, &pStart[d], &pEnd[d]));
1018:   while (!DMPlexPointQueueEmpty(queue)) {
1019:     PetscInt  cell    = -1;
1020:     PetscInt *closure = NULL;
1021:     PetscInt  closureSize, cl, cval;

1023:     PetscCall(DMPlexPointQueueDequeue(queue, &cell));
1024:     PetscCall(DMLabelGetValue(label, cell, &cval));
1025:     PetscCall(DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure));
1026:     /* Mark points in the cell closure that touch the fault */
1027:     for (d = 0; d < dim; ++d) {
1028:       for (cl = 0; cl < closureSize * 2; cl += 2) {
1029:         const PetscInt clp = closure[cl];
1030:         PetscInt       clval;

1032:         if ((clp < pStart[d]) || (clp >= pEnd[d])) continue;
1033:         PetscCall(DMLabelGetValue(label, clp, &clval));
1034:         if (clval == -1) {
1035:           const PetscInt *cone;
1036:           PetscInt        coneSize, c;

1038:           /* If a cone point touches the fault, then this point touches the fault */
1039:           PetscCall(DMPlexGetCone(dm, clp, &cone));
1040:           PetscCall(DMPlexGetConeSize(dm, clp, &coneSize));
1041:           for (c = 0; c < coneSize; ++c) {
1042:             PetscInt cpval;

1044:             PetscCall(DMLabelGetValue(label, cone[c], &cpval));
1045:             if (cpval != -1) {
1046:               PetscInt dep;

1048:               PetscCall(DMPlexGetPointDepth(dm, clp, &dep));
1049:               clval = cval < 0 ? -(shift + dep) : shift + dep;
1050:               PetscCall(DMLabelSetValue(label, clp, clval));
1051:               break;
1052:             }
1053:           }
1054:         }
1055:         /* Mark neighbor cells through marked faces (these cells must also touch the fault) */
1056:         if (d == dim - 1 && clval != -1) {
1057:           const PetscInt *support;
1058:           PetscInt        supportSize, s, nval;

1060:           PetscCall(DMPlexGetSupport(dm, clp, &support));
1061:           PetscCall(DMPlexGetSupportSize(dm, clp, &supportSize));
1062:           for (s = 0; s < supportSize; ++s) {
1063:             PetscCall(DMLabelGetValue(label, support[s], &nval));
1064:             if (nval == -1) {
1065:               PetscCall(DMLabelSetValue(label, support[s], clval < 0 ? clval - 1 : clval + 1));
1066:               PetscCall(DMPlexPointQueueEnqueue(queue, support[s]));
1067:             }
1068:           }
1069:         }
1070:       }
1071:     }
1072:     PetscCall(DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure));
1073:   }
1074:   PetscCall(PetscFree2(pStart, pEnd));
1075:   PetscFunctionReturn(PETSC_SUCCESS);
1076: }

1078: typedef struct {
1079:   DM               dm;
1080:   DMPlexPointQueue queue;
1081: } PointDivision;

1083: static PetscErrorCode divideCell(DMLabel label, PetscInt p, PetscInt val, void *ctx)
1084: {
1085:   PointDivision  *div  = (PointDivision *)ctx;
1086:   PetscInt        cval = val < 0 ? val - 1 : val + 1;
1087:   const PetscInt *support;
1088:   PetscInt        supportSize, s;

1090:   PetscFunctionBegin;
1091:   PetscCall(DMPlexGetSupport(div->dm, p, &support));
1092:   PetscCall(DMPlexGetSupportSize(div->dm, p, &supportSize));
1093:   for (s = 0; s < supportSize; ++s) {
1094:     PetscCall(DMLabelSetValue(label, support[s], cval));
1095:     PetscCall(DMPlexPointQueueEnqueue(div->queue, support[s]));
1096:   }
1097:   PetscFunctionReturn(PETSC_SUCCESS);
1098: }

1100: /* Mark cells by label propagation */
1101: static PetscErrorCode DMPlexLabelFaultHalo(DM dm, DMLabel faultLabel)
1102: {
1103:   DMPlexPointQueue queue = NULL;
1104:   PointDivision    div;
1105:   PetscSF          pointSF;
1106:   IS               pointIS;
1107:   const PetscInt  *points;
1108:   PetscBool        empty;
1109:   PetscInt         dim, shift = 100, n, i;

1111:   PetscFunctionBegin;
1112:   PetscCall(DMGetDimension(dm, &dim));
1113:   PetscCall(DMPlexPointQueueCreate(1024, &queue));
1114:   div.dm    = dm;
1115:   div.queue = queue;
1116:   /* Enqueue cells on fault */
1117:   PetscCall(DMLabelGetStratumIS(faultLabel, shift + dim, &pointIS));
1118:   if (pointIS) {
1119:     PetscCall(ISGetLocalSize(pointIS, &n));
1120:     PetscCall(ISGetIndices(pointIS, &points));
1121:     for (i = 0; i < n; ++i) PetscCall(DMPlexPointQueueEnqueue(queue, points[i]));
1122:     PetscCall(ISRestoreIndices(pointIS, &points));
1123:     PetscCall(ISDestroy(&pointIS));
1124:   }
1125:   PetscCall(DMLabelGetStratumIS(faultLabel, -(shift + dim), &pointIS));
1126:   if (pointIS) {
1127:     PetscCall(ISGetLocalSize(pointIS, &n));
1128:     PetscCall(ISGetIndices(pointIS, &points));
1129:     for (i = 0; i < n; ++i) PetscCall(DMPlexPointQueueEnqueue(queue, points[i]));
1130:     PetscCall(ISRestoreIndices(pointIS, &points));
1131:     PetscCall(ISDestroy(&pointIS));
1132:   }

1134:   PetscCall(DMGetPointSF(dm, &pointSF));
1135:   PetscCall(DMLabelPropagateBegin(faultLabel, pointSF));
1136:   /* While edge queue is not empty: */
1137:   PetscCall(DMPlexPointQueueEmptyCollective((PetscObject)dm, queue, &empty));
1138:   while (!empty) {
1139:     PetscCall(DivideCells_Private(dm, faultLabel, queue));
1140:     PetscCall(DMLabelPropagatePush(faultLabel, pointSF, divideCell, &div));
1141:     PetscCall(DMPlexPointQueueEmptyCollective((PetscObject)dm, queue, &empty));
1142:   }
1143:   PetscCall(DMLabelPropagateEnd(faultLabel, pointSF));
1144:   PetscCall(DMPlexPointQueueDestroy(&queue));
1145:   PetscFunctionReturn(PETSC_SUCCESS);
1146: }

1148: /*
1149:   We are adding three kinds of points here:
1150:     Replicated:     Copies of points which exist in the mesh, such as vertices identified across a fault
1151:     Non-replicated: Points which exist on the fault, but are not replicated
1152:     Ghost:          These are shared fault faces which are not owned by this process. These do not produce hybrid cells and do not replicate
1153:     Hybrid:         Entirely new points, such as cohesive cells

1155:   When creating subsequent cohesive cells, we shift the old hybrid cells to the end of the numbering at
1156:   each depth so that the new split/hybrid points can be inserted as a block.
1157: */
1158: static PetscErrorCode DMPlexConstructCohesiveCells_Internal(DM dm, DMLabel label, DMLabel splitLabel, DM sdm)
1159: {
1160:   MPI_Comm         comm;
1161:   IS               valueIS;
1162:   PetscInt         numSP = 0; /* The number of depths for which we have replicated points */
1163:   const PetscInt  *values;    /* List of depths for which we have replicated points */
1164:   IS              *splitIS;
1165:   IS              *unsplitIS;
1166:   IS               ghostIS;
1167:   PetscInt        *numSplitPoints;     /* The number of replicated points at each depth */
1168:   PetscInt        *numUnsplitPoints;   /* The number of non-replicated points at each depth which still give rise to hybrid points */
1169:   PetscInt        *numHybridPoints;    /* The number of new hybrid points at each depth */
1170:   PetscInt        *numHybridPointsOld; /* The number of existing hybrid points at each depth */
1171:   PetscInt         numGhostPoints;     /* The number of unowned, shared fault faces */
1172:   const PetscInt **splitPoints;        /* Replicated points for each depth */
1173:   const PetscInt **unsplitPoints;      /* Non-replicated points for each depth */
1174:   const PetscInt  *ghostPoints;        /* Ghost fault faces */
1175:   PetscSection     coordSection;
1176:   Vec              coordinates;
1177:   PetscScalar     *coords;
1178:   PetscInt        *depthMax;   /* The first hybrid point at each depth in the original mesh */
1179:   PetscInt        *depthEnd;   /* The point limit at each depth in the original mesh */
1180:   PetscInt        *depthShift; /* Number of replicated+hybrid points at each depth */
1181:   PetscInt        *pMaxNew;    /* The first replicated point at each depth in the new mesh, hybrids come after this */
1182:   PetscInt        *coneNew, *coneONew, *supportNew;
1183:   PetscInt         shift = 100, shift2 = 200, depth = 0, dep, dim, d, sp, maxConeSize, maxSupportSize, maxConeSizeNew, maxSupportSizeNew, numLabels, vStart, vEnd, pEnd, p, v;

1185:   PetscFunctionBegin;
1186:   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
1187:   PetscCall(DMGetDimension(dm, &dim));
1188:   PetscCall(DMPlexGetDepth(dm, &depth));
1189:   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
1190:   /* We do not want this label automatically computed, instead we compute it here */
1191:   PetscCall(DMCreateLabel(sdm, "celltype"));
1192:   /* Count split points and add cohesive cells */
1193:   PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize));
1194:   PetscCall(PetscMalloc5(depth + 1, &depthMax, depth + 1, &depthEnd, 2 * (depth + 1), &depthShift, depth + 1, &pMaxNew, depth + 1, &numHybridPointsOld));
1195:   PetscCall(PetscMalloc7(depth + 1, &splitIS, depth + 1, &unsplitIS, depth + 1, &numSplitPoints, depth + 1, &numUnsplitPoints, depth + 1, &numHybridPoints, depth + 1, &splitPoints, depth + 1, &unsplitPoints));
1196:   for (d = 0; d <= depth; ++d) {
1197:     PetscCall(DMPlexGetDepthStratum(dm, d, NULL, &pMaxNew[d]));
1198:     PetscCall(DMPlexGetTensorPrismBounds_Internal(dm, d, &depthMax[d], NULL));
1199:     depthEnd[d]           = pMaxNew[d];
1200:     depthMax[d]           = depthMax[d] < 0 ? depthEnd[d] : depthMax[d];
1201:     numSplitPoints[d]     = 0;
1202:     numUnsplitPoints[d]   = 0;
1203:     numHybridPoints[d]    = 0;
1204:     numHybridPointsOld[d] = depthMax[d] < 0 ? 0 : depthEnd[d] - depthMax[d];
1205:     splitPoints[d]        = NULL;
1206:     unsplitPoints[d]      = NULL;
1207:     splitIS[d]            = NULL;
1208:     unsplitIS[d]          = NULL;
1209:     /* we are shifting the existing hybrid points with the stratum behind them, so
1210:      * the split comes at the end of the normal points, i.e., at depthMax[d] */
1211:     depthShift[2 * d]     = depthMax[d];
1212:     depthShift[2 * d + 1] = 0;
1213:   }
1214:   numGhostPoints = 0;
1215:   ghostPoints    = NULL;
1216:   if (label) {
1217:     PetscCall(DMLabelGetValueIS(label, &valueIS));
1218:     PetscCall(ISGetLocalSize(valueIS, &numSP));
1219:     PetscCall(ISGetIndices(valueIS, &values));
1220:   }
1221:   for (sp = 0; sp < numSP; ++sp) {
1222:     const PetscInt dep = values[sp];

1224:     if ((dep < 0) || (dep > depth)) continue;
1225:     PetscCall(DMLabelGetStratumIS(label, dep, &splitIS[dep]));
1226:     if (splitIS[dep]) {
1227:       PetscCall(ISGetLocalSize(splitIS[dep], &numSplitPoints[dep]));
1228:       PetscCall(ISGetIndices(splitIS[dep], &splitPoints[dep]));
1229:     }
1230:     PetscCall(DMLabelGetStratumIS(label, shift2 + dep, &unsplitIS[dep]));
1231:     if (unsplitIS[dep]) {
1232:       PetscCall(ISGetLocalSize(unsplitIS[dep], &numUnsplitPoints[dep]));
1233:       PetscCall(ISGetIndices(unsplitIS[dep], &unsplitPoints[dep]));
1234:     }
1235:   }
1236:   PetscCall(DMLabelGetStratumIS(label, shift2 + dim - 1, &ghostIS));
1237:   if (ghostIS) {
1238:     PetscCall(ISGetLocalSize(ghostIS, &numGhostPoints));
1239:     PetscCall(ISGetIndices(ghostIS, &ghostPoints));
1240:   }
1241:   /* Calculate number of hybrid points */
1242:   for (d = 1; d <= depth; ++d) numHybridPoints[d] = numSplitPoints[d - 1] + numUnsplitPoints[d - 1]; /* There is a hybrid cell/face/edge for every split face/edge/vertex   */
1243:   for (d = 0; d <= depth; ++d) depthShift[2 * d + 1] = numSplitPoints[d] + numHybridPoints[d];
1244:   PetscCall(DMPlexShiftPointSetUp_Internal(depth, depthShift));
1245:   /* the end of the points in this stratum that come before the new points:
1246:    * shifting pMaxNew[d] gets the new start of the next stratum, then count back the old hybrid points and the newly
1247:    * added points */
1248:   for (d = 0; d <= depth; ++d) pMaxNew[d] = DMPlexShiftPoint_Internal(pMaxNew[d], depth, depthShift) - (numHybridPointsOld[d] + numSplitPoints[d] + numHybridPoints[d]);
1249:   PetscCall(DMPlexShiftSizes_Internal(dm, depthShift, sdm));
1250:   /* Step 3: Set cone/support sizes for new points */
1251:   for (dep = 0; dep <= depth; ++dep) {
1252:     for (p = 0; p < numSplitPoints[dep]; ++p) {
1253:       const PetscInt  oldp   = splitPoints[dep][p];
1254:       const PetscInt  newp   = DMPlexShiftPoint_Internal(oldp, depth, depthShift) /*oldp + depthOffset[dep]*/;
1255:       const PetscInt  splitp = p + pMaxNew[dep];
1256:       const PetscInt *support;
1257:       DMPolytopeType  ct;
1258:       PetscInt        coneSize, supportSize, qf, qn, qp, e;

1260:       PetscCall(DMPlexGetConeSize(dm, oldp, &coneSize));
1261:       PetscCall(DMPlexSetConeSize(sdm, splitp, coneSize));
1262:       PetscCall(DMPlexGetSupportSize(dm, oldp, &supportSize));
1263:       PetscCall(DMPlexSetSupportSize(sdm, splitp, supportSize));
1264:       PetscCall(DMPlexGetCellType(dm, oldp, &ct));
1265:       PetscCall(DMPlexSetCellType(sdm, splitp, ct));
1266:       if (dep == depth - 1) {
1267:         const PetscInt hybcell = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1];

1269:         /* Add cohesive cells, they are prisms */
1270:         PetscCall(DMPlexSetConeSize(sdm, hybcell, 2 + coneSize));
1271:         switch (coneSize) {
1272:         case 2:
1273:           PetscCall(DMPlexSetCellType(sdm, hybcell, DM_POLYTOPE_SEG_PRISM_TENSOR));
1274:           break;
1275:         case 3:
1276:           PetscCall(DMPlexSetCellType(sdm, hybcell, DM_POLYTOPE_TRI_PRISM_TENSOR));
1277:           break;
1278:         case 4:
1279:           PetscCall(DMPlexSetCellType(sdm, hybcell, DM_POLYTOPE_QUAD_PRISM_TENSOR));
1280:           break;
1281:         }
1282:         /* Shared fault faces with only one support cell now have two with the cohesive cell */
1283:         /*   TODO Check thaat oldp has rootdegree == 1 */
1284:         if (supportSize == 1) {
1285:           const PetscInt *support;
1286:           PetscInt        val;

1288:           PetscCall(DMPlexGetSupport(dm, oldp, &support));
1289:           PetscCall(DMLabelGetValue(label, support[0], &val));
1290:           if (val < 0) PetscCall(DMPlexSetSupportSize(sdm, splitp, 2));
1291:           else PetscCall(DMPlexSetSupportSize(sdm, newp, 2));
1292:         }
1293:       } else if (dep == 0) {
1294:         const PetscInt hybedge = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1];

1296:         PetscCall(DMPlexGetSupport(dm, oldp, &support));
1297:         for (e = 0, qn = 0, qp = 0, qf = 0; e < supportSize; ++e) {
1298:           PetscInt val;

1300:           PetscCall(DMLabelGetValue(label, support[e], &val));
1301:           if (val == 1) ++qf;
1302:           if ((val == 1) || (val == (shift + 1))) ++qn;
1303:           if ((val == 1) || (val == -(shift + 1))) ++qp;
1304:         }
1305:         /* Split old vertex: Edges into original vertex and new cohesive edge */
1306:         PetscCall(DMPlexSetSupportSize(sdm, newp, qn + 1));
1307:         /* Split new vertex: Edges into split vertex and new cohesive edge */
1308:         PetscCall(DMPlexSetSupportSize(sdm, splitp, qp + 1));
1309:         /* Add hybrid edge */
1310:         PetscCall(DMPlexSetConeSize(sdm, hybedge, 2));
1311:         PetscCall(DMPlexSetSupportSize(sdm, hybedge, qf));
1312:         PetscCall(DMPlexSetCellType(sdm, hybedge, DM_POLYTOPE_POINT_PRISM_TENSOR));
1313:       } else if (dep == dim - 2) {
1314:         const PetscInt hybface = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1];

1316:         PetscCall(DMPlexGetSupport(dm, oldp, &support));
1317:         for (e = 0, qn = 0, qp = 0, qf = 0; e < supportSize; ++e) {
1318:           PetscInt val;

1320:           PetscCall(DMLabelGetValue(label, support[e], &val));
1321:           if (val == dim - 1) ++qf;
1322:           if ((val == dim - 1) || (val == (shift + dim - 1))) ++qn;
1323:           if ((val == dim - 1) || (val == -(shift + dim - 1))) ++qp;
1324:         }
1325:         /* Split old edge: Faces into original edge and cohesive face (positive side?) */
1326:         PetscCall(DMPlexSetSupportSize(sdm, newp, qn + 1));
1327:         /* Split new edge: Faces into split edge and cohesive face (negative side?) */
1328:         PetscCall(DMPlexSetSupportSize(sdm, splitp, qp + 1));
1329:         /* Add hybrid face */
1330:         PetscCall(DMPlexSetConeSize(sdm, hybface, 4));
1331:         PetscCall(DMPlexSetSupportSize(sdm, hybface, qf));
1332:         PetscCall(DMPlexSetCellType(sdm, hybface, DM_POLYTOPE_SEG_PRISM_TENSOR));
1333:       }
1334:     }
1335:   }
1336:   for (dep = 0; dep <= depth; ++dep) {
1337:     for (p = 0; p < numUnsplitPoints[dep]; ++p) {
1338:       const PetscInt  oldp = unsplitPoints[dep][p];
1339:       const PetscInt  newp = DMPlexShiftPoint_Internal(oldp, depth, depthShift) /*oldp + depthOffset[dep]*/;
1340:       const PetscInt *support;
1341:       PetscInt        coneSize, supportSize, qf, e, s;

1343:       PetscCall(DMPlexGetConeSize(dm, oldp, &coneSize));
1344:       PetscCall(DMPlexGetSupportSize(dm, oldp, &supportSize));
1345:       PetscCall(DMPlexGetSupport(dm, oldp, &support));
1346:       if (dep == 0) {
1347:         const PetscInt hybedge = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1] + numSplitPoints[dep];

1349:         /* Unsplit vertex: Edges into original vertex, split edges, and new cohesive edge twice */
1350:         for (s = 0, qf = 0; s < supportSize; ++s, ++qf) {
1351:           PetscCall(PetscFindInt(support[s], numSplitPoints[dep + 1], splitPoints[dep + 1], &e));
1352:           if (e >= 0) ++qf;
1353:         }
1354:         PetscCall(DMPlexSetSupportSize(sdm, newp, qf + 2));
1355:         /* Add hybrid edge */
1356:         PetscCall(DMPlexSetConeSize(sdm, hybedge, 2));
1357:         for (e = 0, qf = 0; e < supportSize; ++e) {
1358:           PetscInt val;

1360:           PetscCall(DMLabelGetValue(label, support[e], &val));
1361:           /* Split and unsplit edges produce hybrid faces */
1362:           if (val == 1) ++qf;
1363:           if (val == (shift2 + 1)) ++qf;
1364:         }
1365:         PetscCall(DMPlexSetSupportSize(sdm, hybedge, qf));
1366:         PetscCall(DMPlexSetCellType(sdm, hybedge, DM_POLYTOPE_POINT_PRISM_TENSOR));
1367:       } else if (dep == dim - 2) {
1368:         const PetscInt hybface = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1] + numSplitPoints[dep];
1369:         PetscInt       val;

1371:         for (e = 0, qf = 0; e < supportSize; ++e) {
1372:           PetscCall(DMLabelGetValue(label, support[e], &val));
1373:           if (val == dim - 1) qf += 2;
1374:           else ++qf;
1375:         }
1376:         /* Unsplit edge: Faces into original edge, split face, and cohesive face twice */
1377:         PetscCall(DMPlexSetSupportSize(sdm, newp, qf + 2));
1378:         /* Add hybrid face */
1379:         for (e = 0, qf = 0; e < supportSize; ++e) {
1380:           PetscCall(DMLabelGetValue(label, support[e], &val));
1381:           if (val == dim - 1) ++qf;
1382:         }
1383:         PetscCall(DMPlexSetConeSize(sdm, hybface, 4));
1384:         PetscCall(DMPlexSetSupportSize(sdm, hybface, qf));
1385:         PetscCall(DMPlexSetCellType(sdm, hybface, DM_POLYTOPE_SEG_PRISM_TENSOR));
1386:       }
1387:     }
1388:   }
1389:   /* Step 4: Setup split DM */
1390:   PetscCall(DMSetUp(sdm));
1391:   PetscCall(DMPlexShiftPoints_Internal(dm, depthShift, sdm));
1392:   PetscCall(DMPlexGetMaxSizes(sdm, &maxConeSizeNew, &maxSupportSizeNew));
1393:   PetscCall(PetscMalloc3(PetscMax(maxConeSize, maxConeSizeNew) * 3, &coneNew, PetscMax(maxConeSize, maxConeSizeNew) * 3, &coneONew, PetscMax(maxSupportSize, maxSupportSizeNew), &supportNew));
1394:   /* Step 6: Set cones and supports for new points */
1395:   for (dep = 0; dep <= depth; ++dep) {
1396:     for (p = 0; p < numSplitPoints[dep]; ++p) {
1397:       const PetscInt  oldp   = splitPoints[dep][p];
1398:       const PetscInt  newp   = DMPlexShiftPoint_Internal(oldp, depth, depthShift) /*oldp + depthOffset[dep]*/;
1399:       const PetscInt  splitp = p + pMaxNew[dep];
1400:       const PetscInt *cone, *support, *ornt;
1401:       DMPolytopeType  ct;
1402:       PetscInt        coneSize, supportSize, q, qf, qn, qp, v, e, s;

1404:       PetscCall(DMPlexGetCellType(dm, oldp, &ct));
1405:       PetscCall(DMPlexGetConeSize(dm, oldp, &coneSize));
1406:       PetscCall(DMPlexGetCone(dm, oldp, &cone));
1407:       PetscCall(DMPlexGetConeOrientation(dm, oldp, &ornt));
1408:       PetscCall(DMPlexGetSupportSize(dm, oldp, &supportSize));
1409:       PetscCall(DMPlexGetSupport(dm, oldp, &support));
1410:       if (dep == depth - 1) {
1411:         PetscBool       hasUnsplit = PETSC_FALSE;
1412:         const PetscInt  hybcell    = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1];
1413:         const PetscInt *supportF;

1415:         coneONew[0] = coneONew[1] = -1000;
1416:         /* Split face:       copy in old face to new face to start */
1417:         PetscCall(DMPlexGetSupport(sdm, newp, &supportF));
1418:         PetscCall(DMPlexSetSupport(sdm, splitp, supportF));
1419:         /* Split old face:   old vertices/edges in cone so no change */
1420:         /* Split new face:   new vertices/edges in cone */
1421:         for (q = 0; q < coneSize; ++q) {
1422:           PetscCall(PetscFindInt(cone[q], numSplitPoints[dep - 1], splitPoints[dep - 1], &v));
1423:           if (v < 0) {
1424:             PetscCall(PetscFindInt(cone[q], numUnsplitPoints[dep - 1], unsplitPoints[dep - 1], &v));
1425:             PetscCheck(v >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate point %" PetscInt_FMT " in split or unsplit points of depth %" PetscInt_FMT, cone[q], dep - 1);
1426:             coneNew[2 + q] = DMPlexShiftPoint_Internal(cone[q], depth, depthShift) /*cone[q] + depthOffset[dep-1]*/;
1427:             hasUnsplit     = PETSC_TRUE;
1428:           } else {
1429:             coneNew[2 + q] = v + pMaxNew[dep - 1];
1430:             if (dep > 1) {
1431:               const PetscInt *econe;
1432:               PetscInt        econeSize, r, vs, vu;

1434:               PetscCall(DMPlexGetConeSize(dm, cone[q], &econeSize));
1435:               PetscCall(DMPlexGetCone(dm, cone[q], &econe));
1436:               for (r = 0; r < econeSize; ++r) {
1437:                 PetscCall(PetscFindInt(econe[r], numSplitPoints[dep - 2], splitPoints[dep - 2], &vs));
1438:                 PetscCall(PetscFindInt(econe[r], numUnsplitPoints[dep - 2], unsplitPoints[dep - 2], &vu));
1439:                 if (vs >= 0) continue;
1440:                 PetscCheck(vu >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate point %" PetscInt_FMT " in split or unsplit points of depth %" PetscInt_FMT, econe[r], dep - 2);
1441:                 hasUnsplit = PETSC_TRUE;
1442:               }
1443:             }
1444:           }
1445:         }
1446:         PetscCall(DMPlexSetCone(sdm, splitp, &coneNew[2]));
1447:         PetscCall(DMPlexSetConeOrientation(sdm, splitp, ornt));
1448:         /* Face support */
1449:         PetscInt vals[2];

1451:         PetscCall(DMLabelGetValue(label, support[0], &vals[0]));
1452:         if (supportSize > 1) PetscCall(DMLabelGetValue(label, support[1], &vals[1]));
1453:         else vals[1] = -vals[0];
1454:         PetscCheck(vals[0] * vals[1] < 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid support labels %" PetscInt_FMT " %" PetscInt_FMT, vals[0], vals[1]);

1456:         for (s = 0; s < 2; ++s) {
1457:           if (s >= supportSize) {
1458:             if (vals[s] < 0) {
1459:               /* Ghost old face:   Replace negative side cell with cohesive cell */
1460:               PetscCall(DMPlexInsertSupport(sdm, newp, s, hybcell));
1461:             } else {
1462:               /* Ghost new face:   Replace positive side cell with cohesive cell */
1463:               PetscCall(DMPlexInsertSupport(sdm, splitp, s, hybcell));
1464:             }
1465:           } else {
1466:             if (vals[s] < 0) {
1467:               /* Split old face:   Replace negative side cell with cohesive cell */
1468:               PetscCall(DMPlexInsertSupport(sdm, newp, s, hybcell));
1469:             } else {
1470:               /* Split new face:   Replace positive side cell with cohesive cell */
1471:               PetscCall(DMPlexInsertSupport(sdm, splitp, s, hybcell));
1472:             }
1473:           }
1474:         }
1475:         /* Get orientation for cohesive face using the positive side cell */
1476:         {
1477:           const PetscInt *ncone, *nconeO;
1478:           PetscInt        nconeSize, nc, ocell;
1479:           PetscBool       flip = PETSC_FALSE;

1481:           if (supportSize > 1) {
1482:             ocell = vals[0] < 0 ? support[1] : support[0];
1483:           } else {
1484:             ocell = support[0];
1485:             flip  = vals[0] < 0 ? PETSC_TRUE : PETSC_FALSE;
1486:           }
1487:           PetscCall(DMPlexGetConeSize(dm, ocell, &nconeSize));
1488:           PetscCall(DMPlexGetCone(dm, ocell, &ncone));
1489:           PetscCall(DMPlexGetConeOrientation(dm, ocell, &nconeO));
1490:           for (nc = 0; nc < nconeSize; ++nc) {
1491:             if (ncone[nc] == oldp) {
1492:               coneONew[0] = flip ? -(nconeO[nc] + 1) : nconeO[nc];
1493:               break;
1494:             }
1495:           }
1496:           PetscCheck(nc < nconeSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate face %" PetscInt_FMT " in neighboring cell %" PetscInt_FMT, oldp, ocell);
1497:         }
1498:         /* Cohesive cell:    Old and new split face, then new cohesive faces */
1499:         {
1500:           const PetscInt No = DMPolytopeTypeGetNumArrangments(ct) / 2;
1501:           PetscCheck((coneONew[0] >= -No) && (coneONew[0] < No), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid %s orientation %" PetscInt_FMT, DMPolytopeTypes[ct], coneONew[0]);
1502:         }
1503:         const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, coneONew[0]);

1505:         coneNew[0]  = newp; /* Extracted negative side orientation above */
1506:         coneNew[1]  = splitp;
1507:         coneONew[1] = coneONew[0];
1508:         for (q = 0; q < coneSize; ++q) {
1509:           /* Hybrid faces must follow order from oriented end face */
1510:           const PetscInt qa = arr[q * 2 + 0];
1511:           const PetscInt qo = arr[q * 2 + 1];
1512:           DMPolytopeType ft = dep == 2 ? DM_POLYTOPE_SEGMENT : DM_POLYTOPE_POINT;

1514:           PetscCall(PetscFindInt(cone[qa], numSplitPoints[dep - 1], splitPoints[dep - 1], &v));
1515:           if (v < 0) {
1516:             PetscCall(PetscFindInt(cone[qa], numUnsplitPoints[dep - 1], unsplitPoints[dep - 1], &v));
1517:             coneNew[2 + q] = v + pMaxNew[dep] + numSplitPoints[dep] + numSplitPoints[dep - 1];
1518:           } else {
1519:             coneNew[2 + q] = v + pMaxNew[dep] + numSplitPoints[dep];
1520:           }
1521:           coneONew[2 + q] = DMPolytopeTypeComposeOrientation(ft, qo, ornt[qa]);
1522:         }
1523:         PetscCall(DMPlexSetCone(sdm, hybcell, coneNew));
1524:         PetscCall(DMPlexSetConeOrientation(sdm, hybcell, coneONew));
1525:         /* Label the hybrid cells on the boundary of the split */
1526:         if (hasUnsplit) PetscCall(DMLabelSetValue(label, -hybcell, dim));
1527:       } else if (dep == 0) {
1528:         const PetscInt hybedge = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1];

1530:         /* Split old vertex: Edges in old split faces and new cohesive edge */
1531:         for (e = 0, qn = 0; e < supportSize; ++e) {
1532:           PetscInt val;

1534:           PetscCall(DMLabelGetValue(label, support[e], &val));
1535:           if ((val == 1) || (val == (shift + 1))) supportNew[qn++] = DMPlexShiftPoint_Internal(support[e], depth, depthShift) /*support[e] + depthOffset[dep+1]*/;
1536:         }
1537:         supportNew[qn] = hybedge;
1538:         PetscCall(DMPlexSetSupport(sdm, newp, supportNew));
1539:         /* Split new vertex: Edges in new split faces and new cohesive edge */
1540:         for (e = 0, qp = 0; e < supportSize; ++e) {
1541:           PetscInt val, edge;

1543:           PetscCall(DMLabelGetValue(label, support[e], &val));
1544:           if (val == 1) {
1545:             PetscCall(PetscFindInt(support[e], numSplitPoints[dep + 1], splitPoints[dep + 1], &edge));
1546:             PetscCheck(edge >= 0, comm, PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " is not a split edge", support[e]);
1547:             supportNew[qp++] = edge + pMaxNew[dep + 1];
1548:           } else if (val == -(shift + 1)) {
1549:             supportNew[qp++] = DMPlexShiftPoint_Internal(support[e], depth, depthShift) /*support[e] + depthOffset[dep+1]*/;
1550:           }
1551:         }
1552:         supportNew[qp] = hybedge;
1553:         PetscCall(DMPlexSetSupport(sdm, splitp, supportNew));
1554:         /* Hybrid edge:    Old and new split vertex */
1555:         coneNew[0] = newp;
1556:         coneNew[1] = splitp;
1557:         PetscCall(DMPlexSetCone(sdm, hybedge, coneNew));
1558:         for (e = 0, qf = 0; e < supportSize; ++e) {
1559:           PetscInt val, edge;

1561:           PetscCall(DMLabelGetValue(label, support[e], &val));
1562:           if (val == 1) {
1563:             PetscCall(PetscFindInt(support[e], numSplitPoints[dep + 1], splitPoints[dep + 1], &edge));
1564:             PetscCheck(edge >= 0, comm, PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " is not a split edge", support[e]);
1565:             supportNew[qf++] = edge + pMaxNew[dep + 2] + numSplitPoints[dep + 2];
1566:           }
1567:         }
1568:         PetscCall(DMPlexSetSupport(sdm, hybedge, supportNew));
1569:       } else if (dep == dim - 2) {
1570:         const PetscInt hybface = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1];

1572:         /* Split old edge:   old vertices in cone so no change */
1573:         /* Split new edge:   new vertices in cone */
1574:         for (q = 0; q < coneSize; ++q) {
1575:           PetscCall(PetscFindInt(cone[q], numSplitPoints[dep - 1], splitPoints[dep - 1], &v));
1576:           if (v < 0) {
1577:             PetscCall(PetscFindInt(cone[q], numUnsplitPoints[dep - 1], unsplitPoints[dep - 1], &v));
1578:             PetscCheck(v >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate point %" PetscInt_FMT " in split or unsplit points of depth %" PetscInt_FMT, cone[q], dep - 1);
1579:             coneNew[q] = DMPlexShiftPoint_Internal(cone[q], depth, depthShift) /*cone[q] + depthOffset[dep-1]*/;
1580:           } else {
1581:             coneNew[q] = v + pMaxNew[dep - 1];
1582:           }
1583:         }
1584:         PetscCall(DMPlexSetCone(sdm, splitp, coneNew));
1585:         /* Split old edge: Faces in positive side cells and old split faces */
1586:         for (e = 0, q = 0; e < supportSize; ++e) {
1587:           PetscInt val;

1589:           PetscCall(DMLabelGetValue(label, support[e], &val));
1590:           if (val == dim - 1) {
1591:             supportNew[q++] = DMPlexShiftPoint_Internal(support[e], depth, depthShift) /*support[e] + depthOffset[dep+1]*/;
1592:           } else if (val == (shift + dim - 1)) {
1593:             supportNew[q++] = DMPlexShiftPoint_Internal(support[e], depth, depthShift) /*support[e] + depthOffset[dep+1]*/;
1594:           }
1595:         }
1596:         supportNew[q++] = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1];
1597:         PetscCall(DMPlexSetSupport(sdm, newp, supportNew));
1598:         /* Split new edge: Faces in negative side cells and new split faces */
1599:         for (e = 0, q = 0; e < supportSize; ++e) {
1600:           PetscInt val, face;

1602:           PetscCall(DMLabelGetValue(label, support[e], &val));
1603:           if (val == dim - 1) {
1604:             PetscCall(PetscFindInt(support[e], numSplitPoints[dep + 1], splitPoints[dep + 1], &face));
1605:             PetscCheck(face >= 0, comm, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " is not a split face", support[e]);
1606:             supportNew[q++] = face + pMaxNew[dep + 1];
1607:           } else if (val == -(shift + dim - 1)) {
1608:             supportNew[q++] = DMPlexShiftPoint_Internal(support[e], depth, depthShift) /*support[e] + depthOffset[dep+1]*/;
1609:           }
1610:         }
1611:         supportNew[q++] = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1];
1612:         PetscCall(DMPlexSetSupport(sdm, splitp, supportNew));
1613:         /* Hybrid face */
1614:         coneNew[0] = newp;
1615:         coneNew[1] = splitp;
1616:         for (v = 0; v < coneSize; ++v) {
1617:           PetscInt vertex;
1618:           PetscCall(PetscFindInt(cone[v], numSplitPoints[dep - 1], splitPoints[dep - 1], &vertex));
1619:           if (vertex < 0) {
1620:             PetscCall(PetscFindInt(cone[v], numUnsplitPoints[dep - 1], unsplitPoints[dep - 1], &vertex));
1621:             PetscCheck(vertex >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate point %" PetscInt_FMT " in split or unsplit points of depth %" PetscInt_FMT, cone[v], dep - 1);
1622:             coneNew[2 + v] = vertex + pMaxNew[dep] + numSplitPoints[dep] + numSplitPoints[dep - 1];
1623:           } else {
1624:             coneNew[2 + v] = vertex + pMaxNew[dep] + numSplitPoints[dep];
1625:           }
1626:         }
1627:         PetscCall(DMPlexSetCone(sdm, hybface, coneNew));
1628:         for (e = 0, qf = 0; e < supportSize; ++e) {
1629:           PetscInt val, face;

1631:           PetscCall(DMLabelGetValue(label, support[e], &val));
1632:           if (val == dim - 1) {
1633:             PetscCall(PetscFindInt(support[e], numSplitPoints[dep + 1], splitPoints[dep + 1], &face));
1634:             PetscCheck(face >= 0, comm, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " is not a split face", support[e]);
1635:             supportNew[qf++] = face + pMaxNew[dep + 2] + numSplitPoints[dep + 2];
1636:           }
1637:         }
1638:         PetscCall(DMPlexSetSupport(sdm, hybface, supportNew));
1639:       }
1640:     }
1641:   }
1642:   for (dep = 0; dep <= depth; ++dep) {
1643:     for (p = 0; p < numUnsplitPoints[dep]; ++p) {
1644:       const PetscInt  oldp = unsplitPoints[dep][p];
1645:       const PetscInt  newp = DMPlexShiftPoint_Internal(oldp, depth, depthShift) /*oldp + depthOffset[dep]*/;
1646:       const PetscInt *cone, *support;
1647:       PetscInt        coneSize, supportSize, supportSizeNew, q, qf, e, f, s;

1649:       PetscCall(DMPlexGetConeSize(dm, oldp, &coneSize));
1650:       PetscCall(DMPlexGetCone(dm, oldp, &cone));
1651:       PetscCall(DMPlexGetSupportSize(dm, oldp, &supportSize));
1652:       PetscCall(DMPlexGetSupport(dm, oldp, &support));
1653:       if (dep == 0) {
1654:         const PetscInt hybedge = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1] + numSplitPoints[dep];

1656:         /* Unsplit vertex */
1657:         PetscCall(DMPlexGetSupportSize(sdm, newp, &supportSizeNew));
1658:         for (s = 0, q = 0; s < supportSize; ++s) {
1659:           supportNew[q++] = DMPlexShiftPoint_Internal(support[s], depth, depthShift) /*support[s] + depthOffset[dep+1]*/;
1660:           PetscCall(PetscFindInt(support[s], numSplitPoints[dep + 1], splitPoints[dep + 1], &e));
1661:           if (e >= 0) supportNew[q++] = e + pMaxNew[dep + 1];
1662:         }
1663:         supportNew[q++] = hybedge;
1664:         supportNew[q++] = hybedge;
1665:         PetscCheck(q == supportSizeNew, comm, PETSC_ERR_ARG_WRONG, "Support size %" PetscInt_FMT " != %" PetscInt_FMT " for vertex %" PetscInt_FMT, q, supportSizeNew, newp);
1666:         PetscCall(DMPlexSetSupport(sdm, newp, supportNew));
1667:         /* Hybrid edge */
1668:         coneNew[0] = newp;
1669:         coneNew[1] = newp;
1670:         PetscCall(DMPlexSetCone(sdm, hybedge, coneNew));
1671:         for (e = 0, qf = 0; e < supportSize; ++e) {
1672:           PetscInt val, edge;

1674:           PetscCall(DMLabelGetValue(label, support[e], &val));
1675:           if (val == 1) {
1676:             PetscCall(PetscFindInt(support[e], numSplitPoints[dep + 1], splitPoints[dep + 1], &edge));
1677:             PetscCheck(edge >= 0, comm, PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " is not a split edge", support[e]);
1678:             supportNew[qf++] = edge + pMaxNew[dep + 2] + numSplitPoints[dep + 2];
1679:           } else if (val == (shift2 + 1)) {
1680:             PetscCall(PetscFindInt(support[e], numUnsplitPoints[dep + 1], unsplitPoints[dep + 1], &edge));
1681:             PetscCheck(edge >= 0, comm, PETSC_ERR_ARG_WRONG, "Edge %" PetscInt_FMT " is not a unsplit edge", support[e]);
1682:             supportNew[qf++] = edge + pMaxNew[dep + 2] + numSplitPoints[dep + 2] + numSplitPoints[dep + 1];
1683:           }
1684:         }
1685:         PetscCall(DMPlexSetSupport(sdm, hybedge, supportNew));
1686:       } else if (dep == dim - 2) {
1687:         const PetscInt hybface = p + pMaxNew[dep + 1] + numSplitPoints[dep + 1] + numSplitPoints[dep];

1689:         /* Unsplit edge: Faces into original edge, split face, and hybrid face twice */
1690:         for (f = 0, qf = 0; f < supportSize; ++f) {
1691:           PetscInt val, face;

1693:           PetscCall(DMLabelGetValue(label, support[f], &val));
1694:           if (val == dim - 1) {
1695:             PetscCall(PetscFindInt(support[f], numSplitPoints[dep + 1], splitPoints[dep + 1], &face));
1696:             PetscCheck(face >= 0, comm, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " is not a split face", support[f]);
1697:             supportNew[qf++] = DMPlexShiftPoint_Internal(support[f], depth, depthShift) /*support[f] + depthOffset[dep+1]*/;
1698:             supportNew[qf++] = face + pMaxNew[dep + 1];
1699:           } else {
1700:             supportNew[qf++] = DMPlexShiftPoint_Internal(support[f], depth, depthShift) /*support[f] + depthOffset[dep+1]*/;
1701:           }
1702:         }
1703:         supportNew[qf++] = hybface;
1704:         supportNew[qf++] = hybface;
1705:         PetscCall(DMPlexGetSupportSize(sdm, newp, &supportSizeNew));
1706:         PetscCheck(qf == supportSizeNew, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Support size for unsplit edge %" PetscInt_FMT " is %" PetscInt_FMT " != %" PetscInt_FMT, newp, qf, supportSizeNew);
1707:         PetscCall(DMPlexSetSupport(sdm, newp, supportNew));
1708:         /* Add hybrid face */
1709:         coneNew[0] = newp;
1710:         coneNew[1] = newp;
1711:         PetscCall(PetscFindInt(cone[0], numUnsplitPoints[dep - 1], unsplitPoints[dep - 1], &v));
1712:         PetscCheck(v >= 0, comm, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is not an unsplit vertex", cone[0]);
1713:         coneNew[2] = v + pMaxNew[dep] + numSplitPoints[dep] + numSplitPoints[dep - 1];
1714:         PetscCall(PetscFindInt(cone[1], numUnsplitPoints[dep - 1], unsplitPoints[dep - 1], &v));
1715:         PetscCheck(v >= 0, comm, PETSC_ERR_ARG_WRONG, "Vertex %" PetscInt_FMT " is not an unsplit vertex", cone[1]);
1716:         coneNew[3] = v + pMaxNew[dep] + numSplitPoints[dep] + numSplitPoints[dep - 1];
1717:         PetscCall(DMPlexSetCone(sdm, hybface, coneNew));
1718:         for (f = 0, qf = 0; f < supportSize; ++f) {
1719:           PetscInt val, face;

1721:           PetscCall(DMLabelGetValue(label, support[f], &val));
1722:           if (val == dim - 1) {
1723:             PetscCall(PetscFindInt(support[f], numSplitPoints[dep + 1], splitPoints[dep + 1], &face));
1724:             supportNew[qf++] = face + pMaxNew[dep + 2] + numSplitPoints[dep + 2];
1725:           }
1726:         }
1727:         PetscCall(DMPlexGetSupportSize(sdm, hybface, &supportSizeNew));
1728:         PetscCheck(qf == supportSizeNew, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Support size for hybrid face %" PetscInt_FMT " is %" PetscInt_FMT " != %" PetscInt_FMT, hybface, qf, supportSizeNew);
1729:         PetscCall(DMPlexSetSupport(sdm, hybface, supportNew));
1730:       }
1731:     }
1732:   }
1733:   /* Step 6b: Replace split points in negative side cones */
1734:   for (sp = 0; sp < numSP; ++sp) {
1735:     PetscInt        dep = values[sp];
1736:     IS              pIS;
1737:     PetscInt        numPoints;
1738:     const PetscInt *points;

1740:     if (dep >= 0) continue;
1741:     PetscCall(DMLabelGetStratumIS(label, dep, &pIS));
1742:     if (!pIS) continue;
1743:     dep = -dep - shift;
1744:     PetscCall(ISGetLocalSize(pIS, &numPoints));
1745:     PetscCall(ISGetIndices(pIS, &points));
1746:     for (p = 0; p < numPoints; ++p) {
1747:       const PetscInt  oldp = points[p];
1748:       const PetscInt  newp = DMPlexShiftPoint_Internal(oldp, depth, depthShift) /*depthOffset[dep] + oldp*/;
1749:       const PetscInt *cone;
1750:       PetscInt        coneSize, c;
1751:       /* PetscBool       replaced = PETSC_FALSE; */

1753:       /* Negative edge: replace split vertex */
1754:       /* Negative cell: replace split face */
1755:       PetscCall(DMPlexGetConeSize(sdm, newp, &coneSize));
1756:       PetscCall(DMPlexGetCone(sdm, newp, &cone));
1757:       for (c = 0; c < coneSize; ++c) {
1758:         const PetscInt coldp = DMPlexShiftPointInverse_Internal(cone[c], depth, depthShift);
1759:         PetscInt       csplitp, cp, val;

1761:         PetscCall(DMLabelGetValue(label, coldp, &val));
1762:         if (val == dep - 1) {
1763:           PetscCall(PetscFindInt(coldp, numSplitPoints[dep - 1], splitPoints[dep - 1], &cp));
1764:           PetscCheck(cp >= 0, comm, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT " is not a split point of dimension %" PetscInt_FMT, oldp, dep - 1);
1765:           csplitp = pMaxNew[dep - 1] + cp;
1766:           PetscCall(DMPlexInsertCone(sdm, newp, c, csplitp));
1767:           /* replaced = PETSC_TRUE; */
1768:         }
1769:       }
1770:       /* Cells with only a vertex or edge on the submesh have no replacement */
1771:       /* PetscCheck(replaced,comm, PETSC_ERR_ARG_WRONG, "The cone of point %d does not contain split points", oldp); */
1772:     }
1773:     PetscCall(ISRestoreIndices(pIS, &points));
1774:     PetscCall(ISDestroy(&pIS));
1775:   }
1776:   /* Step 7: Coordinates */
1777:   PetscCall(DMPlexShiftCoordinates_Internal(dm, depthShift, sdm));
1778:   PetscCall(DMGetCoordinateSection(sdm, &coordSection));
1779:   PetscCall(DMGetCoordinatesLocal(sdm, &coordinates));
1780:   PetscCall(VecGetArray(coordinates, &coords));
1781:   for (v = 0; v < (numSplitPoints ? numSplitPoints[0] : 0); ++v) {
1782:     const PetscInt newp   = DMPlexShiftPoint_Internal(splitPoints[0][v], depth, depthShift) /*depthOffset[0] + splitPoints[0][v]*/;
1783:     const PetscInt splitp = pMaxNew[0] + v;
1784:     PetscInt       dof, off, soff, d;

1786:     PetscCall(PetscSectionGetDof(coordSection, newp, &dof));
1787:     PetscCall(PetscSectionGetOffset(coordSection, newp, &off));
1788:     PetscCall(PetscSectionGetOffset(coordSection, splitp, &soff));
1789:     for (d = 0; d < dof; ++d) coords[soff + d] = coords[off + d];
1790:   }
1791:   PetscCall(VecRestoreArray(coordinates, &coords));
1792:   /* Step 8: SF, if I can figure this out we can split the mesh in parallel */
1793:   PetscCall(DMPlexShiftSF_Internal(dm, depthShift, sdm));
1794:   /*   TODO We need to associate the ghost points with the correct replica */
1795:   /* Step 9: Labels */
1796:   PetscCall(DMPlexShiftLabels_Internal(dm, depthShift, sdm));
1797:   PetscCall(DMPlexCreateVTKLabel_Internal(dm, PETSC_FALSE, sdm));
1798:   PetscCall(DMGetNumLabels(sdm, &numLabels));
1799:   for (dep = 0; dep <= depth; ++dep) {
1800:     for (p = 0; p < numSplitPoints[dep]; ++p) {
1801:       const PetscInt newp   = DMPlexShiftPoint_Internal(splitPoints[dep][p], depth, depthShift) /*depthOffset[dep] + splitPoints[dep][p]*/;
1802:       const PetscInt splitp = pMaxNew[dep] + p;
1803:       PetscInt       l;

1805:       if (splitLabel) {
1806:         const PetscInt val = 100 + dep;

1808:         PetscCall(DMLabelSetValue(splitLabel, newp, val));
1809:         PetscCall(DMLabelSetValue(splitLabel, splitp, -val));
1810:       }
1811:       for (l = 0; l < numLabels; ++l) {
1812:         DMLabel     mlabel;
1813:         const char *lname;
1814:         PetscInt    val;
1815:         PetscBool   isDepth;

1817:         PetscCall(DMGetLabelName(sdm, l, &lname));
1818:         PetscCall(PetscStrcmp(lname, "depth", &isDepth));
1819:         if (isDepth) continue;
1820:         PetscCall(DMGetLabel(sdm, lname, &mlabel));
1821:         PetscCall(DMLabelGetValue(mlabel, newp, &val));
1822:         if (val >= 0) PetscCall(DMLabelSetValue(mlabel, splitp, val));
1823:       }
1824:     }
1825:   }
1826:   for (sp = 0; sp < numSP; ++sp) {
1827:     const PetscInt dep = values[sp];

1829:     if ((dep < 0) || (dep > depth)) continue;
1830:     if (splitIS[dep]) PetscCall(ISRestoreIndices(splitIS[dep], &splitPoints[dep]));
1831:     PetscCall(ISDestroy(&splitIS[dep]));
1832:     if (unsplitIS[dep]) PetscCall(ISRestoreIndices(unsplitIS[dep], &unsplitPoints[dep]));
1833:     PetscCall(ISDestroy(&unsplitIS[dep]));
1834:   }
1835:   if (ghostIS) PetscCall(ISRestoreIndices(ghostIS, &ghostPoints));
1836:   PetscCall(ISDestroy(&ghostIS));
1837:   if (label) {
1838:     PetscCall(ISRestoreIndices(valueIS, &values));
1839:     PetscCall(ISDestroy(&valueIS));
1840:   }
1841:   for (d = 0; d <= depth; ++d) {
1842:     PetscCall(DMPlexGetDepthStratum(sdm, d, NULL, &pEnd));
1843:     pMaxNew[d] = pEnd - numHybridPoints[d] - numHybridPointsOld[d];
1844:   }
1845:   PetscCall(PetscFree3(coneNew, coneONew, supportNew));
1846:   PetscCall(PetscFree5(depthMax, depthEnd, depthShift, pMaxNew, numHybridPointsOld));
1847:   PetscCall(PetscFree7(splitIS, unsplitIS, numSplitPoints, numUnsplitPoints, numHybridPoints, splitPoints, unsplitPoints));
1848:   PetscFunctionReturn(PETSC_SUCCESS);
1849: }

1851: /*@C
1852:   DMPlexConstructCohesiveCells - Construct cohesive cells which split the face along an internal interface

1854:   Collective on dm

1856:   Input Parameters:
1857: + dm - The original DM
1858: - label - The label specifying the boundary faces (this could be auto-generated)

1860:   Output Parameters:
1861: + splitLabel - The label containing the split points, or NULL if no output is desired
1862: - dmSplit - The new DM

1864:   Level: developer

1866: .seealso: `DMCreate()`, `DMPlexLabelCohesiveComplete()`
1867: @*/
1868: PetscErrorCode DMPlexConstructCohesiveCells(DM dm, DMLabel label, DMLabel splitLabel, DM *dmSplit)
1869: {
1870:   DM       sdm;
1871:   PetscInt dim;

1873:   PetscFunctionBegin;
1876:   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), &sdm));
1877:   PetscCall(DMSetType(sdm, DMPLEX));
1878:   PetscCall(DMGetDimension(dm, &dim));
1879:   PetscCall(DMSetDimension(sdm, dim));
1880:   switch (dim) {
1881:   case 2:
1882:   case 3:
1883:     PetscCall(DMPlexConstructCohesiveCells_Internal(dm, label, splitLabel, sdm));
1884:     break;
1885:   default:
1886:     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct cohesive cells for dimension %" PetscInt_FMT, dim);
1887:   }
1888:   *dmSplit = sdm;
1889:   PetscFunctionReturn(PETSC_SUCCESS);
1890: }

1892: /* Returns the side of the surface for a given cell with a face on the surface */
1893: static PetscErrorCode GetSurfaceSide_Static(DM dm, DM subdm, PetscInt numSubpoints, const PetscInt *subpoints, PetscInt cell, PetscInt face, PetscBool *pos)
1894: {
1895:   const PetscInt *cone, *ornt;
1896:   PetscInt        dim, coneSize, c;

1898:   PetscFunctionBegin;
1899:   *pos = PETSC_TRUE;
1900:   PetscCall(DMGetDimension(dm, &dim));
1901:   PetscCall(DMPlexGetConeSize(dm, cell, &coneSize));
1902:   PetscCall(DMPlexGetCone(dm, cell, &cone));
1903:   PetscCall(DMPlexGetConeOrientation(dm, cell, &ornt));
1904:   for (c = 0; c < coneSize; ++c) {
1905:     if (cone[c] == face) {
1906:       PetscInt o = ornt[c];

1908:       if (subdm) {
1909:         const PetscInt *subcone, *subornt;
1910:         PetscInt        subpoint, subface, subconeSize, sc;

1912:         PetscCall(PetscFindInt(cell, numSubpoints, subpoints, &subpoint));
1913:         PetscCall(PetscFindInt(face, numSubpoints, subpoints, &subface));
1914:         PetscCall(DMPlexGetConeSize(subdm, subpoint, &subconeSize));
1915:         PetscCall(DMPlexGetCone(subdm, subpoint, &subcone));
1916:         PetscCall(DMPlexGetConeOrientation(subdm, subpoint, &subornt));
1917:         for (sc = 0; sc < subconeSize; ++sc) {
1918:           if (subcone[sc] == subface) {
1919:             o = subornt[0];
1920:             break;
1921:           }
1922:         }
1923:         PetscCheck(sc < subconeSize, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find subpoint %" PetscInt_FMT " (%" PetscInt_FMT ") in cone for subpoint %" PetscInt_FMT " (%" PetscInt_FMT ")", subface, face, subpoint, cell);
1924:       }
1925:       if (o >= 0) *pos = PETSC_TRUE;
1926:       else *pos = PETSC_FALSE;
1927:       break;
1928:     }
1929:   }
1930:   PetscCheck(c != coneSize, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cell %" PetscInt_FMT " in split face %" PetscInt_FMT " support does not have it in the cone", cell, face);
1931:   PetscFunctionReturn(PETSC_SUCCESS);
1932: }

1934: static PetscErrorCode CheckFaultEdge_Private(DM dm, DMLabel label)
1935: {
1936:   IS              facePosIS, faceNegIS, dimIS;
1937:   const PetscInt *points;
1938:   PetscInt        dim, numPoints, p, shift = 100, shift2 = 200;

1940:   PetscFunctionBegin;
1941:   PetscCall(DMGetDimension(dm, &dim));
1942:   /* If any faces touching the fault divide cells on either side, split them */
1943:   PetscCall(DMLabelGetStratumIS(label, shift + dim - 1, &facePosIS));
1944:   PetscCall(DMLabelGetStratumIS(label, -(shift + dim - 1), &faceNegIS));
1945:   if (!facePosIS || !faceNegIS) {
1946:     PetscCall(ISDestroy(&facePosIS));
1947:     PetscCall(ISDestroy(&faceNegIS));
1948:     PetscFunctionReturn(PETSC_SUCCESS);
1949:   }
1950:   PetscCall(ISExpand(facePosIS, faceNegIS, &dimIS));
1951:   PetscCall(ISDestroy(&facePosIS));
1952:   PetscCall(ISDestroy(&faceNegIS));
1953:   PetscCall(ISGetLocalSize(dimIS, &numPoints));
1954:   PetscCall(ISGetIndices(dimIS, &points));
1955:   for (p = 0; p < numPoints; ++p) {
1956:     const PetscInt  point = points[p];
1957:     const PetscInt *support;
1958:     PetscInt        supportSize, valA, valB;

1960:     PetscCall(DMPlexGetSupportSize(dm, point, &supportSize));
1961:     if (supportSize != 2) continue;
1962:     PetscCall(DMPlexGetSupport(dm, point, &support));
1963:     PetscCall(DMLabelGetValue(label, support[0], &valA));
1964:     PetscCall(DMLabelGetValue(label, support[1], &valB));
1965:     if ((valA == -1) || (valB == -1)) continue;
1966:     if (valA * valB > 0) continue;
1967:     /* Check that this face is not incident on only unsplit faces, meaning has at least one split face */
1968:     {
1969:       PetscInt *closure = NULL;
1970:       PetscBool split   = PETSC_FALSE;
1971:       PetscInt  closureSize, cl;

1973:       PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure));
1974:       for (cl = 0; cl < closureSize * 2; cl += 2) {
1975:         PetscCall(DMLabelGetValue(label, closure[cl], &valA));
1976:         if ((valA >= 0) && (valA <= dim)) {
1977:           split = PETSC_TRUE;
1978:           break;
1979:         }
1980:       }
1981:       PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure));
1982:       if (!split) continue;
1983:     }
1984:     /* Split the face */
1985:     PetscCall(DMLabelGetValue(label, point, &valA));
1986:     PetscCall(DMLabelClearValue(label, point, valA));
1987:     PetscCall(DMLabelSetValue(label, point, dim - 1));
1988:     /* Label its closure:
1989:       unmarked: label as unsplit
1990:       incident: relabel as split
1991:       split:    do nothing
1992:     */
1993:     {
1994:       PetscInt *closure = NULL;
1995:       PetscInt  closureSize, cl, dep;

1997:       PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure));
1998:       for (cl = 0; cl < closureSize * 2; cl += 2) {
1999:         PetscCall(DMLabelGetValue(label, closure[cl], &valA));
2000:         if (valA == -1) { /* Mark as unsplit */
2001:           PetscCall(DMPlexGetPointDepth(dm, closure[cl], &dep));
2002:           PetscCall(DMLabelSetValue(label, closure[cl], shift2 + dep));
2003:         } else if (((valA >= shift) && (valA < shift2)) || ((valA <= -shift) && (valA > -shift2))) {
2004:           PetscCall(DMPlexGetPointDepth(dm, closure[cl], &dep));
2005:           PetscCall(DMLabelClearValue(label, closure[cl], valA));
2006:           PetscCall(DMLabelSetValue(label, closure[cl], dep));
2007:         }
2008:       }
2009:       PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure));
2010:     }
2011:   }
2012:   PetscCall(ISRestoreIndices(dimIS, &points));
2013:   PetscCall(ISDestroy(&dimIS));
2014:   PetscFunctionReturn(PETSC_SUCCESS);
2015: }

2017: /*@
2018:   DMPlexLabelCohesiveComplete - Starting with a label marking points on an internal surface, we add all other mesh pieces
2019:   to complete the surface

2021:   Input Parameters:
2022: + dm     - The DM
2023: . label  - A DMLabel marking the surface
2024: . blabel - A DMLabel marking the vertices on the boundary which will not be duplicated, or NULL to find them automatically
2025: . bvalue - Value of DMLabel marking the vertices on the boundary
2026: . flip   - Flag to flip the submesh normal and replace points on the other side
2027: - subdm  - The subDM associated with the label, or NULL

2029:   Output Parameter:
2030: . label - A DMLabel marking all surface points

2032:   Note: The vertices in blabel are called "unsplit" in the terminology from hybrid cell creation.

2034:   Level: developer

2036: .seealso: `DMPlexConstructCohesiveCells()`, `DMPlexLabelComplete()`
2037: @*/
2038: PetscErrorCode DMPlexLabelCohesiveComplete(DM dm, DMLabel label, DMLabel blabel, PetscInt bvalue, PetscBool flip, DM subdm)
2039: {
2040:   DMLabel         depthLabel;
2041:   IS              dimIS, subpointIS = NULL;
2042:   const PetscInt *points, *subpoints;
2043:   const PetscInt  rev   = flip ? -1 : 1;
2044:   PetscInt        shift = 100, shift2 = 200, shift3 = 300, dim, depth, numPoints, numSubpoints, p, val;

2046:   PetscFunctionBegin;
2047:   PetscCall(DMPlexGetDepth(dm, &depth));
2048:   PetscCall(DMGetDimension(dm, &dim));
2049:   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
2050:   if (subdm) {
2051:     PetscCall(DMPlexGetSubpointIS(subdm, &subpointIS));
2052:     if (subpointIS) {
2053:       PetscCall(ISGetLocalSize(subpointIS, &numSubpoints));
2054:       PetscCall(ISGetIndices(subpointIS, &subpoints));
2055:     }
2056:   }
2057:   /* Mark cell on the fault, and its faces which touch the fault: cell orientation for face gives the side of the fault */
2058:   PetscCall(DMLabelGetStratumIS(label, dim - 1, &dimIS));
2059:   if (!dimIS) goto divide;
2060:   PetscCall(ISGetLocalSize(dimIS, &numPoints));
2061:   PetscCall(ISGetIndices(dimIS, &points));
2062:   for (p = 0; p < numPoints; ++p) { /* Loop over fault faces */
2063:     const PetscInt *support;
2064:     PetscInt        supportSize, s;

2066:     PetscCall(DMPlexGetSupportSize(dm, points[p], &supportSize));
2067: #if 0
2068:     if (supportSize != 2) {
2069:       const PetscInt *lp;
2070:       PetscInt        Nlp, pind;

2072:       /* Check that for a cell with a single support face, that face is in the SF */
2073:       /*   THis check only works for the remote side. We would need root side information */
2074:       PetscCall(PetscSFGetGraph(dm->sf, NULL, &Nlp, &lp, NULL));
2075:       PetscCall(PetscFindInt(points[p], Nlp, lp, &pind));
2076:       PetscCheck(pind >= 0,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Split face %" PetscInt_FMT " has %" PetscInt_FMT " != 2 supports, and the face is not shared with another process", points[p], supportSize);
2077:     }
2078: #endif
2079:     PetscCall(DMPlexGetSupport(dm, points[p], &support));
2080:     for (s = 0; s < supportSize; ++s) {
2081:       const PetscInt *cone;
2082:       PetscInt        coneSize, c;
2083:       PetscBool       pos;

2085:       PetscCall(GetSurfaceSide_Static(dm, subdm, numSubpoints, subpoints, support[s], points[p], &pos));
2086:       if (pos) PetscCall(DMLabelSetValue(label, support[s], rev * (shift + dim)));
2087:       else PetscCall(DMLabelSetValue(label, support[s], -rev * (shift + dim)));
2088:       if (rev < 0) pos = !pos ? PETSC_TRUE : PETSC_FALSE;
2089:       /* Put faces touching the fault in the label */
2090:       PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize));
2091:       PetscCall(DMPlexGetCone(dm, support[s], &cone));
2092:       for (c = 0; c < coneSize; ++c) {
2093:         const PetscInt point = cone[c];

2095:         PetscCall(DMLabelGetValue(label, point, &val));
2096:         if (val == -1) {
2097:           PetscInt *closure = NULL;
2098:           PetscInt  closureSize, cl;

2100:           PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure));
2101:           for (cl = 0; cl < closureSize * 2; cl += 2) {
2102:             const PetscInt clp  = closure[cl];
2103:             PetscInt       bval = -1;

2105:             PetscCall(DMLabelGetValue(label, clp, &val));
2106:             if (blabel) PetscCall(DMLabelGetValue(blabel, clp, &bval));
2107:             if ((val >= 0) && (val < dim - 1) && (bval < 0)) {
2108:               PetscCall(DMLabelSetValue(label, point, pos == PETSC_TRUE ? shift + dim - 1 : -(shift + dim - 1)));
2109:               break;
2110:             }
2111:           }
2112:           PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure));
2113:         }
2114:       }
2115:     }
2116:   }
2117:   PetscCall(ISRestoreIndices(dimIS, &points));
2118:   PetscCall(ISDestroy(&dimIS));
2119:   /* Mark boundary points as unsplit */
2120:   if (blabel) {
2121:     IS bdIS;

2123:     PetscCall(DMLabelGetStratumIS(blabel, bvalue, &bdIS));
2124:     PetscCall(ISGetLocalSize(bdIS, &numPoints));
2125:     PetscCall(ISGetIndices(bdIS, &points));
2126:     for (p = 0; p < numPoints; ++p) {
2127:       const PetscInt point = points[p];
2128:       PetscInt       val, bval;

2130:       PetscCall(DMLabelGetValue(blabel, point, &bval));
2131:       if (bval >= 0) {
2132:         PetscCall(DMLabelGetValue(label, point, &val));
2133:         if ((val < 0) || (val > dim)) {
2134:           /* This could be a point added from splitting a vertex on an adjacent fault, otherwise its just wrong */
2135:           PetscCall(DMLabelClearValue(blabel, point, bval));
2136:         }
2137:       }
2138:     }
2139:     for (p = 0; p < numPoints; ++p) {
2140:       const PetscInt point = points[p];
2141:       PetscInt       val, bval;

2143:       PetscCall(DMLabelGetValue(blabel, point, &bval));
2144:       if (bval >= 0) {
2145:         const PetscInt *cone, *support;
2146:         PetscInt        coneSize, supportSize, s, valA, valB, valE;

2148:         /* Mark as unsplit */
2149:         PetscCall(DMLabelGetValue(label, point, &val));
2150:         PetscCheck(val >= 0 && val <= dim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " has label value %" PetscInt_FMT ", should be part of the fault", point, val);
2151:         PetscCall(DMLabelClearValue(label, point, val));
2152:         PetscCall(DMLabelSetValue(label, point, shift2 + val));
2153:         /* Check for cross-edge
2154:              A cross-edge has endpoints which are both on the boundary of the surface, but the edge itself is not. */
2155:         if (val != 0) continue;
2156:         PetscCall(DMPlexGetSupport(dm, point, &support));
2157:         PetscCall(DMPlexGetSupportSize(dm, point, &supportSize));
2158:         for (s = 0; s < supportSize; ++s) {
2159:           PetscCall(DMPlexGetCone(dm, support[s], &cone));
2160:           PetscCall(DMPlexGetConeSize(dm, support[s], &coneSize));
2161:           PetscCheck(coneSize == 2, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Edge %" PetscInt_FMT " has %" PetscInt_FMT " vertices != 2", support[s], coneSize);
2162:           PetscCall(DMLabelGetValue(blabel, cone[0], &valA));
2163:           PetscCall(DMLabelGetValue(blabel, cone[1], &valB));
2164:           PetscCall(DMLabelGetValue(blabel, support[s], &valE));
2165:           if ((valE < 0) && (valA >= 0) && (valB >= 0) && (cone[0] != cone[1])) PetscCall(DMLabelSetValue(blabel, support[s], 2));
2166:         }
2167:       }
2168:     }
2169:     PetscCall(ISRestoreIndices(bdIS, &points));
2170:     PetscCall(ISDestroy(&bdIS));
2171:   }
2172:   /* Mark ghost fault cells */
2173:   {
2174:     PetscSF         sf;
2175:     const PetscInt *leaves;
2176:     PetscInt        Nl, l;

2178:     PetscCall(DMGetPointSF(dm, &sf));
2179:     PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &leaves, NULL));
2180:     PetscCall(DMLabelGetStratumIS(label, dim - 1, &dimIS));
2181:     if (!dimIS) goto divide;
2182:     PetscCall(ISGetLocalSize(dimIS, &numPoints));
2183:     PetscCall(ISGetIndices(dimIS, &points));
2184:     if (Nl > 0) {
2185:       for (p = 0; p < numPoints; ++p) {
2186:         const PetscInt point = points[p];
2187:         PetscInt       val;

2189:         PetscCall(PetscFindInt(point, Nl, leaves, &l));
2190:         if (l >= 0) {
2191:           PetscInt *closure = NULL;
2192:           PetscInt  closureSize, cl;

2194:           PetscCall(DMLabelGetValue(label, point, &val));
2195:           PetscCheck((val == dim - 1) || (val == shift2 + dim - 1), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " has label value %" PetscInt_FMT ", should be a fault face", point, val);
2196:           PetscCall(DMLabelClearValue(label, point, val));
2197:           PetscCall(DMLabelSetValue(label, point, shift3 + val));
2198:           PetscCall(DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure));
2199:           for (cl = 2; cl < closureSize * 2; cl += 2) {
2200:             const PetscInt clp = closure[cl];

2202:             PetscCall(DMLabelGetValue(label, clp, &val));
2203:             PetscCheck(val != -1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %" PetscInt_FMT " is missing from label, but is in the closure of a fault face", point);
2204:             PetscCall(DMLabelClearValue(label, clp, val));
2205:             PetscCall(DMLabelSetValue(label, clp, shift3 + val));
2206:           }
2207:           PetscCall(DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure));
2208:         }
2209:       }
2210:     }
2211:     PetscCall(ISRestoreIndices(dimIS, &points));
2212:     PetscCall(ISDestroy(&dimIS));
2213:   }
2214: divide:
2215:   if (subpointIS) PetscCall(ISRestoreIndices(subpointIS, &subpoints));
2216:   PetscCall(DMPlexLabelFaultHalo(dm, label));
2217:   PetscCall(CheckFaultEdge_Private(dm, label));
2218:   PetscFunctionReturn(PETSC_SUCCESS);
2219: }

2221: /* Check that no cell have all vertices on the fault */
2222: PetscErrorCode DMPlexCheckValidSubmesh_Private(DM dm, DMLabel label, DM subdm)
2223: {
2224:   IS              subpointIS;
2225:   const PetscInt *dmpoints;
2226:   PetscInt        defaultValue, cStart, cEnd, c, vStart, vEnd;

2228:   PetscFunctionBegin;
2229:   if (!label) PetscFunctionReturn(PETSC_SUCCESS);
2230:   PetscCall(DMLabelGetDefaultValue(label, &defaultValue));
2231:   PetscCall(DMPlexGetSubpointIS(subdm, &subpointIS));
2232:   if (!subpointIS) PetscFunctionReturn(PETSC_SUCCESS);
2233:   PetscCall(DMPlexGetHeightStratum(subdm, 0, &cStart, &cEnd));
2234:   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
2235:   PetscCall(ISGetIndices(subpointIS, &dmpoints));
2236:   for (c = cStart; c < cEnd; ++c) {
2237:     PetscBool invalidCell = PETSC_TRUE;
2238:     PetscInt *closure     = NULL;
2239:     PetscInt  closureSize, cl;

2241:     PetscCall(DMPlexGetTransitiveClosure(dm, dmpoints[c], PETSC_TRUE, &closureSize, &closure));
2242:     for (cl = 0; cl < closureSize * 2; cl += 2) {
2243:       PetscInt value = 0;

2245:       if ((closure[cl] < vStart) || (closure[cl] >= vEnd)) continue;
2246:       PetscCall(DMLabelGetValue(label, closure[cl], &value));
2247:       if (value == defaultValue) {
2248:         invalidCell = PETSC_FALSE;
2249:         break;
2250:       }
2251:     }
2252:     PetscCall(DMPlexRestoreTransitiveClosure(dm, dmpoints[c], PETSC_TRUE, &closureSize, &closure));
2253:     if (invalidCell) {
2254:       PetscCall(ISRestoreIndices(subpointIS, &dmpoints));
2255:       PetscCall(ISDestroy(&subpointIS));
2256:       PetscCall(DMDestroy(&subdm));
2257:       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Ambiguous submesh. Cell %" PetscInt_FMT " has all of its vertices on the submesh.", dmpoints[c]);
2258:     }
2259:   }
2260:   PetscCall(ISRestoreIndices(subpointIS, &dmpoints));
2261:   PetscFunctionReturn(PETSC_SUCCESS);
2262: }

2264: /*@
2265:   DMPlexCreateHybridMesh - Create a mesh with hybrid cells along an internal interface

2267:   Collective on dm

2269:   Input Parameters:
2270: + dm - The original DM
2271: . label - The label specifying the interface vertices
2272: . bdlabel - The optional label specifying the interface boundary vertices
2273: - bdvalue - Value of optional label specifying the interface boundary vertices

2275:   Output Parameters:
2276: + hybridLabel - The label fully marking the interface, or NULL if no output is desired
2277: . splitLabel - The label containing the split points, or NULL if no output is desired
2278: . dmInterface - The new interface DM, or NULL
2279: - dmHybrid - The new DM with cohesive cells

2281:   Note: The hybridLabel indicates what parts of the original mesh impinged on the division surface. For points
2282:   directly on the division surface, they are labeled with their dimension, so an edge 7 on the division surface would be
2283:   7 (1) in hybridLabel. For points that impinge from the positive side, they are labeled with 100+dim, so an edge 6 with
2284:   one vertex 3 on the surface would be 6 (101) and 3 (0) in hybridLabel. If an edge 9 from the negative side of the
2285:   surface also hits vertex 3, it would be 9 (-101) in hybridLabel.

2287:   The splitLabel indicates what points in the new hybrid mesh were the result of splitting points in the original
2288:   mesh. The label value is $\pm 100+dim$ for each point. For example, if two edges 10 and 14 in the hybrid resulting from
2289:   splitting an edge in the original mesh, you would have 10 (101) and 14 (-101) in the splitLabel.

2291:   The dmInterface is a DM built from the original division surface. It has a label which can be retrieved using
2292:   DMPlexGetSubpointMap() which maps each point back to the point in the surface of the original mesh.

2294:   Level: developer

2296: .seealso: `DMPlexConstructCohesiveCells()`, `DMPlexLabelCohesiveComplete()`, `DMPlexGetSubpointMap()`, `DMCreate()`
2297: @*/
2298: PetscErrorCode DMPlexCreateHybridMesh(DM dm, DMLabel label, DMLabel bdlabel, PetscInt bdvalue, DMLabel *hybridLabel, DMLabel *splitLabel, DM *dmInterface, DM *dmHybrid)
2299: {
2300:   DM       idm;
2301:   DMLabel  subpointMap, hlabel, slabel = NULL;
2302:   PetscInt dim;

2304:   PetscFunctionBegin;
2312:   PetscCall(DMGetDimension(dm, &dim));
2313:   PetscCall(DMPlexCreateSubmesh(dm, label, 1, PETSC_FALSE, &idm));
2314:   PetscCall(DMPlexCheckValidSubmesh_Private(dm, label, idm));
2315:   PetscCall(DMPlexOrient(idm));
2316:   PetscCall(DMPlexGetSubpointMap(idm, &subpointMap));
2317:   PetscCall(DMLabelDuplicate(subpointMap, &hlabel));
2318:   PetscCall(DMLabelClearStratum(hlabel, dim));
2319:   if (splitLabel) {
2320:     const char *name;
2321:     char        sname[PETSC_MAX_PATH_LEN];

2323:     PetscCall(PetscObjectGetName((PetscObject)hlabel, &name));
2324:     PetscCall(PetscStrncpy(sname, name, PETSC_MAX_PATH_LEN));
2325:     PetscCall(PetscStrcat(sname, " split"));
2326:     PetscCall(DMLabelCreate(PETSC_COMM_SELF, sname, &slabel));
2327:   }
2328:   PetscCall(DMPlexLabelCohesiveComplete(dm, hlabel, bdlabel, bdvalue, PETSC_FALSE, idm));
2329:   if (dmInterface) {
2330:     *dmInterface = idm;
2331:   } else PetscCall(DMDestroy(&idm));
2332:   PetscCall(DMPlexConstructCohesiveCells(dm, hlabel, slabel, dmHybrid));
2333:   PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_TRUE, *dmHybrid));
2334:   if (hybridLabel) *hybridLabel = hlabel;
2335:   else PetscCall(DMLabelDestroy(&hlabel));
2336:   if (splitLabel) *splitLabel = slabel;
2337:   {
2338:     DM      cdm;
2339:     DMLabel ctLabel;

2341:     /* We need to somehow share the celltype label with the coordinate dm */
2342:     PetscCall(DMGetCoordinateDM(*dmHybrid, &cdm));
2343:     PetscCall(DMPlexGetCellTypeLabel(*dmHybrid, &ctLabel));
2344:     PetscCall(DMSetLabel(cdm, ctLabel));
2345:   }
2346:   PetscFunctionReturn(PETSC_SUCCESS);
2347: }

2349: /* Here we need the explicit assumption that:

2351:      For any marked cell, the marked vertices constitute a single face
2352: */
2353: static PetscErrorCode DMPlexMarkSubmesh_Uninterpolated(DM dm, DMLabel vertexLabel, PetscInt value, DMLabel subpointMap, PetscInt *numFaces, PetscInt *nFV, DM subdm)
2354: {
2355:   IS              subvertexIS = NULL;
2356:   const PetscInt *subvertices;
2357:   PetscInt       *pStart, *pEnd, pSize;
2358:   PetscInt        depth, dim, d, numSubVerticesInitial = 0, v;

2360:   PetscFunctionBegin;
2361:   *numFaces = 0;
2362:   *nFV      = 0;
2363:   PetscCall(DMPlexGetDepth(dm, &depth));
2364:   PetscCall(DMGetDimension(dm, &dim));
2365:   pSize = PetscMax(depth, dim) + 1;
2366:   PetscCall(PetscMalloc2(pSize, &pStart, pSize, &pEnd));
2367:   for (d = 0; d <= depth; ++d) PetscCall(DMPlexGetSimplexOrBoxCells(dm, depth - d, &pStart[d], &pEnd[d]));
2368:   /* Loop over initial vertices and mark all faces in the collective star() */
2369:   if (vertexLabel) PetscCall(DMLabelGetStratumIS(vertexLabel, value, &subvertexIS));
2370:   if (subvertexIS) {
2371:     PetscCall(ISGetSize(subvertexIS, &numSubVerticesInitial));
2372:     PetscCall(ISGetIndices(subvertexIS, &subvertices));
2373:   }
2374:   for (v = 0; v < numSubVerticesInitial; ++v) {
2375:     const PetscInt vertex = subvertices[v];
2376:     PetscInt      *star   = NULL;
2377:     PetscInt       starSize, s, numCells = 0, c;

2379:     PetscCall(DMPlexGetTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star));
2380:     for (s = 0; s < starSize * 2; s += 2) {
2381:       const PetscInt point = star[s];
2382:       if ((point >= pStart[depth]) && (point < pEnd[depth])) star[numCells++] = point;
2383:     }
2384:     for (c = 0; c < numCells; ++c) {
2385:       const PetscInt cell    = star[c];
2386:       PetscInt      *closure = NULL;
2387:       PetscInt       closureSize, cl;
2388:       PetscInt       cellLoc, numCorners = 0, faceSize = 0;

2390:       PetscCall(DMLabelGetValue(subpointMap, cell, &cellLoc));
2391:       if (cellLoc == 2) continue;
2392:       PetscCheck(cellLoc < 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Cell %" PetscInt_FMT " has dimension %" PetscInt_FMT " in the surface label", cell, cellLoc);
2393:       PetscCall(DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure));
2394:       for (cl = 0; cl < closureSize * 2; cl += 2) {
2395:         const PetscInt point = closure[cl];
2396:         PetscInt       vertexLoc;

2398:         if ((point >= pStart[0]) && (point < pEnd[0])) {
2399:           ++numCorners;
2400:           PetscCall(DMLabelGetValue(vertexLabel, point, &vertexLoc));
2401:           if (vertexLoc == value) closure[faceSize++] = point;
2402:         }
2403:       }
2404:       if (!(*nFV)) PetscCall(DMPlexGetNumFaceVertices(dm, dim, numCorners, nFV));
2405:       PetscCheck(faceSize <= *nFV, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %" PetscInt_FMT " of an element on the surface", faceSize);
2406:       if (faceSize == *nFV) {
2407:         const PetscInt *cells = NULL;
2408:         PetscInt        numCells, nc;

2410:         ++(*numFaces);
2411:         for (cl = 0; cl < faceSize; ++cl) PetscCall(DMLabelSetValue(subpointMap, closure[cl], 0));
2412:         PetscCall(DMPlexGetJoin(dm, faceSize, closure, &numCells, &cells));
2413:         for (nc = 0; nc < numCells; ++nc) PetscCall(DMLabelSetValue(subpointMap, cells[nc], 2));
2414:         PetscCall(DMPlexRestoreJoin(dm, faceSize, closure, &numCells, &cells));
2415:       }
2416:       PetscCall(DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure));
2417:     }
2418:     PetscCall(DMPlexRestoreTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star));
2419:   }
2420:   if (subvertexIS) PetscCall(ISRestoreIndices(subvertexIS, &subvertices));
2421:   PetscCall(ISDestroy(&subvertexIS));
2422:   PetscCall(PetscFree2(pStart, pEnd));
2423:   PetscFunctionReturn(PETSC_SUCCESS);
2424: }

2426: static PetscErrorCode DMPlexMarkSubmesh_Interpolated(DM dm, DMLabel vertexLabel, PetscInt value, PetscBool markedFaces, DMLabel subpointMap, DM subdm)
2427: {
2428:   IS              subvertexIS = NULL;
2429:   const PetscInt *subvertices;
2430:   PetscInt       *pStart, *pEnd;
2431:   PetscInt        dim, d, numSubVerticesInitial = 0, v;

2433:   PetscFunctionBegin;
2434:   PetscCall(DMGetDimension(dm, &dim));
2435:   PetscCall(PetscMalloc2(dim + 1, &pStart, dim + 1, &pEnd));
2436:   for (d = 0; d <= dim; ++d) PetscCall(DMPlexGetSimplexOrBoxCells(dm, dim - d, &pStart[d], &pEnd[d]));
2437:   /* Loop over initial vertices and mark all faces in the collective star() */
2438:   if (vertexLabel) {
2439:     PetscCall(DMLabelGetStratumIS(vertexLabel, value, &subvertexIS));
2440:     if (subvertexIS) {
2441:       PetscCall(ISGetSize(subvertexIS, &numSubVerticesInitial));
2442:       PetscCall(ISGetIndices(subvertexIS, &subvertices));
2443:     }
2444:   }
2445:   for (v = 0; v < numSubVerticesInitial; ++v) {
2446:     const PetscInt vertex = subvertices[v];
2447:     PetscInt      *star   = NULL;
2448:     PetscInt       starSize, s, numFaces = 0, f;

2450:     PetscCall(DMPlexGetTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star));
2451:     for (s = 0; s < starSize * 2; s += 2) {
2452:       const PetscInt point = star[s];
2453:       PetscInt       faceLoc;

2455:       if ((point >= pStart[dim - 1]) && (point < pEnd[dim - 1])) {
2456:         if (markedFaces) {
2457:           PetscCall(DMLabelGetValue(vertexLabel, point, &faceLoc));
2458:           if (faceLoc < 0) continue;
2459:         }
2460:         star[numFaces++] = point;
2461:       }
2462:     }
2463:     for (f = 0; f < numFaces; ++f) {
2464:       const PetscInt face    = star[f];
2465:       PetscInt      *closure = NULL;
2466:       PetscInt       closureSize, c;
2467:       PetscInt       faceLoc;

2469:       PetscCall(DMLabelGetValue(subpointMap, face, &faceLoc));
2470:       if (faceLoc == dim - 1) continue;
2471:       PetscCheck(faceLoc < 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Face %" PetscInt_FMT " has dimension %" PetscInt_FMT " in the surface label", face, faceLoc);
2472:       PetscCall(DMPlexGetTransitiveClosure(dm, face, PETSC_TRUE, &closureSize, &closure));
2473:       for (c = 0; c < closureSize * 2; c += 2) {
2474:         const PetscInt point = closure[c];
2475:         PetscInt       vertexLoc;

2477:         if ((point >= pStart[0]) && (point < pEnd[0])) {
2478:           PetscCall(DMLabelGetValue(vertexLabel, point, &vertexLoc));
2479:           if (vertexLoc != value) break;
2480:         }
2481:       }
2482:       if (c == closureSize * 2) {
2483:         const PetscInt *support;
2484:         PetscInt        supportSize, s;

2486:         for (c = 0; c < closureSize * 2; c += 2) {
2487:           const PetscInt point = closure[c];

2489:           for (d = 0; d < dim; ++d) {
2490:             if ((point >= pStart[d]) && (point < pEnd[d])) {
2491:               PetscCall(DMLabelSetValue(subpointMap, point, d));
2492:               break;
2493:             }
2494:           }
2495:         }
2496:         PetscCall(DMPlexGetSupportSize(dm, face, &supportSize));
2497:         PetscCall(DMPlexGetSupport(dm, face, &support));
2498:         for (s = 0; s < supportSize; ++s) PetscCall(DMLabelSetValue(subpointMap, support[s], dim));
2499:       }
2500:       PetscCall(DMPlexRestoreTransitiveClosure(dm, face, PETSC_TRUE, &closureSize, &closure));
2501:     }
2502:     PetscCall(DMPlexRestoreTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star));
2503:   }
2504:   if (subvertexIS) PetscCall(ISRestoreIndices(subvertexIS, &subvertices));
2505:   PetscCall(ISDestroy(&subvertexIS));
2506:   PetscCall(PetscFree2(pStart, pEnd));
2507:   PetscFunctionReturn(PETSC_SUCCESS);
2508: }

2510: static PetscErrorCode DMPlexMarkCohesiveSubmesh_Uninterpolated(DM dm, PetscBool hasLagrange, const char labelname[], PetscInt value, DMLabel subpointMap, PetscInt *numFaces, PetscInt *nFV, PetscInt *subCells[], DM subdm)
2511: {
2512:   DMLabel         label = NULL;
2513:   const PetscInt *cone;
2514:   PetscInt        dim, cMax, cEnd, c, subc = 0, p, coneSize = -1;

2516:   PetscFunctionBegin;
2517:   *numFaces = 0;
2518:   *nFV      = 0;
2519:   if (labelname) PetscCall(DMGetLabel(dm, labelname, &label));
2520:   *subCells = NULL;
2521:   PetscCall(DMGetDimension(dm, &dim));
2522:   PetscCall(DMPlexGetTensorPrismBounds_Internal(dm, dim, &cMax, &cEnd));
2523:   if (cMax < 0) PetscFunctionReturn(PETSC_SUCCESS);
2524:   if (label) {
2525:     for (c = cMax; c < cEnd; ++c) {
2526:       PetscInt val;

2528:       PetscCall(DMLabelGetValue(label, c, &val));
2529:       if (val == value) {
2530:         ++(*numFaces);
2531:         PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
2532:       }
2533:     }
2534:   } else {
2535:     *numFaces = cEnd - cMax;
2536:     PetscCall(DMPlexGetConeSize(dm, cMax, &coneSize));
2537:   }
2538:   PetscCall(PetscMalloc1(*numFaces * 2, subCells));
2539:   if (!(*numFaces)) PetscFunctionReturn(PETSC_SUCCESS);
2540:   *nFV = hasLagrange ? coneSize / 3 : coneSize / 2;
2541:   for (c = cMax; c < cEnd; ++c) {
2542:     const PetscInt *cells;
2543:     PetscInt        numCells;

2545:     if (label) {
2546:       PetscInt val;

2548:       PetscCall(DMLabelGetValue(label, c, &val));
2549:       if (val != value) continue;
2550:     }
2551:     PetscCall(DMPlexGetCone(dm, c, &cone));
2552:     for (p = 0; p < *nFV; ++p) PetscCall(DMLabelSetValue(subpointMap, cone[p], 0));
2553:     /* Negative face */
2554:     PetscCall(DMPlexGetJoin(dm, *nFV, cone, &numCells, &cells));
2555:     /* Not true in parallel
2556:     PetscCheck(numCells == 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cohesive cells should separate two cells"); */
2557:     for (p = 0; p < numCells; ++p) {
2558:       PetscCall(DMLabelSetValue(subpointMap, cells[p], 2));
2559:       (*subCells)[subc++] = cells[p];
2560:     }
2561:     PetscCall(DMPlexRestoreJoin(dm, *nFV, cone, &numCells, &cells));
2562:     /* Positive face is not included */
2563:   }
2564:   PetscFunctionReturn(PETSC_SUCCESS);
2565: }

2567: static PetscErrorCode DMPlexMarkCohesiveSubmesh_Interpolated(DM dm, DMLabel label, PetscInt value, DMLabel subpointMap, DM subdm)
2568: {
2569:   PetscInt *pStart, *pEnd;
2570:   PetscInt  dim, cMax, cEnd, c, d;

2572:   PetscFunctionBegin;
2573:   PetscCall(DMGetDimension(dm, &dim));
2574:   PetscCall(DMPlexGetTensorPrismBounds_Internal(dm, dim, &cMax, &cEnd));
2575:   if (cMax < 0) PetscFunctionReturn(PETSC_SUCCESS);
2576:   PetscCall(PetscMalloc2(dim + 1, &pStart, dim + 1, &pEnd));
2577:   for (d = 0; d <= dim; ++d) PetscCall(DMPlexGetDepthStratum(dm, d, &pStart[d], &pEnd[d]));
2578:   for (c = cMax; c < cEnd; ++c) {
2579:     const PetscInt *cone;
2580:     PetscInt       *closure = NULL;
2581:     PetscInt        fconeSize, coneSize, closureSize, cl, val;

2583:     if (label) {
2584:       PetscCall(DMLabelGetValue(label, c, &val));
2585:       if (val != value) continue;
2586:     }
2587:     PetscCall(DMPlexGetConeSize(dm, c, &coneSize));
2588:     PetscCall(DMPlexGetCone(dm, c, &cone));
2589:     PetscCall(DMPlexGetConeSize(dm, cone[0], &fconeSize));
2590:     PetscCheck(coneSize == (fconeSize ? fconeSize : 1) + 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cohesive cells should separate two cells");
2591:     /* Negative face */
2592:     PetscCall(DMPlexGetTransitiveClosure(dm, cone[0], PETSC_TRUE, &closureSize, &closure));
2593:     for (cl = 0; cl < closureSize * 2; cl += 2) {
2594:       const PetscInt point = closure[cl];

2596:       for (d = 0; d <= dim; ++d) {
2597:         if ((point >= pStart[d]) && (point < pEnd[d])) {
2598:           PetscCall(DMLabelSetValue(subpointMap, point, d));
2599:           break;
2600:         }
2601:       }
2602:     }
2603:     PetscCall(DMPlexRestoreTransitiveClosure(dm, cone[0], PETSC_TRUE, &closureSize, &closure));
2604:     /* Cells -- positive face is not included */
2605:     for (cl = 0; cl < 1; ++cl) {
2606:       const PetscInt *support;
2607:       PetscInt        supportSize, s;

2609:       PetscCall(DMPlexGetSupportSize(dm, cone[cl], &supportSize));
2610:       /* PetscCheck(supportSize == 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cohesive faces should separate two cells"); */
2611:       PetscCall(DMPlexGetSupport(dm, cone[cl], &support));
2612:       for (s = 0; s < supportSize; ++s) PetscCall(DMLabelSetValue(subpointMap, support[s], dim));
2613:     }
2614:   }
2615:   PetscCall(PetscFree2(pStart, pEnd));
2616:   PetscFunctionReturn(PETSC_SUCCESS);
2617: }

2619: static PetscErrorCode DMPlexGetFaceOrientation(DM dm, PetscInt cell, PetscInt numCorners, PetscInt indices[], PetscInt oppositeVertex, PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
2620: {
2621:   MPI_Comm       comm;
2622:   PetscBool      posOrient = PETSC_FALSE;
2623:   const PetscInt debug     = 0;
2624:   PetscInt       cellDim, faceSize, f;

2626:   PetscFunctionBegin;
2627:   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
2628:   PetscCall(DMGetDimension(dm, &cellDim));
2629:   if (debug) PetscCall(PetscPrintf(comm, "cellDim: %" PetscInt_FMT " numCorners: %" PetscInt_FMT "\n", cellDim, numCorners));

2631:   if (cellDim == 1 && numCorners == 2) {
2632:     /* Triangle */
2633:     faceSize  = numCorners - 1;
2634:     posOrient = !(oppositeVertex % 2) ? PETSC_TRUE : PETSC_FALSE;
2635:   } else if (cellDim == 2 && numCorners == 3) {
2636:     /* Triangle */
2637:     faceSize  = numCorners - 1;
2638:     posOrient = !(oppositeVertex % 2) ? PETSC_TRUE : PETSC_FALSE;
2639:   } else if (cellDim == 3 && numCorners == 4) {
2640:     /* Tetrahedron */
2641:     faceSize  = numCorners - 1;
2642:     posOrient = (oppositeVertex % 2) ? PETSC_TRUE : PETSC_FALSE;
2643:   } else if (cellDim == 1 && numCorners == 3) {
2644:     /* Quadratic line */
2645:     faceSize  = 1;
2646:     posOrient = PETSC_TRUE;
2647:   } else if (cellDim == 2 && numCorners == 4) {
2648:     /* Quads */
2649:     faceSize = 2;
2650:     if ((indices[1] > indices[0]) && (indices[1] - indices[0] == 1)) {
2651:       posOrient = PETSC_TRUE;
2652:     } else if ((indices[0] == 3) && (indices[1] == 0)) {
2653:       posOrient = PETSC_TRUE;
2654:     } else {
2655:       if (((indices[0] > indices[1]) && (indices[0] - indices[1] == 1)) || ((indices[0] == 0) && (indices[1] == 3))) {
2656:         posOrient = PETSC_FALSE;
2657:       } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossedge");
2658:     }
2659:   } else if (cellDim == 2 && numCorners == 6) {
2660:     /* Quadratic triangle (I hate this) */
2661:     /* Edges are determined by the first 2 vertices (corners of edges) */
2662:     const PetscInt faceSizeTri = 3;
2663:     PetscInt       sortedIndices[3], i, iFace;
2664:     PetscBool      found                    = PETSC_FALSE;
2665:     PetscInt       faceVerticesTriSorted[9] = {
2666:       0, 3, 4, /* bottom */
2667:       1, 4, 5, /* right */
2668:       2, 3, 5, /* left */
2669:     };
2670:     PetscInt faceVerticesTri[9] = {
2671:       0, 3, 4, /* bottom */
2672:       1, 4, 5, /* right */
2673:       2, 5, 3, /* left */
2674:     };

2676:     for (i = 0; i < faceSizeTri; ++i) sortedIndices[i] = indices[i];
2677:     PetscCall(PetscSortInt(faceSizeTri, sortedIndices));
2678:     for (iFace = 0; iFace < 3; ++iFace) {
2679:       const PetscInt ii = iFace * faceSizeTri;
2680:       PetscInt       fVertex, cVertex;

2682:       if ((sortedIndices[0] == faceVerticesTriSorted[ii + 0]) && (sortedIndices[1] == faceVerticesTriSorted[ii + 1])) {
2683:         for (fVertex = 0; fVertex < faceSizeTri; ++fVertex) {
2684:           for (cVertex = 0; cVertex < faceSizeTri; ++cVertex) {
2685:             if (indices[cVertex] == faceVerticesTri[ii + fVertex]) {
2686:               faceVertices[fVertex] = origVertices[cVertex];
2687:               break;
2688:             }
2689:           }
2690:         }
2691:         found = PETSC_TRUE;
2692:         break;
2693:       }
2694:     }
2695:     PetscCheck(found, comm, PETSC_ERR_ARG_WRONG, "Invalid tri crossface");
2696:     if (posOriented) *posOriented = PETSC_TRUE;
2697:     PetscFunctionReturn(PETSC_SUCCESS);
2698:   } else if (cellDim == 2 && numCorners == 9) {
2699:     /* Quadratic quad (I hate this) */
2700:     /* Edges are determined by the first 2 vertices (corners of edges) */
2701:     const PetscInt faceSizeQuad = 3;
2702:     PetscInt       sortedIndices[3], i, iFace;
2703:     PetscBool      found                      = PETSC_FALSE;
2704:     PetscInt       faceVerticesQuadSorted[12] = {
2705:       0, 1, 4, /* bottom */
2706:       1, 2, 5, /* right */
2707:       2, 3, 6, /* top */
2708:       0, 3, 7, /* left */
2709:     };
2710:     PetscInt faceVerticesQuad[12] = {
2711:       0, 1, 4, /* bottom */
2712:       1, 2, 5, /* right */
2713:       2, 3, 6, /* top */
2714:       3, 0, 7, /* left */
2715:     };

2717:     for (i = 0; i < faceSizeQuad; ++i) sortedIndices[i] = indices[i];
2718:     PetscCall(PetscSortInt(faceSizeQuad, sortedIndices));
2719:     for (iFace = 0; iFace < 4; ++iFace) {
2720:       const PetscInt ii = iFace * faceSizeQuad;
2721:       PetscInt       fVertex, cVertex;

2723:       if ((sortedIndices[0] == faceVerticesQuadSorted[ii + 0]) && (sortedIndices[1] == faceVerticesQuadSorted[ii + 1])) {
2724:         for (fVertex = 0; fVertex < faceSizeQuad; ++fVertex) {
2725:           for (cVertex = 0; cVertex < faceSizeQuad; ++cVertex) {
2726:             if (indices[cVertex] == faceVerticesQuad[ii + fVertex]) {
2727:               faceVertices[fVertex] = origVertices[cVertex];
2728:               break;
2729:             }
2730:           }
2731:         }
2732:         found = PETSC_TRUE;
2733:         break;
2734:       }
2735:     }
2736:     PetscCheck(found, comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossface");
2737:     if (posOriented) *posOriented = PETSC_TRUE;
2738:     PetscFunctionReturn(PETSC_SUCCESS);
2739:   } else if (cellDim == 3 && numCorners == 8) {
2740:     /* Hexes
2741:        A hex is two oriented quads with the normal of the first
2742:        pointing up at the second.

2744:           7---6
2745:          /|  /|
2746:         4---5 |
2747:         | 1-|-2
2748:         |/  |/
2749:         0---3

2751:         Faces are determined by the first 4 vertices (corners of faces) */
2752:     const PetscInt faceSizeHex = 4;
2753:     PetscInt       sortedIndices[4], i, iFace;
2754:     PetscBool      found                     = PETSC_FALSE;
2755:     PetscInt       faceVerticesHexSorted[24] = {
2756:       0, 1, 2, 3, /* bottom */
2757:       4, 5, 6, 7, /* top */
2758:       0, 3, 4, 5, /* front */
2759:       2, 3, 5, 6, /* right */
2760:       1, 2, 6, 7, /* back */
2761:       0, 1, 4, 7, /* left */
2762:     };
2763:     PetscInt faceVerticesHex[24] = {
2764:       1, 2, 3, 0, /* bottom */
2765:       4, 5, 6, 7, /* top */
2766:       0, 3, 5, 4, /* front */
2767:       3, 2, 6, 5, /* right */
2768:       2, 1, 7, 6, /* back */
2769:       1, 0, 4, 7, /* left */
2770:     };

2772:     for (i = 0; i < faceSizeHex; ++i) sortedIndices[i] = indices[i];
2773:     PetscCall(PetscSortInt(faceSizeHex, sortedIndices));
2774:     for (iFace = 0; iFace < 6; ++iFace) {
2775:       const PetscInt ii = iFace * faceSizeHex;
2776:       PetscInt       fVertex, cVertex;

2778:       if ((sortedIndices[0] == faceVerticesHexSorted[ii + 0]) && (sortedIndices[1] == faceVerticesHexSorted[ii + 1]) && (sortedIndices[2] == faceVerticesHexSorted[ii + 2]) && (sortedIndices[3] == faceVerticesHexSorted[ii + 3])) {
2779:         for (fVertex = 0; fVertex < faceSizeHex; ++fVertex) {
2780:           for (cVertex = 0; cVertex < faceSizeHex; ++cVertex) {
2781:             if (indices[cVertex] == faceVerticesHex[ii + fVertex]) {
2782:               faceVertices[fVertex] = origVertices[cVertex];
2783:               break;
2784:             }
2785:           }
2786:         }
2787:         found = PETSC_TRUE;
2788:         break;
2789:       }
2790:     }
2791:     PetscCheck(found, comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
2792:     if (posOriented) *posOriented = PETSC_TRUE;
2793:     PetscFunctionReturn(PETSC_SUCCESS);
2794:   } else if (cellDim == 3 && numCorners == 10) {
2795:     /* Quadratic tet */
2796:     /* Faces are determined by the first 3 vertices (corners of faces) */
2797:     const PetscInt faceSizeTet = 6;
2798:     PetscInt       sortedIndices[6], i, iFace;
2799:     PetscBool      found                     = PETSC_FALSE;
2800:     PetscInt       faceVerticesTetSorted[24] = {
2801:       0, 1, 2, 6, 7, 8, /* bottom */
2802:       0, 3, 4, 6, 7, 9, /* front */
2803:       1, 4, 5, 7, 8, 9, /* right */
2804:       2, 3, 5, 6, 8, 9, /* left */
2805:     };
2806:     PetscInt faceVerticesTet[24] = {
2807:       0, 1, 2, 6, 7, 8, /* bottom */
2808:       0, 4, 3, 6, 7, 9, /* front */
2809:       1, 5, 4, 7, 8, 9, /* right */
2810:       2, 3, 5, 8, 6, 9, /* left */
2811:     };

2813:     for (i = 0; i < faceSizeTet; ++i) sortedIndices[i] = indices[i];
2814:     PetscCall(PetscSortInt(faceSizeTet, sortedIndices));
2815:     for (iFace = 0; iFace < 4; ++iFace) {
2816:       const PetscInt ii = iFace * faceSizeTet;
2817:       PetscInt       fVertex, cVertex;

2819:       if ((sortedIndices[0] == faceVerticesTetSorted[ii + 0]) && (sortedIndices[1] == faceVerticesTetSorted[ii + 1]) && (sortedIndices[2] == faceVerticesTetSorted[ii + 2]) && (sortedIndices[3] == faceVerticesTetSorted[ii + 3])) {
2820:         for (fVertex = 0; fVertex < faceSizeTet; ++fVertex) {
2821:           for (cVertex = 0; cVertex < faceSizeTet; ++cVertex) {
2822:             if (indices[cVertex] == faceVerticesTet[ii + fVertex]) {
2823:               faceVertices[fVertex] = origVertices[cVertex];
2824:               break;
2825:             }
2826:           }
2827:         }
2828:         found = PETSC_TRUE;
2829:         break;
2830:       }
2831:     }
2832:     PetscCheck(found, comm, PETSC_ERR_ARG_WRONG, "Invalid tet crossface");
2833:     if (posOriented) *posOriented = PETSC_TRUE;
2834:     PetscFunctionReturn(PETSC_SUCCESS);
2835:   } else if (cellDim == 3 && numCorners == 27) {
2836:     /* Quadratic hexes (I hate this)
2837:        A hex is two oriented quads with the normal of the first
2838:        pointing up at the second.

2840:          7---6
2841:         /|  /|
2842:        4---5 |
2843:        | 3-|-2
2844:        |/  |/
2845:        0---1

2847:        Faces are determined by the first 4 vertices (corners of faces) */
2848:     const PetscInt faceSizeQuadHex = 9;
2849:     PetscInt       sortedIndices[9], i, iFace;
2850:     PetscBool      found                         = PETSC_FALSE;
2851:     PetscInt       faceVerticesQuadHexSorted[54] = {
2852:       0, 1, 2, 3, 8,  9,  10, 11, 24, /* bottom */
2853:       4, 5, 6, 7, 12, 13, 14, 15, 25, /* top */
2854:       0, 1, 4, 5, 8,  12, 16, 17, 22, /* front */
2855:       1, 2, 5, 6, 9,  13, 17, 18, 21, /* right */
2856:       2, 3, 6, 7, 10, 14, 18, 19, 23, /* back */
2857:       0, 3, 4, 7, 11, 15, 16, 19, 20, /* left */
2858:     };
2859:     PetscInt faceVerticesQuadHex[54] = {
2860:       3, 2, 1, 0, 10, 9,  8,  11, 24, /* bottom */
2861:       4, 5, 6, 7, 12, 13, 14, 15, 25, /* top */
2862:       0, 1, 5, 4, 8,  17, 12, 16, 22, /* front */
2863:       1, 2, 6, 5, 9,  18, 13, 17, 21, /* right */
2864:       2, 3, 7, 6, 10, 19, 14, 18, 23, /* back */
2865:       3, 0, 4, 7, 11, 16, 15, 19, 20  /* left */
2866:     };

2868:     for (i = 0; i < faceSizeQuadHex; ++i) sortedIndices[i] = indices[i];
2869:     PetscCall(PetscSortInt(faceSizeQuadHex, sortedIndices));
2870:     for (iFace = 0; iFace < 6; ++iFace) {
2871:       const PetscInt ii = iFace * faceSizeQuadHex;
2872:       PetscInt       fVertex, cVertex;

2874:       if ((sortedIndices[0] == faceVerticesQuadHexSorted[ii + 0]) && (sortedIndices[1] == faceVerticesQuadHexSorted[ii + 1]) && (sortedIndices[2] == faceVerticesQuadHexSorted[ii + 2]) && (sortedIndices[3] == faceVerticesQuadHexSorted[ii + 3])) {
2875:         for (fVertex = 0; fVertex < faceSizeQuadHex; ++fVertex) {
2876:           for (cVertex = 0; cVertex < faceSizeQuadHex; ++cVertex) {
2877:             if (indices[cVertex] == faceVerticesQuadHex[ii + fVertex]) {
2878:               faceVertices[fVertex] = origVertices[cVertex];
2879:               break;
2880:             }
2881:           }
2882:         }
2883:         found = PETSC_TRUE;
2884:         break;
2885:       }
2886:     }
2887:     PetscCheck(found, comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
2888:     if (posOriented) *posOriented = PETSC_TRUE;
2889:     PetscFunctionReturn(PETSC_SUCCESS);
2890:   } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Unknown cell type for faceOrientation().");
2891:   if (!posOrient) {
2892:     if (debug) PetscCall(PetscPrintf(comm, "  Reversing initial face orientation\n"));
2893:     for (f = 0; f < faceSize; ++f) faceVertices[f] = origVertices[faceSize - 1 - f];
2894:   } else {
2895:     if (debug) PetscCall(PetscPrintf(comm, "  Keeping initial face orientation\n"));
2896:     for (f = 0; f < faceSize; ++f) faceVertices[f] = origVertices[f];
2897:   }
2898:   if (posOriented) *posOriented = posOrient;
2899:   PetscFunctionReturn(PETSC_SUCCESS);
2900: }

2902: /*@
2903:   DMPlexGetOrientedFace - Given a cell and a face, as a set of vertices, return the oriented face, as a set of vertices,
2904:   in faceVertices. The orientation is such that the face normal points out of the cell

2906:   Not collective

2908:   Input Parameters:
2909: + dm           - The original mesh
2910: . cell         - The cell mesh point
2911: . faceSize     - The number of vertices on the face
2912: . face         - The face vertices
2913: . numCorners   - The number of vertices on the cell
2914: . indices      - Local numbering of face vertices in cell cone
2915: - origVertices - Original face vertices

2917:   Output Parameters:
2918: + faceVertices - The face vertices properly oriented
2919: - posOriented  - PETSC_TRUE if the face was oriented with outward normal

2921:   Level: developer

2923: .seealso: `DMPlexGetCone()`
2924: @*/
2925: PetscErrorCode DMPlexGetOrientedFace(DM dm, PetscInt cell, PetscInt faceSize, const PetscInt face[], PetscInt numCorners, PetscInt indices[], PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
2926: {
2927:   const PetscInt *cone = NULL;
2928:   PetscInt        coneSize, v, f, v2;
2929:   PetscInt        oppositeVertex = -1;

2931:   PetscFunctionBegin;
2932:   PetscCall(DMPlexGetConeSize(dm, cell, &coneSize));
2933:   PetscCall(DMPlexGetCone(dm, cell, &cone));
2934:   for (v = 0, v2 = 0; v < coneSize; ++v) {
2935:     PetscBool found = PETSC_FALSE;

2937:     for (f = 0; f < faceSize; ++f) {
2938:       if (face[f] == cone[v]) {
2939:         found = PETSC_TRUE;
2940:         break;
2941:       }
2942:     }
2943:     if (found) {
2944:       indices[v2]      = v;
2945:       origVertices[v2] = cone[v];
2946:       ++v2;
2947:     } else {
2948:       oppositeVertex = v;
2949:     }
2950:   }
2951:   PetscCall(DMPlexGetFaceOrientation(dm, cell, numCorners, indices, oppositeVertex, origVertices, faceVertices, posOriented));
2952:   PetscFunctionReturn(PETSC_SUCCESS);
2953: }

2955: /*
2956:   DMPlexInsertFace_Internal - Puts a face into the mesh

2958:   Not collective

2960:   Input Parameters:
2961:   + dm              - The DMPlex
2962:   . numFaceVertex   - The number of vertices in the face
2963:   . faceVertices    - The vertices in the face for dm
2964:   . subfaceVertices - The vertices in the face for subdm
2965:   . numCorners      - The number of vertices in the cell
2966:   . cell            - A cell in dm containing the face
2967:   . subcell         - A cell in subdm containing the face
2968:   . firstFace       - First face in the mesh
2969:   - newFacePoint    - Next face in the mesh

2971:   Output Parameters:
2972:   . newFacePoint - Contains next face point number on input, updated on output

2974:   Level: developer
2975: */
2976: static PetscErrorCode DMPlexInsertFace_Internal(DM dm, DM subdm, PetscInt numFaceVertices, const PetscInt faceVertices[], const PetscInt subfaceVertices[], PetscInt numCorners, PetscInt cell, PetscInt subcell, PetscInt firstFace, PetscInt *newFacePoint)
2977: {
2978:   MPI_Comm        comm;
2979:   DM_Plex        *submesh = (DM_Plex *)subdm->data;
2980:   const PetscInt *faces;
2981:   PetscInt        numFaces, coneSize;

2983:   PetscFunctionBegin;
2984:   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
2985:   PetscCall(DMPlexGetConeSize(subdm, subcell, &coneSize));
2986:   PetscCheck(coneSize == 1, comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size of cell %" PetscInt_FMT " is %" PetscInt_FMT " != 1", cell, coneSize);
2987: #if 0
2988:   /* Cannot use this because support() has not been constructed yet */
2989:   PetscCall(DMPlexGetJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces));
2990: #else
2991:   {
2992:     PetscInt f;

2994:     numFaces = 0;
2995:     PetscCall(DMGetWorkArray(subdm, 1, MPIU_INT, (void **)&faces));
2996:     for (f = firstFace; f < *newFacePoint; ++f) {
2997:       PetscInt dof, off, d;

2999:       PetscCall(PetscSectionGetDof(submesh->coneSection, f, &dof));
3000:       PetscCall(PetscSectionGetOffset(submesh->coneSection, f, &off));
3001:       /* Yes, I know this is quadratic, but I expect the sizes to be <5 */
3002:       for (d = 0; d < dof; ++d) {
3003:         const PetscInt p = submesh->cones[off + d];
3004:         PetscInt       v;

3006:         for (v = 0; v < numFaceVertices; ++v) {
3007:           if (subfaceVertices[v] == p) break;
3008:         }
3009:         if (v == numFaceVertices) break;
3010:       }
3011:       if (d == dof) {
3012:         numFaces               = 1;
3013:         ((PetscInt *)faces)[0] = f;
3014:       }
3015:     }
3016:   }
3017: #endif
3018:   PetscCheck(numFaces <= 1, comm, PETSC_ERR_ARG_WRONG, "Vertex set had %" PetscInt_FMT " faces, not one", numFaces);
3019:   if (numFaces == 1) {
3020:     /* Add the other cell neighbor for this face */
3021:     PetscCall(DMPlexSetCone(subdm, subcell, faces));
3022:   } else {
3023:     PetscInt *indices, *origVertices, *orientedVertices, *orientedSubVertices, v, ov;
3024:     PetscBool posOriented;

3026:     PetscCall(DMGetWorkArray(subdm, 4 * numFaceVertices * sizeof(PetscInt), MPIU_INT, &orientedVertices));
3027:     origVertices        = &orientedVertices[numFaceVertices];
3028:     indices             = &orientedVertices[numFaceVertices * 2];
3029:     orientedSubVertices = &orientedVertices[numFaceVertices * 3];
3030:     PetscCall(DMPlexGetOrientedFace(dm, cell, numFaceVertices, faceVertices, numCorners, indices, origVertices, orientedVertices, &posOriented));
3031:     /* TODO: I know that routine should return a permutation, not the indices */
3032:     for (v = 0; v < numFaceVertices; ++v) {
3033:       const PetscInt vertex = faceVertices[v], subvertex = subfaceVertices[v];
3034:       for (ov = 0; ov < numFaceVertices; ++ov) {
3035:         if (orientedVertices[ov] == vertex) {
3036:           orientedSubVertices[ov] = subvertex;
3037:           break;
3038:         }
3039:       }
3040:       PetscCheck(ov != numFaceVertices, comm, PETSC_ERR_PLIB, "Could not find face vertex %" PetscInt_FMT " in orientated set", vertex);
3041:     }
3042:     PetscCall(DMPlexSetCone(subdm, *newFacePoint, orientedSubVertices));
3043:     PetscCall(DMPlexSetCone(subdm, subcell, newFacePoint));
3044:     PetscCall(DMRestoreWorkArray(subdm, 4 * numFaceVertices * sizeof(PetscInt), MPIU_INT, &orientedVertices));
3045:     ++(*newFacePoint);
3046:   }
3047: #if 0
3048:   PetscCall(DMPlexRestoreJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces));
3049: #else
3050:   PetscCall(DMRestoreWorkArray(subdm, 1, MPIU_INT, (void **)&faces));
3051: #endif
3052:   PetscFunctionReturn(PETSC_SUCCESS);
3053: }

3055: static PetscErrorCode DMPlexCreateSubmesh_Uninterpolated(DM dm, DMLabel vertexLabel, PetscInt value, DM subdm)
3056: {
3057:   MPI_Comm        comm;
3058:   DMLabel         subpointMap;
3059:   IS              subvertexIS, subcellIS;
3060:   const PetscInt *subVertices, *subCells;
3061:   PetscInt        numSubVertices, firstSubVertex, numSubCells;
3062:   PetscInt       *subface, maxConeSize, numSubFaces = 0, firstSubFace, newFacePoint, nFV = 0;
3063:   PetscInt        vStart, vEnd, c, f;

3065:   PetscFunctionBegin;
3066:   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
3067:   /* Create subpointMap which marks the submesh */
3068:   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "subpoint_map", &subpointMap));
3069:   PetscCall(DMPlexSetSubpointMap(subdm, subpointMap));
3070:   PetscCall(DMLabelDestroy(&subpointMap));
3071:   if (vertexLabel) PetscCall(DMPlexMarkSubmesh_Uninterpolated(dm, vertexLabel, value, subpointMap, &numSubFaces, &nFV, subdm));
3072:   /* Setup chart */
3073:   PetscCall(DMLabelGetStratumSize(subpointMap, 0, &numSubVertices));
3074:   PetscCall(DMLabelGetStratumSize(subpointMap, 2, &numSubCells));
3075:   PetscCall(DMPlexSetChart(subdm, 0, numSubCells + numSubFaces + numSubVertices));
3076:   PetscCall(DMPlexSetVTKCellHeight(subdm, 1));
3077:   /* Set cone sizes */
3078:   firstSubVertex = numSubCells;
3079:   firstSubFace   = numSubCells + numSubVertices;
3080:   newFacePoint   = firstSubFace;
3081:   PetscCall(DMLabelGetStratumIS(subpointMap, 0, &subvertexIS));
3082:   if (subvertexIS) PetscCall(ISGetIndices(subvertexIS, &subVertices));
3083:   PetscCall(DMLabelGetStratumIS(subpointMap, 2, &subcellIS));
3084:   if (subcellIS) PetscCall(ISGetIndices(subcellIS, &subCells));
3085:   for (c = 0; c < numSubCells; ++c) PetscCall(DMPlexSetConeSize(subdm, c, 1));
3086:   for (f = firstSubFace; f < firstSubFace + numSubFaces; ++f) PetscCall(DMPlexSetConeSize(subdm, f, nFV));
3087:   PetscCall(DMSetUp(subdm));
3088:   /* Create face cones */
3089:   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
3090:   PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, NULL));
3091:   PetscCall(DMGetWorkArray(subdm, maxConeSize, MPIU_INT, (void **)&subface));
3092:   for (c = 0; c < numSubCells; ++c) {
3093:     const PetscInt cell    = subCells[c];
3094:     const PetscInt subcell = c;
3095:     PetscInt      *closure = NULL;
3096:     PetscInt       closureSize, cl, numCorners = 0, faceSize = 0;

3098:     PetscCall(DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure));
3099:     for (cl = 0; cl < closureSize * 2; cl += 2) {
3100:       const PetscInt point = closure[cl];
3101:       PetscInt       subVertex;

3103:       if ((point >= vStart) && (point < vEnd)) {
3104:         ++numCorners;
3105:         PetscCall(PetscFindInt(point, numSubVertices, subVertices, &subVertex));
3106:         if (subVertex >= 0) {
3107:           closure[faceSize] = point;
3108:           subface[faceSize] = firstSubVertex + subVertex;
3109:           ++faceSize;
3110:         }
3111:       }
3112:     }
3113:     PetscCheck(faceSize <= nFV, comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %" PetscInt_FMT " of an element on the surface", faceSize);
3114:     if (faceSize == nFV) PetscCall(DMPlexInsertFace_Internal(dm, subdm, faceSize, closure, subface, numCorners, cell, subcell, firstSubFace, &newFacePoint));
3115:     PetscCall(DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure));
3116:   }
3117:   PetscCall(DMRestoreWorkArray(subdm, maxConeSize, MPIU_INT, (void **)&subface));
3118:   PetscCall(DMPlexSymmetrize(subdm));
3119:   PetscCall(DMPlexStratify(subdm));
3120:   /* Build coordinates */
3121:   {
3122:     PetscSection coordSection, subCoordSection;
3123:     Vec          coordinates, subCoordinates;
3124:     PetscScalar *coords, *subCoords;
3125:     PetscInt     numComp, coordSize, v;
3126:     const char  *name;

3128:     PetscCall(DMGetCoordinateSection(dm, &coordSection));
3129:     PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
3130:     PetscCall(DMGetCoordinateSection(subdm, &subCoordSection));
3131:     PetscCall(PetscSectionSetNumFields(subCoordSection, 1));
3132:     PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &numComp));
3133:     PetscCall(PetscSectionSetFieldComponents(subCoordSection, 0, numComp));
3134:     PetscCall(PetscSectionSetChart(subCoordSection, firstSubVertex, firstSubVertex + numSubVertices));
3135:     for (v = 0; v < numSubVertices; ++v) {
3136:       const PetscInt vertex    = subVertices[v];
3137:       const PetscInt subvertex = firstSubVertex + v;
3138:       PetscInt       dof;

3140:       PetscCall(PetscSectionGetDof(coordSection, vertex, &dof));
3141:       PetscCall(PetscSectionSetDof(subCoordSection, subvertex, dof));
3142:       PetscCall(PetscSectionSetFieldDof(subCoordSection, subvertex, 0, dof));
3143:     }
3144:     PetscCall(PetscSectionSetUp(subCoordSection));
3145:     PetscCall(PetscSectionGetStorageSize(subCoordSection, &coordSize));
3146:     PetscCall(VecCreate(PETSC_COMM_SELF, &subCoordinates));
3147:     PetscCall(PetscObjectGetName((PetscObject)coordinates, &name));
3148:     PetscCall(PetscObjectSetName((PetscObject)subCoordinates, name));
3149:     PetscCall(VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE));
3150:     PetscCall(VecSetType(subCoordinates, VECSTANDARD));
3151:     if (coordSize) {
3152:       PetscCall(VecGetArray(coordinates, &coords));
3153:       PetscCall(VecGetArray(subCoordinates, &subCoords));
3154:       for (v = 0; v < numSubVertices; ++v) {
3155:         const PetscInt vertex    = subVertices[v];
3156:         const PetscInt subvertex = firstSubVertex + v;
3157:         PetscInt       dof, off, sdof, soff, d;

3159:         PetscCall(PetscSectionGetDof(coordSection, vertex, &dof));
3160:         PetscCall(PetscSectionGetOffset(coordSection, vertex, &off));
3161:         PetscCall(PetscSectionGetDof(subCoordSection, subvertex, &sdof));
3162:         PetscCall(PetscSectionGetOffset(subCoordSection, subvertex, &soff));
3163:         PetscCheck(dof == sdof, comm, PETSC_ERR_PLIB, "Coordinate dimension %" PetscInt_FMT " on subvertex %" PetscInt_FMT ", vertex %" PetscInt_FMT " should be %" PetscInt_FMT, sdof, subvertex, vertex, dof);
3164:         for (d = 0; d < dof; ++d) subCoords[soff + d] = coords[off + d];
3165:       }
3166:       PetscCall(VecRestoreArray(coordinates, &coords));
3167:       PetscCall(VecRestoreArray(subCoordinates, &subCoords));
3168:     }
3169:     PetscCall(DMSetCoordinatesLocal(subdm, subCoordinates));
3170:     PetscCall(VecDestroy(&subCoordinates));
3171:   }
3172:   /* Cleanup */
3173:   if (subvertexIS) PetscCall(ISRestoreIndices(subvertexIS, &subVertices));
3174:   PetscCall(ISDestroy(&subvertexIS));
3175:   if (subcellIS) PetscCall(ISRestoreIndices(subcellIS, &subCells));
3176:   PetscCall(ISDestroy(&subcellIS));
3177:   PetscFunctionReturn(PETSC_SUCCESS);
3178: }

3180: /* TODO: Fix this to properly propagate up error conditions it may find */
3181: static inline PetscInt DMPlexFilterPoint_Internal(PetscInt point, PetscInt firstSubPoint, PetscInt numSubPoints, const PetscInt subPoints[])
3182: {
3183:   PetscInt       subPoint;
3184:   PetscErrorCode ierr;

3186:   ierr = PetscFindInt(point, numSubPoints, subPoints, &subPoint);
3187:   if (ierr) return -1;
3188:   return subPoint < 0 ? subPoint : firstSubPoint + subPoint;
3189: }

3191: /* TODO: Fix this to properly propagate up error conditions it may find */
3192: static inline PetscInt DMPlexFilterPointPerm_Internal(PetscInt point, PetscInt firstSubPoint, PetscInt numSubPoints, const PetscInt subPoints[], const PetscInt subIndices[])
3193: {
3194:   PetscInt       subPoint;
3195:   PetscErrorCode ierr;

3197:   ierr = PetscFindInt(point, numSubPoints, subPoints, &subPoint);
3198:   if (ierr) return -1;
3199:   return subPoint < 0 ? subPoint : firstSubPoint + (subIndices ? subIndices[subPoint] : subPoint);
3200: }

3202: static PetscErrorCode DMPlexFilterLabels_Internal(DM dm, const PetscInt numSubPoints[], const PetscInt *subpoints[], const PetscInt firstSubPoint[], DM subdm)
3203: {
3204:   DMLabel  depthLabel;
3205:   PetscInt Nl, l, d;

3207:   PetscFunctionBegin;
3208:   // Reset depth label for fast lookup
3209:   PetscCall(DMPlexGetDepthLabel(dm, &depthLabel));
3210:   PetscCall(DMLabelMakeAllInvalid_Internal(depthLabel));
3211:   PetscCall(DMGetNumLabels(dm, &Nl));
3212:   for (l = 0; l < Nl; ++l) {
3213:     DMLabel         label, newlabel;
3214:     const char     *lname;
3215:     PetscBool       isDepth, isDim, isCelltype, isVTK;
3216:     IS              valueIS;
3217:     const PetscInt *values;
3218:     PetscInt        Nv, v;

3220:     PetscCall(DMGetLabelName(dm, l, &lname));
3221:     PetscCall(PetscStrcmp(lname, "depth", &isDepth));
3222:     PetscCall(PetscStrcmp(lname, "dim", &isDim));
3223:     PetscCall(PetscStrcmp(lname, "celltype", &isCelltype));
3224:     PetscCall(PetscStrcmp(lname, "vtk", &isVTK));
3225:     if (isDepth || isDim || isCelltype || isVTK) continue;
3226:     PetscCall(DMCreateLabel(subdm, lname));
3227:     PetscCall(DMGetLabel(dm, lname, &label));
3228:     PetscCall(DMGetLabel(subdm, lname, &newlabel));
3229:     PetscCall(DMLabelGetDefaultValue(label, &v));
3230:     PetscCall(DMLabelSetDefaultValue(newlabel, v));
3231:     PetscCall(DMLabelGetValueIS(label, &valueIS));
3232:     PetscCall(ISGetLocalSize(valueIS, &Nv));
3233:     PetscCall(ISGetIndices(valueIS, &values));
3234:     for (v = 0; v < Nv; ++v) {
3235:       IS              pointIS;
3236:       const PetscInt *points;
3237:       PetscInt        Np, p;

3239:       PetscCall(DMLabelGetStratumIS(label, values[v], &pointIS));
3240:       PetscCall(ISGetLocalSize(pointIS, &Np));
3241:       PetscCall(ISGetIndices(pointIS, &points));
3242:       for (p = 0; p < Np; ++p) {
3243:         const PetscInt point = points[p];
3244:         PetscInt       subp;

3246:         PetscCall(DMPlexGetPointDepth(dm, point, &d));
3247:         subp = DMPlexFilterPoint_Internal(point, firstSubPoint[d], numSubPoints[d], subpoints[d]);
3248:         if (subp >= 0) PetscCall(DMLabelSetValue(newlabel, subp, values[v]));
3249:       }
3250:       PetscCall(ISRestoreIndices(pointIS, &points));
3251:       PetscCall(ISDestroy(&pointIS));
3252:     }
3253:     PetscCall(ISRestoreIndices(valueIS, &values));
3254:     PetscCall(ISDestroy(&valueIS));
3255:   }
3256:   PetscFunctionReturn(PETSC_SUCCESS);
3257: }

3259: static PetscErrorCode DMPlexCreateSubmeshGeneric_Interpolated(DM dm, DMLabel label, PetscInt value, PetscBool markedFaces, PetscBool isCohesive, PetscInt cellHeight, DM subdm)
3260: {
3261:   MPI_Comm         comm;
3262:   DMLabel          subpointMap;
3263:   IS              *subpointIS;
3264:   const PetscInt **subpoints;
3265:   PetscInt        *numSubPoints, *firstSubPoint, *coneNew, *orntNew;
3266:   PetscInt         totSubPoints = 0, maxConeSize, dim, sdim, cdim, p, d, v;
3267:   PetscMPIInt      rank;

3269:   PetscFunctionBegin;
3270:   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
3271:   PetscCallMPI(MPI_Comm_rank(comm, &rank));
3272:   /* Create subpointMap which marks the submesh */
3273:   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "subpoint_map", &subpointMap));
3274:   PetscCall(DMPlexSetSubpointMap(subdm, subpointMap));
3275:   if (cellHeight) {
3276:     if (isCohesive) PetscCall(DMPlexMarkCohesiveSubmesh_Interpolated(dm, label, value, subpointMap, subdm));
3277:     else PetscCall(DMPlexMarkSubmesh_Interpolated(dm, label, value, markedFaces, subpointMap, subdm));
3278:   } else {
3279:     DMLabel         depth;
3280:     IS              pointIS;
3281:     const PetscInt *points;
3282:     PetscInt        numPoints = 0;

3284:     PetscCall(DMPlexGetDepthLabel(dm, &depth));
3285:     PetscCall(DMLabelGetStratumIS(label, value, &pointIS));
3286:     if (pointIS) {
3287:       PetscCall(ISGetIndices(pointIS, &points));
3288:       PetscCall(ISGetLocalSize(pointIS, &numPoints));
3289:     }
3290:     for (p = 0; p < numPoints; ++p) {
3291:       PetscInt *closure = NULL;
3292:       PetscInt  closureSize, c, pdim;

3294:       PetscCall(DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closure));
3295:       for (c = 0; c < closureSize * 2; c += 2) {
3296:         PetscCall(DMLabelGetValue(depth, closure[c], &pdim));
3297:         PetscCall(DMLabelSetValue(subpointMap, closure[c], pdim));
3298:       }
3299:       PetscCall(DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closure));
3300:     }
3301:     if (pointIS) PetscCall(ISRestoreIndices(pointIS, &points));
3302:     PetscCall(ISDestroy(&pointIS));
3303:   }
3304:   /* Setup chart */
3305:   PetscCall(DMGetDimension(dm, &dim));
3306:   PetscCall(DMGetCoordinateDim(dm, &cdim));
3307:   PetscCall(PetscMalloc4(dim + 1, &numSubPoints, dim + 1, &firstSubPoint, dim + 1, &subpointIS, dim + 1, &subpoints));
3308:   for (d = 0; d <= dim; ++d) {
3309:     PetscCall(DMLabelGetStratumSize(subpointMap, d, &numSubPoints[d]));
3310:     totSubPoints += numSubPoints[d];
3311:   }
3312:   // Determine submesh dimension
3313:   PetscCall(DMGetDimension(subdm, &sdim));
3314:   if (sdim > 0) {
3315:     // Calling function knows what dimension to use, and we include neighboring cells as well
3316:     sdim = dim;
3317:   } else {
3318:     // We reset the subdimension based on what is being selected
3319:     PetscInt lsdim;
3320:     for (lsdim = dim; lsdim >= 0; --lsdim)
3321:       if (numSubPoints[lsdim]) break;
3322:     PetscCallMPI(MPI_Allreduce(&lsdim, &sdim, 1, MPIU_INT, MPIU_MAX, comm));
3323:     PetscCall(DMSetDimension(subdm, sdim));
3324:     PetscCall(DMSetCoordinateDim(subdm, cdim));
3325:   }
3326:   PetscCall(DMPlexSetChart(subdm, 0, totSubPoints));
3327:   PetscCall(DMPlexSetVTKCellHeight(subdm, cellHeight));
3328:   /* Set cone sizes */
3329:   firstSubPoint[sdim] = 0;
3330:   firstSubPoint[0]    = firstSubPoint[sdim] + numSubPoints[sdim];
3331:   if (sdim > 1) firstSubPoint[sdim - 1] = firstSubPoint[0] + numSubPoints[0];
3332:   if (sdim > 2) firstSubPoint[sdim - 2] = firstSubPoint[sdim - 1] + numSubPoints[sdim - 1];
3333:   for (d = 0; d <= sdim; ++d) {
3334:     PetscCall(DMLabelGetStratumIS(subpointMap, d, &subpointIS[d]));
3335:     if (subpointIS[d]) PetscCall(ISGetIndices(subpointIS[d], &subpoints[d]));
3336:   }
3337:   /* We do not want this label automatically computed, instead we compute it here */
3338:   PetscCall(DMCreateLabel(subdm, "celltype"));
3339:   for (d = 0; d <= sdim; ++d) {
3340:     for (p = 0; p < numSubPoints[d]; ++p) {
3341:       const PetscInt  point    = subpoints[d][p];
3342:       const PetscInt  subpoint = firstSubPoint[d] + p;
3343:       const PetscInt *cone;
3344:       PetscInt        coneSize;

3346:       PetscCall(DMPlexGetConeSize(dm, point, &coneSize));
3347:       if (cellHeight && (d == sdim)) {
3348:         PetscInt coneSizeNew, c, val;

3350:         PetscCall(DMPlexGetCone(dm, point, &cone));
3351:         for (c = 0, coneSizeNew = 0; c < coneSize; ++c) {
3352:           PetscCall(DMLabelGetValue(subpointMap, cone[c], &val));
3353:           if (val >= 0) coneSizeNew++;
3354:         }
3355:         PetscCall(DMPlexSetConeSize(subdm, subpoint, coneSizeNew));
3356:         PetscCall(DMPlexSetCellType(subdm, subpoint, DM_POLYTOPE_FV_GHOST));
3357:       } else {
3358:         DMPolytopeType ct;

3360:         PetscCall(DMPlexSetConeSize(subdm, subpoint, coneSize));
3361:         PetscCall(DMPlexGetCellType(dm, point, &ct));
3362:         PetscCall(DMPlexSetCellType(subdm, subpoint, ct));
3363:       }
3364:     }
3365:   }
3366:   PetscCall(DMLabelDestroy(&subpointMap));
3367:   PetscCall(DMSetUp(subdm));
3368:   /* Set cones */
3369:   PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, NULL));
3370:   PetscCall(PetscMalloc2(maxConeSize, &coneNew, maxConeSize, &orntNew));
3371:   for (d = 0; d <= sdim; ++d) {
3372:     for (p = 0; p < numSubPoints[d]; ++p) {
3373:       const PetscInt  point    = subpoints[d][p];
3374:       const PetscInt  subpoint = firstSubPoint[d] + p;
3375:       const PetscInt *cone, *ornt;
3376:       PetscInt        coneSize, subconeSize, coneSizeNew, c, subc, fornt = 0;

3378:       if (d == sdim - 1) {
3379:         const PetscInt *support, *cone, *ornt;
3380:         PetscInt        supportSize, coneSize, s, subc;

3382:         PetscCall(DMPlexGetSupport(dm, point, &support));
3383:         PetscCall(DMPlexGetSupportSize(dm, point, &supportSize));
3384:         for (s = 0; s < supportSize; ++s) {
3385:           PetscBool isHybrid = PETSC_FALSE;

3387:           PetscCall(DMPlexCellIsHybrid_Internal(dm, support[s], &isHybrid));
3388:           if (!isHybrid) continue;
3389:           PetscCall(PetscFindInt(support[s], numSubPoints[d + 1], subpoints[d + 1], &subc));
3390:           if (subc >= 0) {
3391:             const PetscInt ccell = subpoints[d + 1][subc];

3393:             PetscCall(DMPlexGetCone(dm, ccell, &cone));
3394:             PetscCall(DMPlexGetConeSize(dm, ccell, &coneSize));
3395:             PetscCall(DMPlexGetConeOrientation(dm, ccell, &ornt));
3396:             for (c = 0; c < coneSize; ++c) {
3397:               if (cone[c] == point) {
3398:                 fornt = ornt[c];
3399:                 break;
3400:               }
3401:             }
3402:             break;
3403:           }
3404:         }
3405:       }
3406:       PetscCall(DMPlexGetConeSize(dm, point, &coneSize));
3407:       PetscCall(DMPlexGetConeSize(subdm, subpoint, &subconeSize));
3408:       PetscCall(DMPlexGetCone(dm, point, &cone));
3409:       PetscCall(DMPlexGetConeOrientation(dm, point, &ornt));
3410:       for (c = 0, coneSizeNew = 0; c < coneSize; ++c) {
3411:         PetscCall(PetscFindInt(cone[c], numSubPoints[d - 1], subpoints[d - 1], &subc));
3412:         if (subc >= 0) {
3413:           coneNew[coneSizeNew] = firstSubPoint[d - 1] + subc;
3414:           orntNew[coneSizeNew] = ornt[c];
3415:           ++coneSizeNew;
3416:         }
3417:       }
3418:       PetscCheck(coneSizeNew == subconeSize, comm, PETSC_ERR_PLIB, "Number of cone points located %" PetscInt_FMT " does not match subcone size %" PetscInt_FMT, coneSizeNew, subconeSize);
3419:       PetscCall(DMPlexSetCone(subdm, subpoint, coneNew));
3420:       PetscCall(DMPlexSetConeOrientation(subdm, subpoint, orntNew));
3421:       if (fornt < 0) PetscCall(DMPlexOrientPoint(subdm, subpoint, fornt));
3422:     }
3423:   }
3424:   PetscCall(PetscFree2(coneNew, orntNew));
3425:   PetscCall(DMPlexSymmetrize(subdm));
3426:   PetscCall(DMPlexStratify(subdm));
3427:   /* Build coordinates */
3428:   {
3429:     PetscSection coordSection, subCoordSection;
3430:     Vec          coordinates, subCoordinates;
3431:     PetscScalar *coords, *subCoords;
3432:     PetscInt     cdim, numComp, coordSize;
3433:     const char  *name;

3435:     PetscCall(DMGetCoordinateDim(dm, &cdim));
3436:     PetscCall(DMGetCoordinateSection(dm, &coordSection));
3437:     PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
3438:     PetscCall(DMGetCoordinateSection(subdm, &subCoordSection));
3439:     PetscCall(PetscSectionSetNumFields(subCoordSection, 1));
3440:     PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &numComp));
3441:     PetscCall(PetscSectionSetFieldComponents(subCoordSection, 0, numComp));
3442:     PetscCall(PetscSectionSetChart(subCoordSection, firstSubPoint[0], firstSubPoint[0] + numSubPoints[0]));
3443:     for (v = 0; v < numSubPoints[0]; ++v) {
3444:       const PetscInt vertex    = subpoints[0][v];
3445:       const PetscInt subvertex = firstSubPoint[0] + v;
3446:       PetscInt       dof;

3448:       PetscCall(PetscSectionGetDof(coordSection, vertex, &dof));
3449:       PetscCall(PetscSectionSetDof(subCoordSection, subvertex, dof));
3450:       PetscCall(PetscSectionSetFieldDof(subCoordSection, subvertex, 0, dof));
3451:     }
3452:     PetscCall(PetscSectionSetUp(subCoordSection));
3453:     PetscCall(PetscSectionGetStorageSize(subCoordSection, &coordSize));
3454:     PetscCall(VecCreate(PETSC_COMM_SELF, &subCoordinates));
3455:     PetscCall(PetscObjectGetName((PetscObject)coordinates, &name));
3456:     PetscCall(PetscObjectSetName((PetscObject)subCoordinates, name));
3457:     PetscCall(VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE));
3458:     PetscCall(VecSetBlockSize(subCoordinates, cdim));
3459:     PetscCall(VecSetType(subCoordinates, VECSTANDARD));
3460:     PetscCall(VecGetArray(coordinates, &coords));
3461:     PetscCall(VecGetArray(subCoordinates, &subCoords));
3462:     for (v = 0; v < numSubPoints[0]; ++v) {
3463:       const PetscInt vertex    = subpoints[0][v];
3464:       const PetscInt subvertex = firstSubPoint[0] + v;
3465:       PetscInt       dof, off, sdof, soff, d;

3467:       PetscCall(PetscSectionGetDof(coordSection, vertex, &dof));
3468:       PetscCall(PetscSectionGetOffset(coordSection, vertex, &off));
3469:       PetscCall(PetscSectionGetDof(subCoordSection, subvertex, &sdof));
3470:       PetscCall(PetscSectionGetOffset(subCoordSection, subvertex, &soff));
3471:       PetscCheck(dof == sdof, comm, PETSC_ERR_PLIB, "Coordinate dimension %" PetscInt_FMT " on subvertex %" PetscInt_FMT ", vertex %" PetscInt_FMT " should be %" PetscInt_FMT, sdof, subvertex, vertex, dof);
3472:       for (d = 0; d < dof; ++d) subCoords[soff + d] = coords[off + d];
3473:     }
3474:     PetscCall(VecRestoreArray(coordinates, &coords));
3475:     PetscCall(VecRestoreArray(subCoordinates, &subCoords));
3476:     PetscCall(DMSetCoordinatesLocal(subdm, subCoordinates));
3477:     PetscCall(VecDestroy(&subCoordinates));
3478:   }
3479:   /* Build SF: We need this complexity because subpoints might not be selected on the owning process */
3480:   {
3481:     PetscSF            sfPoint, sfPointSub;
3482:     IS                 subpIS;
3483:     const PetscSFNode *remotePoints;
3484:     PetscSFNode       *sremotePoints = NULL, *newLocalPoints = NULL, *newOwners = NULL;
3485:     const PetscInt    *localPoints, *subpoints, *rootdegree;
3486:     PetscInt          *slocalPoints = NULL, *sortedPoints = NULL, *sortedIndices = NULL;
3487:     PetscInt           numRoots, numLeaves, numSubpoints = 0, numSubroots, numSubleaves = 0, l, sl = 0, ll = 0, pStart, pEnd, p;
3488:     PetscMPIInt        rank, size;

3490:     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
3491:     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
3492:     PetscCall(DMGetPointSF(dm, &sfPoint));
3493:     PetscCall(DMGetPointSF(subdm, &sfPointSub));
3494:     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
3495:     PetscCall(DMPlexGetChart(subdm, NULL, &numSubroots));
3496:     PetscCall(DMPlexGetSubpointIS(subdm, &subpIS));
3497:     if (subpIS) {
3498:       PetscBool sorted = PETSC_TRUE;

3500:       PetscCall(ISGetIndices(subpIS, &subpoints));
3501:       PetscCall(ISGetLocalSize(subpIS, &numSubpoints));
3502:       for (p = 1; p < numSubpoints; ++p) sorted = sorted && (subpoints[p] >= subpoints[p - 1]) ? PETSC_TRUE : PETSC_FALSE;
3503:       if (!sorted) {
3504:         PetscCall(PetscMalloc2(numSubpoints, &sortedPoints, numSubpoints, &sortedIndices));
3505:         for (p = 0; p < numSubpoints; ++p) sortedIndices[p] = p;
3506:         PetscCall(PetscArraycpy(sortedPoints, subpoints, numSubpoints));
3507:         PetscCall(PetscSortIntWithArray(numSubpoints, sortedPoints, sortedIndices));
3508:       }
3509:     }
3510:     PetscCall(PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints));
3511:     if (numRoots >= 0) {
3512:       PetscCall(PetscSFComputeDegreeBegin(sfPoint, &rootdegree));
3513:       PetscCall(PetscSFComputeDegreeEnd(sfPoint, &rootdegree));
3514:       PetscCall(PetscMalloc2(pEnd - pStart, &newLocalPoints, numRoots, &newOwners));
3515:       for (p = 0; p < pEnd - pStart; ++p) {
3516:         newLocalPoints[p].rank  = -2;
3517:         newLocalPoints[p].index = -2;
3518:       }
3519:       /* Set subleaves */
3520:       for (l = 0; l < numLeaves; ++l) {
3521:         const PetscInt point    = localPoints[l];
3522:         const PetscInt subpoint = DMPlexFilterPointPerm_Internal(point, 0, numSubpoints, sortedPoints ? sortedPoints : subpoints, sortedIndices);

3524:         if (subpoint < 0) continue;
3525:         newLocalPoints[point - pStart].rank  = rank;
3526:         newLocalPoints[point - pStart].index = subpoint;
3527:         ++numSubleaves;
3528:       }
3529:       /* Must put in owned subpoints */
3530:       for (p = pStart; p < pEnd; ++p) {
3531:         newOwners[p - pStart].rank  = -3;
3532:         newOwners[p - pStart].index = -3;
3533:       }
3534:       for (p = 0; p < numSubpoints; ++p) {
3535:         /* Hold on to currently owned points */
3536:         if (rootdegree[subpoints[p] - pStart]) newOwners[subpoints[p] - pStart].rank = rank + size;
3537:         else newOwners[subpoints[p] - pStart].rank = rank;
3538:         newOwners[subpoints[p] - pStart].index = p;
3539:       }
3540:       PetscCall(PetscSFReduceBegin(sfPoint, MPIU_2INT, newLocalPoints, newOwners, MPI_MAXLOC));
3541:       PetscCall(PetscSFReduceEnd(sfPoint, MPIU_2INT, newLocalPoints, newOwners, MPI_MAXLOC));
3542:       for (p = pStart; p < pEnd; ++p)
3543:         if (newOwners[p - pStart].rank >= size) newOwners[p - pStart].rank -= size;
3544:       PetscCall(PetscSFBcastBegin(sfPoint, MPIU_2INT, newOwners, newLocalPoints, MPI_REPLACE));
3545:       PetscCall(PetscSFBcastEnd(sfPoint, MPIU_2INT, newOwners, newLocalPoints, MPI_REPLACE));
3546:       PetscCall(PetscMalloc1(numSubleaves, &slocalPoints));
3547:       PetscCall(PetscMalloc1(numSubleaves, &sremotePoints));
3548:       for (l = 0; l < numLeaves; ++l) {
3549:         const PetscInt point    = localPoints[l];
3550:         const PetscInt subpoint = DMPlexFilterPointPerm_Internal(point, 0, numSubpoints, sortedPoints ? sortedPoints : subpoints, sortedIndices);

3552:         if (subpoint < 0) continue;
3553:         if (newLocalPoints[point].rank == rank) {
3554:           ++ll;
3555:           continue;
3556:         }
3557:         slocalPoints[sl]        = subpoint;
3558:         sremotePoints[sl].rank  = newLocalPoints[point].rank;
3559:         sremotePoints[sl].index = newLocalPoints[point].index;
3560:         PetscCheck(sremotePoints[sl].rank >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid remote rank for local point %" PetscInt_FMT, point);
3561:         PetscCheck(sremotePoints[sl].index >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid remote subpoint for local point %" PetscInt_FMT, point);
3562:         ++sl;
3563:       }
3564:       PetscCheck(sl + ll == numSubleaves, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatch in number of subleaves %" PetscInt_FMT " + %" PetscInt_FMT " != %" PetscInt_FMT, sl, ll, numSubleaves);
3565:       PetscCall(PetscFree2(newLocalPoints, newOwners));
3566:       PetscCall(PetscSFSetGraph(sfPointSub, numSubroots, sl, slocalPoints, PETSC_OWN_POINTER, sremotePoints, PETSC_OWN_POINTER));
3567:     }
3568:     if (subpIS) PetscCall(ISRestoreIndices(subpIS, &subpoints));
3569:     PetscCall(PetscFree2(sortedPoints, sortedIndices));
3570:   }
3571:   /* Filter labels */
3572:   PetscCall(DMPlexFilterLabels_Internal(dm, numSubPoints, subpoints, firstSubPoint, subdm));
3573:   /* Cleanup */
3574:   for (d = 0; d <= sdim; ++d) {
3575:     if (subpointIS[d]) PetscCall(ISRestoreIndices(subpointIS[d], &subpoints[d]));
3576:     PetscCall(ISDestroy(&subpointIS[d]));
3577:   }
3578:   PetscCall(PetscFree4(numSubPoints, firstSubPoint, subpointIS, subpoints));
3579:   PetscFunctionReturn(PETSC_SUCCESS);
3580: }

3582: static PetscErrorCode DMPlexCreateSubmesh_Interpolated(DM dm, DMLabel vertexLabel, PetscInt value, PetscBool markedFaces, DM subdm)
3583: {
3584:   PetscFunctionBegin;
3585:   PetscCall(DMPlexCreateSubmeshGeneric_Interpolated(dm, vertexLabel, value, markedFaces, PETSC_FALSE, 1, subdm));
3586:   PetscFunctionReturn(PETSC_SUCCESS);
3587: }

3589: /*@
3590:   DMPlexCreateSubmesh - Extract a hypersurface from the mesh using vertices defined by a label

3592:   Input Parameters:
3593: + dm           - The original mesh
3594: . vertexLabel  - The DMLabel marking points contained in the surface
3595: . value        - The label value to use
3596: - markedFaces  - PETSC_TRUE if surface faces are marked in addition to vertices, PETSC_FALSE if only vertices are marked

3598:   Output Parameter:
3599: . subdm - The surface mesh

3601:   Note: This function produces a DMLabel mapping original points in the submesh to their depth. This can be obtained using DMPlexGetSubpointMap().

3603:   Level: developer

3605: .seealso: `DMPlexGetSubpointMap()`, `DMGetLabel()`, `DMLabelSetValue()`
3606: @*/
3607: PetscErrorCode DMPlexCreateSubmesh(DM dm, DMLabel vertexLabel, PetscInt value, PetscBool markedFaces, DM *subdm)
3608: {
3609:   DMPlexInterpolatedFlag interpolated;
3610:   PetscInt               dim, cdim;

3612:   PetscFunctionBegin;
3615:   PetscCall(DMGetDimension(dm, &dim));
3616:   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), subdm));
3617:   PetscCall(DMSetType(*subdm, DMPLEX));
3618:   PetscCall(DMSetDimension(*subdm, dim - 1));
3619:   PetscCall(DMGetCoordinateDim(dm, &cdim));
3620:   PetscCall(DMSetCoordinateDim(*subdm, cdim));
3621:   PetscCall(DMPlexIsInterpolated(dm, &interpolated));
3622:   PetscCheck(interpolated != DMPLEX_INTERPOLATED_PARTIAL, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not for partially interpolated meshes");
3623:   if (interpolated) {
3624:     PetscCall(DMPlexCreateSubmesh_Interpolated(dm, vertexLabel, value, markedFaces, *subdm));
3625:   } else {
3626:     PetscCall(DMPlexCreateSubmesh_Uninterpolated(dm, vertexLabel, value, *subdm));
3627:   }
3628:   PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_TRUE, *subdm));
3629:   PetscFunctionReturn(PETSC_SUCCESS);
3630: }

3632: static PetscErrorCode DMPlexCreateCohesiveSubmesh_Uninterpolated(DM dm, PetscBool hasLagrange, const char label[], PetscInt value, DM subdm)
3633: {
3634:   MPI_Comm        comm;
3635:   DMLabel         subpointMap;
3636:   IS              subvertexIS;
3637:   const PetscInt *subVertices;
3638:   PetscInt        numSubVertices, firstSubVertex, numSubCells, *subCells = NULL;
3639:   PetscInt       *subface, maxConeSize, numSubFaces, firstSubFace, newFacePoint, nFV;
3640:   PetscInt        c, f;

3642:   PetscFunctionBegin;
3643:   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
3644:   /* Create subpointMap which marks the submesh */
3645:   PetscCall(DMLabelCreate(PETSC_COMM_SELF, "subpoint_map", &subpointMap));
3646:   PetscCall(DMPlexSetSubpointMap(subdm, subpointMap));
3647:   PetscCall(DMLabelDestroy(&subpointMap));
3648:   PetscCall(DMPlexMarkCohesiveSubmesh_Uninterpolated(dm, hasLagrange, label, value, subpointMap, &numSubFaces, &nFV, &subCells, subdm));
3649:   /* Setup chart */
3650:   PetscCall(DMLabelGetStratumSize(subpointMap, 0, &numSubVertices));
3651:   PetscCall(DMLabelGetStratumSize(subpointMap, 2, &numSubCells));
3652:   PetscCall(DMPlexSetChart(subdm, 0, numSubCells + numSubFaces + numSubVertices));
3653:   PetscCall(DMPlexSetVTKCellHeight(subdm, 1));
3654:   /* Set cone sizes */
3655:   firstSubVertex = numSubCells;
3656:   firstSubFace   = numSubCells + numSubVertices;
3657:   newFacePoint   = firstSubFace;
3658:   PetscCall(DMLabelGetStratumIS(subpointMap, 0, &subvertexIS));
3659:   if (subvertexIS) PetscCall(ISGetIndices(subvertexIS, &subVertices));
3660:   for (c = 0; c < numSubCells; ++c) PetscCall(DMPlexSetConeSize(subdm, c, 1));
3661:   for (f = firstSubFace; f < firstSubFace + numSubFaces; ++f) PetscCall(DMPlexSetConeSize(subdm, f, nFV));
3662:   PetscCall(DMSetUp(subdm));
3663:   /* Create face cones */
3664:   PetscCall(DMPlexGetMaxSizes(dm, &maxConeSize, NULL));
3665:   PetscCall(DMGetWorkArray(subdm, maxConeSize, MPIU_INT, (void **)&subface));
3666:   for (c = 0; c < numSubCells; ++c) {
3667:     const PetscInt  cell    = subCells[c];
3668:     const PetscInt  subcell = c;
3669:     const PetscInt *cone, *cells;
3670:     PetscBool       isHybrid = PETSC_FALSE;
3671:     PetscInt        numCells, subVertex, p, v;

3673:     PetscCall(DMPlexCellIsHybrid_Internal(dm, cell, &isHybrid));
3674:     if (!isHybrid) continue;
3675:     PetscCall(DMPlexGetCone(dm, cell, &cone));
3676:     for (v = 0; v < nFV; ++v) {
3677:       PetscCall(PetscFindInt(cone[v], numSubVertices, subVertices, &subVertex));
3678:       subface[v] = firstSubVertex + subVertex;
3679:     }
3680:     PetscCall(DMPlexSetCone(subdm, newFacePoint, subface));
3681:     PetscCall(DMPlexSetCone(subdm, subcell, &newFacePoint));
3682:     PetscCall(DMPlexGetJoin(dm, nFV, cone, &numCells, &cells));
3683:     /* Not true in parallel
3684:     PetscCheck(numCells == 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cohesive cells should separate two cells"); */
3685:     for (p = 0; p < numCells; ++p) {
3686:       PetscInt  negsubcell;
3687:       PetscBool isHybrid = PETSC_FALSE;

3689:       PetscCall(DMPlexCellIsHybrid_Internal(dm, cells[p], &isHybrid));
3690:       if (isHybrid) continue;
3691:       /* I know this is a crap search */
3692:       for (negsubcell = 0; negsubcell < numSubCells; ++negsubcell) {
3693:         if (subCells[negsubcell] == cells[p]) break;
3694:       }
3695:       PetscCheck(negsubcell != numSubCells, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find negative face neighbor for cohesive cell %" PetscInt_FMT, cell);
3696:       PetscCall(DMPlexSetCone(subdm, negsubcell, &newFacePoint));
3697:     }
3698:     PetscCall(DMPlexRestoreJoin(dm, nFV, cone, &numCells, &cells));
3699:     ++newFacePoint;
3700:   }
3701:   PetscCall(DMRestoreWorkArray(subdm, maxConeSize, MPIU_INT, (void **)&subface));
3702:   PetscCall(DMPlexSymmetrize(subdm));
3703:   PetscCall(DMPlexStratify(subdm));
3704:   /* Build coordinates */
3705:   {
3706:     PetscSection coordSection, subCoordSection;
3707:     Vec          coordinates, subCoordinates;
3708:     PetscScalar *coords, *subCoords;
3709:     PetscInt     cdim, numComp, coordSize, v;
3710:     const char  *name;

3712:     PetscCall(DMGetCoordinateDim(dm, &cdim));
3713:     PetscCall(DMGetCoordinateSection(dm, &coordSection));
3714:     PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
3715:     PetscCall(DMGetCoordinateSection(subdm, &subCoordSection));
3716:     PetscCall(PetscSectionSetNumFields(subCoordSection, 1));
3717:     PetscCall(PetscSectionGetFieldComponents(coordSection, 0, &numComp));
3718:     PetscCall(PetscSectionSetFieldComponents(subCoordSection, 0, numComp));
3719:     PetscCall(PetscSectionSetChart(subCoordSection, firstSubVertex, firstSubVertex + numSubVertices));
3720:     for (v = 0; v < numSubVertices; ++v) {
3721:       const PetscInt vertex    = subVertices[v];
3722:       const PetscInt subvertex = firstSubVertex + v;
3723:       PetscInt       dof;

3725:       PetscCall(PetscSectionGetDof(coordSection, vertex, &dof));
3726:       PetscCall(PetscSectionSetDof(subCoordSection, subvertex, dof));
3727:       PetscCall(PetscSectionSetFieldDof(subCoordSection, subvertex, 0, dof));
3728:     }
3729:     PetscCall(PetscSectionSetUp(subCoordSection));
3730:     PetscCall(PetscSectionGetStorageSize(subCoordSection, &coordSize));
3731:     PetscCall(VecCreate(PETSC_COMM_SELF, &subCoordinates));
3732:     PetscCall(PetscObjectGetName((PetscObject)coordinates, &name));
3733:     PetscCall(PetscObjectSetName((PetscObject)subCoordinates, name));
3734:     PetscCall(VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE));
3735:     PetscCall(VecSetBlockSize(subCoordinates, cdim));
3736:     PetscCall(VecSetType(subCoordinates, VECSTANDARD));
3737:     PetscCall(VecGetArray(coordinates, &coords));
3738:     PetscCall(VecGetArray(subCoordinates, &subCoords));
3739:     for (v = 0; v < numSubVertices; ++v) {
3740:       const PetscInt vertex    = subVertices[v];
3741:       const PetscInt subvertex = firstSubVertex + v;
3742:       PetscInt       dof, off, sdof, soff, d;

3744:       PetscCall(PetscSectionGetDof(coordSection, vertex, &dof));
3745:       PetscCall(PetscSectionGetOffset(coordSection, vertex, &off));
3746:       PetscCall(PetscSectionGetDof(subCoordSection, subvertex, &sdof));
3747:       PetscCall(PetscSectionGetOffset(subCoordSection, subvertex, &soff));
3748:       PetscCheck(dof == sdof, comm, PETSC_ERR_PLIB, "Coordinate dimension %" PetscInt_FMT " on subvertex %" PetscInt_FMT ", vertex %" PetscInt_FMT " should be %" PetscInt_FMT, sdof, subvertex, vertex, dof);
3749:       for (d = 0; d < dof; ++d) subCoords[soff + d] = coords[off + d];
3750:     }
3751:     PetscCall(VecRestoreArray(coordinates, &coords));
3752:     PetscCall(VecRestoreArray(subCoordinates, &subCoords));
3753:     PetscCall(DMSetCoordinatesLocal(subdm, subCoordinates));
3754:     PetscCall(VecDestroy(&subCoordinates));
3755:   }
3756:   /* Build SF */
3757:   CHKMEMQ;
3758:   {
3759:     PetscSF            sfPoint, sfPointSub;
3760:     const PetscSFNode *remotePoints;
3761:     PetscSFNode       *sremotePoints, *newLocalPoints, *newOwners;
3762:     const PetscInt    *localPoints;
3763:     PetscInt          *slocalPoints;
3764:     PetscInt           numRoots, numLeaves, numSubRoots = numSubCells + numSubFaces + numSubVertices, numSubLeaves = 0, l, sl, ll, pStart, pEnd, p, vStart, vEnd;
3765:     PetscMPIInt        rank;

3767:     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
3768:     PetscCall(DMGetPointSF(dm, &sfPoint));
3769:     PetscCall(DMGetPointSF(subdm, &sfPointSub));
3770:     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
3771:     PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
3772:     PetscCall(PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints));
3773:     if (numRoots >= 0) {
3774:       /* Only vertices should be shared */
3775:       PetscCall(PetscMalloc2(pEnd - pStart, &newLocalPoints, numRoots, &newOwners));
3776:       for (p = 0; p < pEnd - pStart; ++p) {
3777:         newLocalPoints[p].rank  = -2;
3778:         newLocalPoints[p].index = -2;
3779:       }
3780:       /* Set subleaves */
3781:       for (l = 0; l < numLeaves; ++l) {
3782:         const PetscInt point    = localPoints[l];
3783:         const PetscInt subPoint = DMPlexFilterPoint_Internal(point, firstSubVertex, numSubVertices, subVertices);

3785:         PetscCheck(!(point < vStart) || !(point >= vEnd), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Should not be mapping anything but vertices, %" PetscInt_FMT, point);
3786:         if (subPoint < 0) continue;
3787:         newLocalPoints[point - pStart].rank  = rank;
3788:         newLocalPoints[point - pStart].index = subPoint;
3789:         ++numSubLeaves;
3790:       }
3791:       /* Must put in owned subpoints */
3792:       for (p = pStart; p < pEnd; ++p) {
3793:         const PetscInt subPoint = DMPlexFilterPoint_Internal(p, firstSubVertex, numSubVertices, subVertices);

3795:         if (subPoint < 0) {
3796:           newOwners[p - pStart].rank  = -3;
3797:           newOwners[p - pStart].index = -3;
3798:         } else {
3799:           newOwners[p - pStart].rank  = rank;
3800:           newOwners[p - pStart].index = subPoint;
3801:         }
3802:       }
3803:       PetscCall(PetscSFReduceBegin(sfPoint, MPIU_2INT, newLocalPoints, newOwners, MPI_MAXLOC));
3804:       PetscCall(PetscSFReduceEnd(sfPoint, MPIU_2INT, newLocalPoints, newOwners, MPI_MAXLOC));
3805:       PetscCall(PetscSFBcastBegin(sfPoint, MPIU_2INT, newOwners, newLocalPoints, MPI_REPLACE));
3806:       PetscCall(PetscSFBcastEnd(sfPoint, MPIU_2INT, newOwners, newLocalPoints, MPI_REPLACE));
3807:       PetscCall(PetscMalloc1(numSubLeaves, &slocalPoints));
3808:       PetscCall(PetscMalloc1(numSubLeaves, &sremotePoints));
3809:       for (l = 0, sl = 0, ll = 0; l < numLeaves; ++l) {
3810:         const PetscInt point    = localPoints[l];
3811:         const PetscInt subPoint = DMPlexFilterPoint_Internal(point, firstSubVertex, numSubVertices, subVertices);

3813:         if (subPoint < 0) continue;
3814:         if (newLocalPoints[point].rank == rank) {
3815:           ++ll;
3816:           continue;
3817:         }
3818:         slocalPoints[sl]        = subPoint;
3819:         sremotePoints[sl].rank  = newLocalPoints[point].rank;
3820:         sremotePoints[sl].index = newLocalPoints[point].index;
3821:         PetscCheck(sremotePoints[sl].rank >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid remote rank for local point %" PetscInt_FMT, point);
3822:         PetscCheck(sremotePoints[sl].index >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid remote subpoint for local point %" PetscInt_FMT, point);
3823:         ++sl;
3824:       }
3825:       PetscCall(PetscFree2(newLocalPoints, newOwners));
3826:       PetscCheck(sl + ll == numSubLeaves, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Mismatch in number of subleaves %" PetscInt_FMT " + %" PetscInt_FMT " != %" PetscInt_FMT, sl, ll, numSubLeaves);
3827:       PetscCall(PetscSFSetGraph(sfPointSub, numSubRoots, sl, slocalPoints, PETSC_OWN_POINTER, sremotePoints, PETSC_OWN_POINTER));
3828:     }
3829:   }
3830:   CHKMEMQ;
3831:   /* Cleanup */
3832:   if (subvertexIS) PetscCall(ISRestoreIndices(subvertexIS, &subVertices));
3833:   PetscCall(ISDestroy(&subvertexIS));
3834:   PetscCall(PetscFree(subCells));
3835:   PetscFunctionReturn(PETSC_SUCCESS);
3836: }

3838: static PetscErrorCode DMPlexCreateCohesiveSubmesh_Interpolated(DM dm, const char labelname[], PetscInt value, DM subdm)
3839: {
3840:   DMLabel label = NULL;

3842:   PetscFunctionBegin;
3843:   if (labelname) PetscCall(DMGetLabel(dm, labelname, &label));
3844:   PetscCall(DMPlexCreateSubmeshGeneric_Interpolated(dm, label, value, PETSC_FALSE, PETSC_TRUE, 1, subdm));
3845:   PetscFunctionReturn(PETSC_SUCCESS);
3846: }

3848: /*@C
3849:   DMPlexCreateCohesiveSubmesh - Extract from a mesh with cohesive cells the hypersurface defined by one face of the cells. Optionally, a Label can be given to restrict the cells.

3851:   Input Parameters:
3852: + dm          - The original mesh
3853: . hasLagrange - The mesh has Lagrange unknowns in the cohesive cells
3854: . label       - A label name, or NULL
3855: - value  - A label value

3857:   Output Parameter:
3858: . subdm - The surface mesh

3860:   Note: This function produces a DMLabel mapping original points in the submesh to their depth. This can be obtained using DMPlexGetSubpointMap().

3862:   Level: developer

3864: .seealso: `DMPlexGetSubpointMap()`, `DMPlexCreateSubmesh()`
3865: @*/
3866: PetscErrorCode DMPlexCreateCohesiveSubmesh(DM dm, PetscBool hasLagrange, const char label[], PetscInt value, DM *subdm)
3867: {
3868:   PetscInt dim, cdim, depth;

3870:   PetscFunctionBegin;
3873:   PetscCall(DMGetDimension(dm, &dim));
3874:   PetscCall(DMPlexGetDepth(dm, &depth));
3875:   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), subdm));
3876:   PetscCall(DMSetType(*subdm, DMPLEX));
3877:   PetscCall(DMSetDimension(*subdm, dim - 1));
3878:   PetscCall(DMGetCoordinateDim(dm, &cdim));
3879:   PetscCall(DMSetCoordinateDim(*subdm, cdim));
3880:   if (depth == dim) {
3881:     PetscCall(DMPlexCreateCohesiveSubmesh_Interpolated(dm, label, value, *subdm));
3882:   } else {
3883:     PetscCall(DMPlexCreateCohesiveSubmesh_Uninterpolated(dm, hasLagrange, label, value, *subdm));
3884:   }
3885:   PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_TRUE, *subdm));
3886:   PetscFunctionReturn(PETSC_SUCCESS);
3887: }

3889: /*@
3890:   DMPlexFilter - Extract a subset of mesh cells defined by a label as a separate mesh

3892:   Input Parameters:
3893: + dm        - The original mesh
3894: . cellLabel - The DMLabel marking cells contained in the new mesh
3895: - value     - The label value to use

3897:   Output Parameter:
3898: . subdm - The new mesh

3900:   Notes:
3901:   This function produces a `DMLabel` mapping original points in the submesh to their depth. This can be obtained using `DMPlexGetSubpointMap()`.

3903:   Level: developer

3905: .seealso: `DMPlexGetSubpointMap()`, `DMGetLabel()`, `DMLabelSetValue()`, `DMPlexCreateSubmesh()`
3906: @*/
3907: PetscErrorCode DMPlexFilter(DM dm, DMLabel cellLabel, PetscInt value, DM *subdm)
3908: {
3909:   PetscInt dim, overlap;

3911:   PetscFunctionBegin;
3914:   PetscCall(DMGetDimension(dm, &dim));
3915:   PetscCall(DMCreate(PetscObjectComm((PetscObject)dm), subdm));
3916:   PetscCall(DMSetType(*subdm, DMPLEX));
3917:   /* Extract submesh in place, could be empty on some procs, could have inconsistency if procs do not both extract a shared cell */
3918:   PetscCall(DMPlexCreateSubmeshGeneric_Interpolated(dm, cellLabel, value, PETSC_FALSE, PETSC_FALSE, 0, *subdm));
3919:   PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_TRUE, *subdm));
3920:   // It is possible to obtain a surface mesh where some faces are in SF
3921:   //   We should either mark the mesh as having an overlap, or delete these from the SF
3922:   PetscCall(DMPlexGetOverlap(dm, &overlap));
3923:   if (!overlap) {
3924:     PetscSF         sf;
3925:     const PetscInt *leaves;
3926:     PetscInt        cStart, cEnd, Nl;
3927:     PetscBool       hasSubcell = PETSC_FALSE, ghasSubcell;

3929:     PetscCall(DMPlexGetHeightStratum(*subdm, 0, &cStart, &cEnd));
3930:     PetscCall(DMGetPointSF(*subdm, &sf));
3931:     PetscCall(PetscSFGetGraph(sf, NULL, &Nl, &leaves, NULL));
3932:     for (PetscInt l = 0; l < Nl; ++l) {
3933:       const PetscInt point = leaves ? leaves[l] : l;

3935:       if (point >= cStart && point < cEnd) {
3936:         hasSubcell = PETSC_TRUE;
3937:         break;
3938:       }
3939:     }
3940:     PetscCall(MPIU_Allreduce(&hasSubcell, &ghasSubcell, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm)));
3941:     if (ghasSubcell) PetscCall(DMPlexSetOverlap(*subdm, NULL, 1));
3942:   }
3943:   PetscFunctionReturn(PETSC_SUCCESS);
3944: }

3946: /*@
3947:   DMPlexGetSubpointMap - Returns a DMLabel with point dimension as values

3949:   Input Parameter:
3950: . dm - The submesh DM

3952:   Output Parameter:
3953: . subpointMap - The DMLabel of all the points from the original mesh in this submesh, or NULL if this is not a submesh

3955:   Level: developer

3957: .seealso: `DMPlexCreateSubmesh()`, `DMPlexGetSubpointIS()`
3958: @*/
3959: PetscErrorCode DMPlexGetSubpointMap(DM dm, DMLabel *subpointMap)
3960: {
3961:   PetscFunctionBegin;
3964:   *subpointMap = ((DM_Plex *)dm->data)->subpointMap;
3965:   PetscFunctionReturn(PETSC_SUCCESS);
3966: }

3968: /*@
3969:   DMPlexSetSubpointMap - Sets the DMLabel with point dimension as values

3971:   Input Parameters:
3972: + dm - The submesh DM
3973: - subpointMap - The DMLabel of all the points from the original mesh in this submesh

3975:   Note: Should normally not be called by the user, since it is set in DMPlexCreateSubmesh()

3977:   Level: developer

3979: .seealso: `DMPlexCreateSubmesh()`, `DMPlexGetSubpointIS()`
3980: @*/
3981: PetscErrorCode DMPlexSetSubpointMap(DM dm, DMLabel subpointMap)
3982: {
3983:   DM_Plex *mesh = (DM_Plex *)dm->data;
3984:   DMLabel  tmp;

3986:   PetscFunctionBegin;
3988:   tmp               = mesh->subpointMap;
3989:   mesh->subpointMap = subpointMap;
3990:   PetscCall(PetscObjectReference((PetscObject)mesh->subpointMap));
3991:   PetscCall(DMLabelDestroy(&tmp));
3992:   PetscFunctionReturn(PETSC_SUCCESS);
3993: }

3995: static PetscErrorCode DMPlexCreateSubpointIS_Internal(DM dm, IS *subpointIS)
3996: {
3997:   DMLabel  spmap;
3998:   PetscInt depth, d;

4000:   PetscFunctionBegin;
4001:   PetscCall(DMPlexGetSubpointMap(dm, &spmap));
4002:   PetscCall(DMPlexGetDepth(dm, &depth));
4003:   if (spmap && depth >= 0) {
4004:     DM_Plex  *mesh = (DM_Plex *)dm->data;
4005:     PetscInt *points, *depths;
4006:     PetscInt  pStart, pEnd, p, off;

4008:     PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
4009:     PetscCheck(!pStart, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Submeshes must start the point numbering at 0, not %" PetscInt_FMT, pStart);
4010:     PetscCall(PetscMalloc1(pEnd, &points));
4011:     PetscCall(DMGetWorkArray(dm, depth + 1, MPIU_INT, &depths));
4012:     depths[0] = depth;
4013:     depths[1] = 0;
4014:     for (d = 2; d <= depth; ++d) depths[d] = depth + 1 - d;
4015:     for (d = 0, off = 0; d <= depth; ++d) {
4016:       const PetscInt dep = depths[d];
4017:       PetscInt       depStart, depEnd, n;

4019:       PetscCall(DMPlexGetDepthStratum(dm, dep, &depStart, &depEnd));
4020:       PetscCall(DMLabelGetStratumSize(spmap, dep, &n));
4021:       if (((d < 2) && (depth > 1)) || (d == 1)) { /* Only check vertices and cells for now since the map is broken for others */
4022:         PetscCheck(n == depEnd - depStart, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of mapped submesh points %" PetscInt_FMT " at depth %" PetscInt_FMT " should be %" PetscInt_FMT, n, dep, depEnd - depStart);
4023:       } else {
4024:         if (!n) {
4025:           if (d == 0) {
4026:             /* Missing cells */
4027:             for (p = 0; p < depEnd - depStart; ++p, ++off) points[off] = -1;
4028:           } else {
4029:             /* Missing faces */
4030:             for (p = 0; p < depEnd - depStart; ++p, ++off) points[off] = PETSC_MAX_INT;
4031:           }
4032:         }
4033:       }
4034:       if (n) {
4035:         IS              is;
4036:         const PetscInt *opoints;

4038:         PetscCall(DMLabelGetStratumIS(spmap, dep, &is));
4039:         PetscCall(ISGetIndices(is, &opoints));
4040:         for (p = 0; p < n; ++p, ++off) points[off] = opoints[p];
4041:         PetscCall(ISRestoreIndices(is, &opoints));
4042:         PetscCall(ISDestroy(&is));
4043:       }
4044:     }
4045:     PetscCall(DMRestoreWorkArray(dm, depth + 1, MPIU_INT, &depths));
4046:     PetscCheck(off == pEnd, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The number of mapped submesh points %" PetscInt_FMT " should be %" PetscInt_FMT, off, pEnd);
4047:     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, pEnd, points, PETSC_OWN_POINTER, subpointIS));
4048:     PetscCall(PetscObjectStateGet((PetscObject)spmap, &mesh->subpointState));
4049:   }
4050:   PetscFunctionReturn(PETSC_SUCCESS);
4051: }

4053: /*@
4054:   DMPlexGetSubpointIS - Returns an IS covering the entire subdm chart with the original points as data

4056:   Input Parameter:
4057: . dm - The submesh DM

4059:   Output Parameter:
4060: . subpointIS - The IS of all the points from the original mesh in this submesh, or NULL if this is not a submesh

4062:   Note: This IS is guaranteed to be sorted by the construction of the submesh

4064:   Level: developer

4066: .seealso: `DMPlexCreateSubmesh()`, `DMPlexGetSubpointMap()`
4067: @*/
4068: PetscErrorCode DMPlexGetSubpointIS(DM dm, IS *subpointIS)
4069: {
4070:   DM_Plex         *mesh = (DM_Plex *)dm->data;
4071:   DMLabel          spmap;
4072:   PetscObjectState state;

4074:   PetscFunctionBegin;
4077:   PetscCall(DMPlexGetSubpointMap(dm, &spmap));
4078:   PetscCall(PetscObjectStateGet((PetscObject)spmap, &state));
4079:   if (state != mesh->subpointState || !mesh->subpointIS) PetscCall(DMPlexCreateSubpointIS_Internal(dm, &mesh->subpointIS));
4080:   *subpointIS = mesh->subpointIS;
4081:   PetscFunctionReturn(PETSC_SUCCESS);
4082: }

4084: /*@
4085:   DMGetEnclosureRelation - Get the relationship between dmA and dmB

4087:   Input Parameters:
4088: + dmA - The first DM
4089: - dmB - The second DM

4091:   Output Parameter:
4092: . rel - The relation of dmA to dmB

4094:   Level: intermediate

4096: .seealso: `DMGetEnclosurePoint()`
4097: @*/
4098: PetscErrorCode DMGetEnclosureRelation(DM dmA, DM dmB, DMEnclosureType *rel)
4099: {
4100:   DM       plexA, plexB, sdm;
4101:   DMLabel  spmap;
4102:   PetscInt pStartA, pEndA, pStartB, pEndB, NpA, NpB;

4104:   PetscFunctionBegin;
4106:   *rel = DM_ENC_NONE;
4107:   if (!dmA || !dmB) PetscFunctionReturn(PETSC_SUCCESS);
4110:   if (dmA == dmB) {
4111:     *rel = DM_ENC_EQUALITY;
4112:     PetscFunctionReturn(PETSC_SUCCESS);
4113:   }
4114:   PetscCall(DMConvert(dmA, DMPLEX, &plexA));
4115:   PetscCall(DMConvert(dmB, DMPLEX, &plexB));
4116:   PetscCall(DMPlexGetChart(plexA, &pStartA, &pEndA));
4117:   PetscCall(DMPlexGetChart(plexB, &pStartB, &pEndB));
4118:   /* Assumption 1: subDMs have smaller charts than the DMs that they originate from
4119:     - The degenerate case of a subdomain which includes all of the domain on some process can be treated as equality */
4120:   if ((pStartA == pStartB) && (pEndA == pEndB)) {
4121:     *rel = DM_ENC_EQUALITY;
4122:     goto end;
4123:   }
4124:   NpA = pEndA - pStartA;
4125:   NpB = pEndB - pStartB;
4126:   if (NpA == NpB) goto end;
4127:   sdm = NpA > NpB ? plexB : plexA; /* The other is the original, enclosing dm */
4128:   PetscCall(DMPlexGetSubpointMap(sdm, &spmap));
4129:   if (!spmap) goto end;
4130:   /* TODO Check the space mapped to by subpointMap is same size as dm */
4131:   if (NpA > NpB) {
4132:     *rel = DM_ENC_SUPERMESH;
4133:   } else {
4134:     *rel = DM_ENC_SUBMESH;
4135:   }
4136: end:
4137:   PetscCall(DMDestroy(&plexA));
4138:   PetscCall(DMDestroy(&plexB));
4139:   PetscFunctionReturn(PETSC_SUCCESS);
4140: }

4142: /*@
4143:   DMGetEnclosurePoint - Get the point pA in dmA which corresponds to the point pB in dmB

4145:   Input Parameters:
4146: + dmA   - The first DM
4147: . dmB   - The second DM
4148: . etype - The type of enclosure relation that dmA has to dmB
4149: - pB    - A point of dmB

4151:   Output Parameter:
4152: . pA    - The corresponding point of dmA

4154:   Level: intermediate

4156: .seealso: `DMGetEnclosureRelation()`
4157: @*/
4158: PetscErrorCode DMGetEnclosurePoint(DM dmA, DM dmB, DMEnclosureType etype, PetscInt pB, PetscInt *pA)
4159: {
4160:   DM              sdm;
4161:   IS              subpointIS;
4162:   const PetscInt *subpoints;
4163:   PetscInt        numSubpoints;

4165:   PetscFunctionBegin;
4166:   /* TODO Cache the IS, making it look like an index */
4167:   switch (etype) {
4168:   case DM_ENC_SUPERMESH:
4169:     sdm = dmB;
4170:     PetscCall(DMPlexGetSubpointIS(sdm, &subpointIS));
4171:     PetscCall(ISGetIndices(subpointIS, &subpoints));
4172:     *pA = subpoints[pB];
4173:     PetscCall(ISRestoreIndices(subpointIS, &subpoints));
4174:     break;
4175:   case DM_ENC_SUBMESH:
4176:     sdm = dmA;
4177:     PetscCall(DMPlexGetSubpointIS(sdm, &subpointIS));
4178:     PetscCall(ISGetLocalSize(subpointIS, &numSubpoints));
4179:     PetscCall(ISGetIndices(subpointIS, &subpoints));
4180:     PetscCall(PetscFindInt(pB, numSubpoints, subpoints, pA));
4181:     if (*pA < 0) {
4182:       PetscCall(DMViewFromOptions(dmA, NULL, "-dm_enc_A_view"));
4183:       PetscCall(DMViewFromOptions(dmB, NULL, "-dm_enc_B_view"));
4184:       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Point %" PetscInt_FMT " not found in submesh", pB);
4185:     }
4186:     PetscCall(ISRestoreIndices(subpointIS, &subpoints));
4187:     break;
4188:   case DM_ENC_EQUALITY:
4189:   case DM_ENC_NONE:
4190:     *pA = pB;
4191:     break;
4192:   case DM_ENC_UNKNOWN: {
4193:     DMEnclosureType enc;

4195:     PetscCall(DMGetEnclosureRelation(dmA, dmB, &enc));
4196:     PetscCall(DMGetEnclosurePoint(dmA, dmB, enc, pB, pA));
4197:   } break;
4198:   default:
4199:     SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Invalid enclosure type %d", (int)etype);
4200:   }
4201:   PetscFunctionReturn(PETSC_SUCCESS);
4202: }