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