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