xref: /petsc/src/dm/impls/plex/plexrefine.c (revision dcca6d9d80ebd869fe6029bd05a3aa9faafef49e)
1 #include <petsc-private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <petscsf.h>
3 
4 #undef __FUNCT__
5 #define __FUNCT__ "GetDepthStart_Private"
6 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
7 {
8   PetscFunctionBegin;
9   if (cStart) *cStart = 0;
10   if (vStart) *vStart = depthSize[depth];
11   if (fStart) *fStart = depthSize[depth] + depthSize[0];
12   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
13   PetscFunctionReturn(0);
14 }
15 
16 #undef __FUNCT__
17 #define __FUNCT__ "GetDepthEnd_Private"
18 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
19 {
20   PetscFunctionBegin;
21   if (cEnd) *cEnd = depthSize[depth];
22   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
23   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
24   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
25   PetscFunctionReturn(0);
26 }
27 
28 #undef __FUNCT__
29 #define __FUNCT__ "CellRefinerGetSizes"
30 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
31 {
32   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
33   PetscErrorCode ierr;
34 
35   PetscFunctionBegin;
36   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
37   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
38   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
39   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
40   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
41   switch (refiner) {
42   case 0:
43     break;
44   case 1:
45     /* Simplicial 2D */
46     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
47     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
48     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
49     break;
50   case 3:
51     /* Hybrid Simplicial 2D */
52     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
53     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
54     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
55     depthSize[1] = 2*(fMax - fStart) + 3*(cMax - cStart) + (fEnd - fMax) + (cEnd - cMax); /* Every interior face is split into 2 faces, 3 faces are added for each interior cell, and one in each hybrid cell */
56     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
57     break;
58   case 2:
59     /* Hex 2D */
60     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
61     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
62     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
63     break;
64   case 5:
65     /* Simplicial 3D */
66     depthSize[0] =    vEnd - vStart  +    eEnd - eStart;                    /* Add a vertex on every edge */
67     depthSize[1] = 2*(eEnd - eStart) + 3*(fEnd - fStart) + (cEnd - cStart); /* Every edge is split into 2 edges, 3 edges are added for each face, and 1 edge for each cell */
68     depthSize[2] = 4*(fEnd - fStart) + 8*(cEnd - cStart);                   /* Every face split into 4 faces and 8 faces are added for each cell */
69     depthSize[3] = 8*(cEnd - cStart);                                       /* Every cell split into 8 cells */
70     break;
71   case 7:
72     /* Hybrid Simplicial 3D */
73     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
74     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
75     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
76     /* Tetrahedra */
77     depthSize[0]  =    vEnd - vStart  +    eMax - eStart;                    /* Add a vertex on every interior edge */
78     depthSize[1]  = 2*(eMax - eStart) + 3*(fMax - fStart) + (cMax - cStart); /* Every interior edge split into 2 edges, 3 edges added for each interior face, 1 edge for each interior cell */
79     depthSize[2]  = 4*(fMax - fStart) + 8*(cMax - cStart);                   /* Every interior face split into 4 faces, 8 faces added for each interior cell */
80     depthSize[3]  = 8*(cMax - cStart);                                       /* Every interior cell split into 8 cells */
81     /* Triangular Prisms */
82     depthSize[0] += 0;                                                       /* No hybrid vertices */
83     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax);                     /* Every hybrid edge remains, 1 edge for every hybrid face */
84     depthSize[2] += 2*(fEnd - fMax)   + 3*(cEnd - cMax);                     /* Every hybrid face split into 2 faces and 3 faces are added for each hybrid cell */
85     depthSize[3] += 4*(cEnd - cMax);                                         /* Every hybrid cell split into 4 cells */
86     break;
87   case 6:
88     /* Hex 3D */
89     depthSize[0] = vEnd - vStart + eEnd - eStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every edge, face and cell */
90     depthSize[1] = 2*(eEnd - eStart) +  4*(fEnd - fStart) + 6*(cEnd - cStart);    /* Every edge is split into 2 edge, 4 edges are added for each face, and 6 edges for each cell */
91     depthSize[2] = 4*(fEnd - fStart) + 12*(cEnd - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
92     depthSize[3] = 8*(cEnd - cStart);                                             /* Every cell split into 8 cells */
93     break;
94   default:
95     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
96   }
97   PetscFunctionReturn(0);
98 }
99 
100 /* Return triangle edge for orientation o, if it is r for o == 0 */
101 PETSC_STATIC_INLINE PetscInt GetTriEdge_Static(PetscInt o, PetscInt r) {
102   return (o < 0 ? 2-(o+r) : o+r)%3;
103 }
104 
105 /* Return triangle subface for orientation o, if it is r for o == 0 */
106 PETSC_STATIC_INLINE PetscInt GetTriSubface_Static(PetscInt o, PetscInt r) {
107   return (o < 0 ? 3-(o+r) : o+r)%3;
108 }
109 
110 /* Return quad edge for orientation o, if it is r for o == 0 */
111 PETSC_STATIC_INLINE PetscInt GetQuadEdge_Static(PetscInt o, PetscInt r) {
112   return (o < 0 ? 3-(o+r) : o+r)%4;
113 }
114 
115 /* Return quad subface for orientation o, if it is r for o == 0 */
116 PETSC_STATIC_INLINE PetscInt GetQuadSubface_Static(PetscInt o, PetscInt r) {
117   return (o < 0 ? 4-(o+r) : o+r)%4;
118 }
119 
120 #undef __FUNCT__
121 #define __FUNCT__ "CellRefinerSetConeSizes"
122 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
123 {
124   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, e, r;
125   PetscErrorCode ierr;
126 
127   PetscFunctionBegin;
128   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
129   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
130   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
131   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
132   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
133   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
134   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
135   switch (refiner) {
136   case 0: break;
137   case 1:
138     /* Simplicial 2D */
139     /* All cells have 3 faces */
140     for (c = cStart; c < cEnd; ++c) {
141       for (r = 0; r < 4; ++r) {
142         const PetscInt newp = (c - cStart)*4 + r;
143 
144         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
145       }
146     }
147     /* Split faces have 2 vertices and the same cells as the parent */
148     for (f = fStart; f < fEnd; ++f) {
149       for (r = 0; r < 2; ++r) {
150         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
151         PetscInt       size;
152 
153         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
154         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
155         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
156       }
157     }
158     /* Interior faces have 2 vertices and 2 cells */
159     for (c = cStart; c < cEnd; ++c) {
160       for (r = 0; r < 3; ++r) {
161         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
162 
163         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
164         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
165       }
166     }
167     /* Old vertices have identical supports */
168     for (v = vStart; v < vEnd; ++v) {
169       const PetscInt newp = vStartNew + (v - vStart);
170       PetscInt       size;
171 
172       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
173       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
174     }
175     /* Face vertices have 2 + cells*2 supports */
176     for (f = fStart; f < fEnd; ++f) {
177       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
178       PetscInt       size;
179 
180       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
181       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
182     }
183     break;
184   case 2:
185     /* Hex 2D */
186     /* All cells have 4 faces */
187     for (c = cStart; c < cEnd; ++c) {
188       for (r = 0; r < 4; ++r) {
189         const PetscInt newp = (c - cStart)*4 + r;
190 
191         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
192       }
193     }
194     /* Split faces have 2 vertices and the same cells as the parent */
195     for (f = fStart; f < fEnd; ++f) {
196       for (r = 0; r < 2; ++r) {
197         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
198         PetscInt       size;
199 
200         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
201         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
202         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
203       }
204     }
205     /* Interior faces have 2 vertices and 2 cells */
206     for (c = cStart; c < cEnd; ++c) {
207       for (r = 0; r < 4; ++r) {
208         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
209 
210         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
211         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
212       }
213     }
214     /* Old vertices have identical supports */
215     for (v = vStart; v < vEnd; ++v) {
216       const PetscInt newp = vStartNew + (v - vStart);
217       PetscInt       size;
218 
219       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
220       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
221     }
222     /* Face vertices have 2 + cells supports */
223     for (f = fStart; f < fEnd; ++f) {
224       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
225       PetscInt       size;
226 
227       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
228       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
229     }
230     /* Cell vertices have 4 supports */
231     for (c = cStart; c < cEnd; ++c) {
232       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
233 
234       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
235     }
236     break;
237   case 3:
238     /* Hybrid Simplicial 2D */
239     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
240     cMax = PetscMin(cEnd, cMax);
241     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
242     fMax = PetscMin(fEnd, fMax);
243     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
244     /* Interior cells have 3 faces */
245     for (c = cStart; c < cMax; ++c) {
246       for (r = 0; r < 4; ++r) {
247         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
248 
249         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
250       }
251     }
252     /* Hybrid cells have 4 faces */
253     for (c = cMax; c < cEnd; ++c) {
254       for (r = 0; r < 2; ++r) {
255         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
256 
257         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
258       }
259     }
260     /* Interior split faces have 2 vertices and the same cells as the parent */
261     for (f = fStart; f < fMax; ++f) {
262       for (r = 0; r < 2; ++r) {
263         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
264         PetscInt       size;
265 
266         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
267         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
268         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
269       }
270     }
271     /* Interior cell faces have 2 vertices and 2 cells */
272     for (c = cStart; c < cMax; ++c) {
273       for (r = 0; r < 3; ++r) {
274         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
275 
276         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
277         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
278       }
279     }
280     /* Hybrid faces have 2 vertices and the same cells */
281     for (f = fMax; f < fEnd; ++f) {
282       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
283       PetscInt       size;
284 
285       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
286       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
287       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
288     }
289     /* Hybrid cell faces have 2 vertices and 2 cells */
290     for (c = cMax; c < cEnd; ++c) {
291       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
292 
293       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
294       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
295     }
296     /* Old vertices have identical supports */
297     for (v = vStart; v < vEnd; ++v) {
298       const PetscInt newp = vStartNew + (v - vStart);
299       PetscInt       size;
300 
301       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
302       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
303     }
304     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
305     for (f = fStart; f < fMax; ++f) {
306       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
307       const PetscInt *support;
308       PetscInt       size, newSize = 2, s;
309 
310       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
311       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
312       for (s = 0; s < size; ++s) {
313         if (support[s] >= cMax) newSize += 1;
314         else newSize += 2;
315       }
316       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
317     }
318     break;
319   case 5:
320     /* Simplicial 3D */
321     /* All cells have 4 faces */
322     for (c = cStart; c < cEnd; ++c) {
323       for (r = 0; r < 8; ++r) {
324         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
325 
326         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
327       }
328     }
329     /* Split faces have 3 edges and the same cells as the parent */
330     for (f = fStart; f < fEnd; ++f) {
331       for (r = 0; r < 4; ++r) {
332         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
333         PetscInt       size;
334 
335         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
336         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
337         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
338       }
339     }
340     /* Interior faces have 3 edges and 2 cells */
341     for (c = cStart; c < cEnd; ++c) {
342       for (r = 0; r < 8; ++r) {
343         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + r;
344 
345         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
346         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
347       }
348     }
349     /* Split edges have 2 vertices and the same faces */
350     for (e = eStart; e < eEnd; ++e) {
351       for (r = 0; r < 2; ++r) {
352         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
353         PetscInt       size;
354 
355         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
356         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
357         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
358       }
359     }
360     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
361     for (f = fStart; f < fEnd; ++f) {
362       for (r = 0; r < 3; ++r) {
363         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
364         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
365         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;
366 
367         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
368         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
369         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
370         for (s = 0; s < supportSize; ++s) {
371           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
372           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
373           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
374           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
375           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
376           er = ornt[c] < 0 ? (-(ornt[c]+1) + 2-r)%3 : (ornt[c] + r)%3;
377           if (er == eint[c]) {
378             intFaces += 1;
379           } else {
380             intFaces += 2;
381           }
382         }
383         ierr = DMPlexSetSupportSize(rdm, newp, 2+intFaces);CHKERRQ(ierr);
384       }
385     }
386     /* Interior edges have 2 vertices and 4 faces */
387     for (c = cStart; c < cEnd; ++c) {
388       const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
389 
390       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
391       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
392     }
393     /* Old vertices have identical supports */
394     for (v = vStart; v < vEnd; ++v) {
395       const PetscInt newp = vStartNew + (v - vStart);
396       PetscInt       size;
397 
398       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
399       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
400     }
401     /* Edge vertices have 2 + faces*2 + cells*0/1 supports */
402     for (e = eStart; e < eEnd; ++e) {
403       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
404       PetscInt       size, *star = NULL, starSize, s, cellSize = 0;
405 
406       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
407       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
408       for (s = 0; s < starSize*2; s += 2) {
409         const PetscInt *cone, *ornt;
410         PetscInt        e01, e23;
411 
412         if ((star[s] >= cStart) && (star[s] < cEnd)) {
413           /* Check edge 0-1 */
414           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
415           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
416           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
417           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
418           /* Check edge 2-3 */
419           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
420           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
421           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
422           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
423           if ((e01 == e) || (e23 == e)) ++cellSize;
424         }
425       }
426       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
427       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2 + cellSize);CHKERRQ(ierr);
428     }
429     break;
430   case 7:
431     /* Hybrid Simplicial 3D */
432     ierr = DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 8*(cMax - cStart),
433                                  eStartNew + 2*(eMax - eStart) + 3*(fMax - fStart) + (cMax - cStart), PETSC_DETERMINE);CHKERRQ(ierr);
434     /* Interior cells have 4 faces */
435     for (c = cStart; c < cMax; ++c) {
436       for (r = 0; r < 8; ++r) {
437         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
438 
439         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
440       }
441     }
442     /* Hybrid cells have 5 faces */
443     for (c = cMax; c < cEnd; ++c) {
444       for (r = 0; r < 4; ++r) {
445         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;
446 
447         ierr = DMPlexSetConeSize(rdm, newp, 5);CHKERRQ(ierr);
448       }
449     }
450     /* Interior split faces have 3 edges and the same cells as the parent */
451     for (f = fStart; f < fMax; ++f) {
452       for (r = 0; r < 4; ++r) {
453         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
454         PetscInt       size;
455 
456         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
457         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
458         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
459       }
460     }
461     /* Interior cell faces have 3 edges and 2 cells */
462     for (c = cStart; c < cMax; ++c) {
463       for (r = 0; r < 8; ++r) {
464         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + r;
465 
466         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
467         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
468       }
469     }
470     /* Hybrid split faces have 4 edges and the same cells as the parent */
471     for (f = fMax; f < fEnd; ++f) {
472       for (r = 0; r < 2; ++r) {
473         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
474         PetscInt       size;
475 
476         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
477         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
478         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
479       }
480     }
481     /* Hybrid cells faces have 4 edges and 2 cells */
482     for (c = cMax; c < cEnd; ++c) {
483       for (r = 0; r < 3; ++r) {
484         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + r;
485 
486         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
487         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
488       }
489     }
490     /* Interior split edges have 2 vertices and the same faces */
491     for (e = eStart; e < eMax; ++e) {
492       for (r = 0; r < 2; ++r) {
493         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
494         PetscInt       size;
495 
496         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
497         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
498         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
499       }
500     }
501     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
502     for (f = fStart; f < fMax; ++f) {
503       for (r = 0; r < 3; ++r) {
504         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
505         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
506         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;
507 
508         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
509         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
510         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
511         for (s = 0; s < supportSize; ++s) {
512           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
513           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
514           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
515           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
516           if (support[s] < cMax) {
517             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
518             er = ornt[c] < 0 ? (-(ornt[c]+1) + 2-r)%3 : (ornt[c] + r)%3;
519             if (er == eint[c]) {
520               intFaces += 1;
521             } else {
522               intFaces += 2;
523             }
524           } else {
525             intFaces += 1;
526           }
527         }
528         ierr = DMPlexSetSupportSize(rdm, newp, 2+intFaces);CHKERRQ(ierr);
529       }
530     }
531     /* Interior cell edges have 2 vertices and 4 faces */
532     for (c = cStart; c < cMax; ++c) {
533       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
534 
535       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
536       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
537     }
538     /* Hybrid edges have 2 vertices and the same faces */
539     for (e = eMax; e < eEnd; ++e) {
540       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
541       PetscInt       size;
542 
543       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
544       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
545       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
546     }
547     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
548     for (f = fMax; f < fEnd; ++f) {
549       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
550       PetscInt       size;
551 
552       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
553       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
554       ierr = DMPlexSetSupportSize(rdm, newp, 2+2*size);CHKERRQ(ierr);
555     }
556     /* Interior vertices have identical supports */
557     for (v = vStart; v < vEnd; ++v) {
558       const PetscInt newp = vStartNew + (v - vStart);
559       PetscInt       size;
560 
561       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
562       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
563     }
564     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
565     for (e = eStart; e < eMax; ++e) {
566       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
567       const PetscInt *support;
568       PetscInt        size, *star = NULL, starSize, s, faceSize = 0, cellSize = 0;
569 
570       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
571       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
572       for (s = 0; s < size; ++s) {
573         if (support[s] < fMax) faceSize += 2;
574         else                   faceSize += 1;
575       }
576       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
577       for (s = 0; s < starSize*2; s += 2) {
578         const PetscInt *cone, *ornt;
579         PetscInt        e01, e23;
580 
581         if ((star[s] >= cStart) && (star[s] < cMax)) {
582           /* Check edge 0-1 */
583           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
584           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
585           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
586           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
587           /* Check edge 2-3 */
588           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
589           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
590           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
591           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
592           if ((e01 == e) || (e23 == e)) ++cellSize;
593         }
594       }
595       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
596       ierr = DMPlexSetSupportSize(rdm, newp, 2 + faceSize + cellSize);CHKERRQ(ierr);
597     }
598     break;
599   case 6:
600     /* Hex 3D */
601     /* All cells have 6 faces */
602     for (c = cStart; c < cEnd; ++c) {
603       for (r = 0; r < 8; ++r) {
604         const PetscInt newp = (c - cStart)*8 + r;
605 
606         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
607       }
608     }
609     /* Split faces have 4 edges and the same cells as the parent */
610     for (f = fStart; f < fEnd; ++f) {
611       for (r = 0; r < 4; ++r) {
612         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
613         PetscInt       size;
614 
615         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
616         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
617         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
618       }
619     }
620     /* Interior faces have 4 edges and 2 cells */
621     for (c = cStart; c < cEnd; ++c) {
622       for (r = 0; r < 12; ++r) {
623         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
624 
625         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
626         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
627       }
628     }
629     /* Split edges have 2 vertices and the same faces as the parent */
630     for (e = eStart; e < eEnd; ++e) {
631       for (r = 0; r < 2; ++r) {
632         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
633         PetscInt       size;
634 
635         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
636         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
637         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
638       }
639     }
640     /* Face edges have 2 vertices and 2+cells faces */
641     for (f = fStart; f < fEnd; ++f) {
642       for (r = 0; r < 4; ++r) {
643         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
644         PetscInt       size;
645 
646         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
647         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
648         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
649       }
650     }
651     /* Cell edges have 2 vertices and 4 faces */
652     for (c = cStart; c < cEnd; ++c) {
653       for (r = 0; r < 6; ++r) {
654         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
655 
656         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
657         ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
658       }
659     }
660     /* Old vertices have identical supports */
661     for (v = vStart; v < vEnd; ++v) {
662       const PetscInt newp = vStartNew + (v - vStart);
663       PetscInt       size;
664 
665       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
666       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
667     }
668     /* Edge vertices have 2 + faces supports */
669     for (e = eStart; e < eEnd; ++e) {
670       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
671       PetscInt       size;
672 
673       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
674       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
675     }
676     /* Face vertices have 4 + cells supports */
677     for (f = fStart; f < fEnd; ++f) {
678       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
679       PetscInt       size;
680 
681       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
682       ierr = DMPlexSetSupportSize(rdm, newp, 4 + size);CHKERRQ(ierr);
683     }
684     /* Cell vertices have 6 supports */
685     for (c = cStart; c < cEnd; ++c) {
686       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
687 
688       ierr = DMPlexSetSupportSize(rdm, newp, 6);CHKERRQ(ierr);
689     }
690     break;
691   default:
692     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
693   }
694   PetscFunctionReturn(0);
695 }
696 
697 #undef __FUNCT__
698 #define __FUNCT__ "CellRefinerSetCones"
699 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
700 {
701   const PetscInt *faces, cellInd[4] = {0, 1, 2, 3};
702   PetscInt        cStart,    cEnd,    cMax,    vStart,    vEnd, vMax, fStart,    fEnd,    fMax,    eStart,    eEnd,    eMax;
703   PetscInt        cStartNew, cEndNew, cMaxNew, vStartNew, vEndNew,    fStartNew, fEndNew, fMaxNew, eStartNew, eEndNew, eMaxNew;
704   PetscInt        depth, maxSupportSize, *supportRef, c, f, e, v, r, p;
705   PetscErrorCode  ierr;
706 
707   PetscFunctionBegin;
708   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
709   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
710   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
711   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
712   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
713   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
714   if (refiner) {
715     ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
716     ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
717   }
718   switch (refiner) {
719   case 0: break;
720   case 1:
721     /* Simplicial 2D */
722     /*
723      2
724      |\
725      | \
726      |  \
727      |   \
728      | C  \
729      |     \
730      |      \
731      2---1---1
732      |\  D  / \
733      | 2   0   \
734      |A \ /  B  \
735      0---0-------1
736      */
737     /* All cells have 3 faces */
738     for (c = cStart; c < cEnd; ++c) {
739       const PetscInt  newp = cStartNew + (c - cStart)*4;
740       const PetscInt *cone, *ornt;
741       PetscInt        coneNew[3], orntNew[3];
742 
743       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
744       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
745       /* A triangle */
746       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
747       orntNew[0] = ornt[0];
748       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
749       orntNew[1] = -2;
750       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
751       orntNew[2] = ornt[2];
752       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
753       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
754 #if 1
755       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
756       for (p = 0; p < 3; ++p) {
757         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
758       }
759 #endif
760       /* B triangle */
761       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
762       orntNew[0] = ornt[0];
763       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
764       orntNew[1] = ornt[1];
765       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
766       orntNew[2] = -2;
767       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
768       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
769 #if 1
770       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
771       for (p = 0; p < 3; ++p) {
772         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
773       }
774 #endif
775       /* C triangle */
776       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
777       orntNew[0] = -2;
778       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
779       orntNew[1] = ornt[1];
780       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
781       orntNew[2] = ornt[2];
782       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
783       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
784 #if 1
785       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
786       for (p = 0; p < 3; ++p) {
787         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
788       }
789 #endif
790       /* D triangle */
791       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
792       orntNew[0] = 0;
793       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
794       orntNew[1] = 0;
795       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
796       orntNew[2] = 0;
797       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
798       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
799 #if 1
800       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
801       for (p = 0; p < 3; ++p) {
802         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
803       }
804 #endif
805     }
806     /* Split faces have 2 vertices and the same cells as the parent */
807     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
808     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
809     for (f = fStart; f < fEnd; ++f) {
810       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
811 
812       for (r = 0; r < 2; ++r) {
813         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
814         const PetscInt *cone, *ornt, *support;
815         PetscInt        coneNew[2], coneSize, c, supportSize, s;
816 
817         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
818         coneNew[0]       = vStartNew + (cone[0] - vStart);
819         coneNew[1]       = vStartNew + (cone[1] - vStart);
820         coneNew[(r+1)%2] = newv;
821         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
822 #if 1
823         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
824         for (p = 0; p < 2; ++p) {
825           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
826         }
827 #endif
828         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
829         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
830         for (s = 0; s < supportSize; ++s) {
831           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
832           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
833           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
834           for (c = 0; c < coneSize; ++c) {
835             if (cone[c] == f) break;
836           }
837           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
838         }
839         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
840 #if 1
841         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
842         for (p = 0; p < supportSize; ++p) {
843           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
844         }
845 #endif
846       }
847     }
848     /* Interior faces have 2 vertices and 2 cells */
849     for (c = cStart; c < cEnd; ++c) {
850       const PetscInt *cone;
851 
852       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
853       for (r = 0; r < 3; ++r) {
854         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
855         PetscInt       coneNew[2];
856         PetscInt       supportNew[2];
857 
858         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
859         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
860         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
861 #if 1
862         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
863         for (p = 0; p < 2; ++p) {
864           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
865         }
866 #endif
867         supportNew[0] = (c - cStart)*4 + (r+1)%3;
868         supportNew[1] = (c - cStart)*4 + 3;
869         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
870 #if 1
871         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
872         for (p = 0; p < 2; ++p) {
873           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
874         }
875 #endif
876       }
877     }
878     /* Old vertices have identical supports */
879     for (v = vStart; v < vEnd; ++v) {
880       const PetscInt  newp = vStartNew + (v - vStart);
881       const PetscInt *support, *cone;
882       PetscInt        size, s;
883 
884       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
885       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
886       for (s = 0; s < size; ++s) {
887         PetscInt r = 0;
888 
889         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
890         if (cone[1] == v) r = 1;
891         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
892       }
893       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
894 #if 1
895       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
896       for (p = 0; p < size; ++p) {
897         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
898       }
899 #endif
900     }
901     /* Face vertices have 2 + cells*2 supports */
902     for (f = fStart; f < fEnd; ++f) {
903       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
904       const PetscInt *cone, *support;
905       PetscInt        size, s;
906 
907       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
908       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
909       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
910       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
911       for (s = 0; s < size; ++s) {
912         PetscInt r = 0;
913 
914         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
915         if      (cone[1] == f) r = 1;
916         else if (cone[2] == f) r = 2;
917         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
918         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
919       }
920       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
921 #if 1
922       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
923       for (p = 0; p < 2+size*2; ++p) {
924         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
925       }
926 #endif
927     }
928     ierr = PetscFree(supportRef);CHKERRQ(ierr);
929     break;
930   case 2:
931     /* Hex 2D */
932     /*
933      3---------2---------2
934      |         |         |
935      |    D    2    C    |
936      |         |         |
937      3----3----0----1----1
938      |         |         |
939      |    A    0    B    |
940      |         |         |
941      0---------0---------1
942      */
943     /* All cells have 4 faces */
944     for (c = cStart; c < cEnd; ++c) {
945       const PetscInt  newp = (c - cStart)*4;
946       const PetscInt *cone, *ornt;
947       PetscInt        coneNew[4], orntNew[4];
948 
949       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
950       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
951       /* A quad */
952       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
953       orntNew[0] = ornt[0];
954       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
955       orntNew[1] = 0;
956       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
957       orntNew[2] = -2;
958       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
959       orntNew[3] = ornt[3];
960       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
961       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
962 #if 1
963       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
964       for (p = 0; p < 4; ++p) {
965         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
966       }
967 #endif
968       /* B quad */
969       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
970       orntNew[0] = ornt[0];
971       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
972       orntNew[1] = ornt[1];
973       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
974       orntNew[2] = 0;
975       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
976       orntNew[3] = -2;
977       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
978       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
979 #if 1
980       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
981       for (p = 0; p < 4; ++p) {
982         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
983       }
984 #endif
985       /* C quad */
986       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
987       orntNew[0] = -2;
988       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
989       orntNew[1] = ornt[1];
990       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
991       orntNew[2] = ornt[2];
992       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
993       orntNew[3] = 0;
994       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
995       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
996 #if 1
997       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
998       for (p = 0; p < 4; ++p) {
999         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1000       }
1001 #endif
1002       /* D quad */
1003       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
1004       orntNew[0] = 0;
1005       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
1006       orntNew[1] = -2;
1007       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1008       orntNew[2] = ornt[2];
1009       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
1010       orntNew[3] = ornt[3];
1011       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1012       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1013 #if 1
1014       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
1015       for (p = 0; p < 4; ++p) {
1016         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1017       }
1018 #endif
1019     }
1020     /* Split faces have 2 vertices and the same cells as the parent */
1021     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1022     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
1023     for (f = fStart; f < fEnd; ++f) {
1024       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1025 
1026       for (r = 0; r < 2; ++r) {
1027         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1028         const PetscInt *cone, *ornt, *support;
1029         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1030 
1031         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1032         coneNew[0]       = vStartNew + (cone[0] - vStart);
1033         coneNew[1]       = vStartNew + (cone[1] - vStart);
1034         coneNew[(r+1)%2] = newv;
1035         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1036 #if 1
1037         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1038         for (p = 0; p < 2; ++p) {
1039           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
1040         }
1041 #endif
1042         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1043         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1044         for (s = 0; s < supportSize; ++s) {
1045           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1046           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1047           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1048           for (c = 0; c < coneSize; ++c) {
1049             if (cone[c] == f) break;
1050           }
1051           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
1052         }
1053         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1054 #if 1
1055         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1056         for (p = 0; p < supportSize; ++p) {
1057           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
1058         }
1059 #endif
1060       }
1061     }
1062     /* Interior faces have 2 vertices and 2 cells */
1063     for (c = cStart; c < cEnd; ++c) {
1064       const PetscInt *cone;
1065       PetscInt        coneNew[2], supportNew[2];
1066 
1067       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1068       for (r = 0; r < 4; ++r) {
1069         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
1070 
1071         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
1072         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
1073         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1074 #if 1
1075         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1076         for (p = 0; p < 2; ++p) {
1077           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
1078         }
1079 #endif
1080         supportNew[0] = (c - cStart)*4 + r;
1081         supportNew[1] = (c - cStart)*4 + (r+1)%4;
1082         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1083 #if 1
1084         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1085         for (p = 0; p < 2; ++p) {
1086           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
1087         }
1088 #endif
1089       }
1090     }
1091     /* Old vertices have identical supports */
1092     for (v = vStart; v < vEnd; ++v) {
1093       const PetscInt  newp = vStartNew + (v - vStart);
1094       const PetscInt *support, *cone;
1095       PetscInt        size, s;
1096 
1097       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1098       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1099       for (s = 0; s < size; ++s) {
1100         PetscInt r = 0;
1101 
1102         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1103         if (cone[1] == v) r = 1;
1104         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1105       }
1106       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1107 #if 1
1108       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1109       for (p = 0; p < size; ++p) {
1110         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
1111       }
1112 #endif
1113     }
1114     /* Face vertices have 2 + cells supports */
1115     for (f = fStart; f < fEnd; ++f) {
1116       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1117       const PetscInt *cone, *support;
1118       PetscInt        size, s;
1119 
1120       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1121       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1122       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1123       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1124       for (s = 0; s < size; ++s) {
1125         PetscInt r = 0;
1126 
1127         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1128         if      (cone[1] == f) r = 1;
1129         else if (cone[2] == f) r = 2;
1130         else if (cone[3] == f) r = 3;
1131         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
1132       }
1133       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1134 #if 1
1135       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1136       for (p = 0; p < 2+size; ++p) {
1137         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
1138       }
1139 #endif
1140     }
1141     /* Cell vertices have 4 supports */
1142     for (c = cStart; c < cEnd; ++c) {
1143       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
1144       PetscInt       supportNew[4];
1145 
1146       for (r = 0; r < 4; ++r) {
1147         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
1148       }
1149       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1150     }
1151     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1152     break;
1153   case 3:
1154     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
1155     cMax = PetscMin(cEnd, cMax);
1156     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
1157     fMax = PetscMin(fEnd, fMax);
1158     /* Interior cells have 3 faces */
1159     for (c = cStart; c < cMax; ++c) {
1160       const PetscInt  newp = cStartNew + (c - cStart)*4;
1161       const PetscInt *cone, *ornt;
1162       PetscInt        coneNew[3], orntNew[3];
1163 
1164       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1165       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1166       /* A triangle */
1167       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1168       orntNew[0] = ornt[0];
1169       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
1170       orntNew[1] = -2;
1171       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1172       orntNew[2] = ornt[2];
1173       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1174       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1175 #if 1
1176       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
1177       for (p = 0; p < 3; ++p) {
1178         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1179       }
1180 #endif
1181       /* B triangle */
1182       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1183       orntNew[0] = ornt[0];
1184       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1185       orntNew[1] = ornt[1];
1186       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
1187       orntNew[2] = -2;
1188       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1189       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1190 #if 1
1191       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
1192       for (p = 0; p < 3; ++p) {
1193         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1194       }
1195 #endif
1196       /* C triangle */
1197       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
1198       orntNew[0] = -2;
1199       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1200       orntNew[1] = ornt[1];
1201       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1202       orntNew[2] = ornt[2];
1203       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1204       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1205 #if 1
1206       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
1207       for (p = 0; p < 3; ++p) {
1208         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1209       }
1210 #endif
1211       /* D triangle */
1212       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
1213       orntNew[0] = 0;
1214       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
1215       orntNew[1] = 0;
1216       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
1217       orntNew[2] = 0;
1218       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1219       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1220 #if 1
1221       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
1222       for (p = 0; p < 3; ++p) {
1223         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1224       }
1225 #endif
1226     }
1227     /*
1228      2----3----3
1229      |         |
1230      |    B    |
1231      |         |
1232      0----4--- 1
1233      |         |
1234      |    A    |
1235      |         |
1236      0----2----1
1237      */
1238     /* Hybrid cells have 4 faces */
1239     for (c = cMax; c < cEnd; ++c) {
1240       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
1241       const PetscInt *cone, *ornt;
1242       PetscInt        coneNew[4], orntNew[4];
1243 
1244       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1245       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1246       /* A quad */
1247       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1248       orntNew[0] = ornt[0];
1249       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1250       orntNew[1] = ornt[1];
1251       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
1252       orntNew[2] = 0;
1253       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
1254       orntNew[3] = 0;
1255       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1256       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1257 #if 1
1258       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
1259       for (p = 0; p < 4; ++p) {
1260         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1261       }
1262 #endif
1263       /* B quad */
1264       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1265       orntNew[0] = ornt[0];
1266       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1267       orntNew[1] = ornt[1];
1268       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
1269       orntNew[2] = 0;
1270       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
1271       orntNew[3] = 0;
1272       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1273       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1274 #if 1
1275       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
1276       for (p = 0; p < 4; ++p) {
1277         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1278       }
1279 #endif
1280     }
1281     /* Interior split faces have 2 vertices and the same cells as the parent */
1282     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1283     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
1284     for (f = fStart; f < fMax; ++f) {
1285       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1286 
1287       for (r = 0; r < 2; ++r) {
1288         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1289         const PetscInt *cone, *ornt, *support;
1290         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1291 
1292         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1293         coneNew[0]       = vStartNew + (cone[0] - vStart);
1294         coneNew[1]       = vStartNew + (cone[1] - vStart);
1295         coneNew[(r+1)%2] = newv;
1296         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1297 #if 1
1298         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1299         for (p = 0; p < 2; ++p) {
1300           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
1301         }
1302 #endif
1303         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1304         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1305         for (s = 0; s < supportSize; ++s) {
1306           if (support[s] >= cMax) {
1307             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
1308           } else {
1309             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1310             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1311             ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1312             for (c = 0; c < coneSize; ++c) {
1313               if (cone[c] == f) break;
1314             }
1315             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1316           }
1317         }
1318         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1319 #if 1
1320         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1321         for (p = 0; p < supportSize; ++p) {
1322           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
1323         }
1324 #endif
1325       }
1326     }
1327     /* Interior cell faces have 2 vertices and 2 cells */
1328     for (c = cStart; c < cMax; ++c) {
1329       const PetscInt *cone;
1330 
1331       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1332       for (r = 0; r < 3; ++r) {
1333         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
1334         PetscInt       coneNew[2];
1335         PetscInt       supportNew[2];
1336 
1337         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
1338         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
1339         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1340 #if 1
1341         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1342         for (p = 0; p < 2; ++p) {
1343           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
1344         }
1345 #endif
1346         supportNew[0] = (c - cStart)*4 + (r+1)%3;
1347         supportNew[1] = (c - cStart)*4 + 3;
1348         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1349 #if 1
1350         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1351         for (p = 0; p < 2; ++p) {
1352           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
1353         }
1354 #endif
1355       }
1356     }
1357     /* Interior hybrid faces have 2 vertices and the same cells */
1358     for (f = fMax; f < fEnd; ++f) {
1359       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
1360       const PetscInt *cone;
1361       const PetscInt *support;
1362       PetscInt        coneNew[2];
1363       PetscInt        supportNew[2];
1364       PetscInt        size, s, r;
1365 
1366       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1367       coneNew[0] = vStartNew + (cone[0] - vStart);
1368       coneNew[1] = vStartNew + (cone[1] - vStart);
1369       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1370 #if 1
1371       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1372       for (p = 0; p < 2; ++p) {
1373         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
1374       }
1375 #endif
1376       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1377       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1378       for (s = 0; s < size; ++s) {
1379         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1380         for (r = 0; r < 2; ++r) {
1381           if (cone[r+2] == f) break;
1382         }
1383         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
1384       }
1385       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1386 #if 1
1387       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1388       for (p = 0; p < size; ++p) {
1389         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
1390       }
1391 #endif
1392     }
1393     /* Cell hybrid faces have 2 vertices and 2 cells */
1394     for (c = cMax; c < cEnd; ++c) {
1395       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
1396       const PetscInt *cone;
1397       PetscInt        coneNew[2];
1398       PetscInt        supportNew[2];
1399 
1400       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1401       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
1402       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
1403       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1404 #if 1
1405       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1406       for (p = 0; p < 2; ++p) {
1407         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
1408       }
1409 #endif
1410       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
1411       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
1412       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1413 #if 1
1414       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1415       for (p = 0; p < 2; ++p) {
1416         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
1417       }
1418 #endif
1419     }
1420     /* Old vertices have identical supports */
1421     for (v = vStart; v < vEnd; ++v) {
1422       const PetscInt  newp = vStartNew + (v - vStart);
1423       const PetscInt *support, *cone;
1424       PetscInt        size, s;
1425 
1426       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1427       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1428       for (s = 0; s < size; ++s) {
1429         if (support[s] >= fMax) {
1430           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
1431         } else {
1432           PetscInt r = 0;
1433 
1434           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1435           if (cone[1] == v) r = 1;
1436           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1437         }
1438       }
1439       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1440 #if 1
1441       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1442       for (p = 0; p < size; ++p) {
1443         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
1444       }
1445 #endif
1446     }
1447     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
1448     for (f = fStart; f < fMax; ++f) {
1449       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1450       const PetscInt *cone, *support;
1451       PetscInt        size, newSize = 2, s;
1452 
1453       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1454       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1455       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1456       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1457       for (s = 0; s < size; ++s) {
1458         PetscInt r = 0;
1459 
1460         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1461         if (support[s] >= cMax) {
1462           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
1463 
1464           newSize += 1;
1465         } else {
1466           if      (cone[1] == f) r = 1;
1467           else if (cone[2] == f) r = 2;
1468           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
1469           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
1470 
1471           newSize += 2;
1472         }
1473       }
1474       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1475 #if 1
1476       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1477       for (p = 0; p < newSize; ++p) {
1478         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
1479       }
1480 #endif
1481     }
1482     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1483     break;
1484   case 5:
1485     /* Simplicial 3D */
1486     /* All cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
1487     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
1488     for (c = cStart; c < cEnd; ++c) {
1489       const PetscInt  newp = cStartNew + (c - cStart)*8;
1490       const PetscInt *cone, *ornt;
1491       PetscInt        coneNew[4], orntNew[4];
1492 
1493       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1494       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1495       /* A tetrahedron: {0, a, c, d} */
1496       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
1497       orntNew[0] = ornt[0];
1498       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
1499       orntNew[1] = ornt[1];
1500       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
1501       orntNew[2] = ornt[2];
1502       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
1503       orntNew[3] = 0;
1504       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1505       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1506 #if 1
1507       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
1508       for (p = 0; p < 4; ++p) {
1509         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1510       }
1511 #endif
1512       /* B tetrahedron: {a, 1, b, e} */
1513       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
1514       orntNew[0] = ornt[0];
1515       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
1516       orntNew[1] = ornt[1];
1517       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
1518       orntNew[2] = 0;
1519       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
1520       orntNew[3] = ornt[3];
1521       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1522       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1523 #if 1
1524       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
1525       for (p = 0; p < 4; ++p) {
1526         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1527       }
1528 #endif
1529       /* C tetrahedron: {c, b, 2, f} */
1530       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
1531       orntNew[0] = ornt[0];
1532       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
1533       orntNew[1] = 0;
1534       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
1535       orntNew[2] = ornt[2];
1536       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
1537       orntNew[3] = ornt[3];
1538       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1539       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1540 #if 1
1541       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
1542       for (p = 0; p < 4; ++p) {
1543         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1544       }
1545 #endif
1546       /* D tetrahedron: {d, e, f, 3} */
1547       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
1548       orntNew[0] = 0;
1549       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
1550       orntNew[1] = ornt[1];
1551       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
1552       orntNew[2] = ornt[2];
1553       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
1554       orntNew[3] = ornt[3];
1555       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1556       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1557 #if 1
1558       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
1559       for (p = 0; p < 4; ++p) {
1560         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1561       }
1562 #endif
1563       /* A' tetrahedron: {d, a, c, f} */
1564       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
1565       orntNew[0] = -3;
1566       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
1567       orntNew[1] = 0;
1568       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + 3;
1569       orntNew[2] = ornt[2] < 0 ? -((-(ornt[2]+1)+2)%3+1) : (ornt[2]+2)%3;
1570       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
1571       orntNew[3] = 0;
1572       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
1573       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
1574 #if 1
1575       if ((newp+4 < cStartNew) || (newp+4 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+4, cStartNew, cEndNew);
1576       for (p = 0; p < 4; ++p) {
1577         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1578       }
1579 #endif
1580       /* B' tetrahedron: {e, b, a, f} */
1581       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
1582       orntNew[0] = -3;
1583       coneNew[1] = fStartNew + (cone[3] - fStart)*4 + 3;
1584       orntNew[1] = ornt[3] < 0 ? -((-(ornt[3]+1)+1)%3+1) : (ornt[3]+1)%3;
1585       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
1586       orntNew[2] = 0;
1587       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
1588       orntNew[3] = 0;
1589       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
1590       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
1591 #if 1
1592       if ((newp+5 < cStartNew) || (newp+5 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+5, cStartNew, cEndNew);
1593       for (p = 0; p < 4; ++p) {
1594         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1595       }
1596 #endif
1597       /* C' tetrahedron: {b, f, c, a} */
1598       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
1599       orntNew[0] = -3;
1600       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
1601       orntNew[1] = -2;
1602       coneNew[2] = fStartNew + (cone[0] - fStart)*4 + 3;
1603       orntNew[2] = ornt[0] < 0 ? (-(ornt[0]+1)+1)%3 : -((ornt[0]+1)%3+1);
1604       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
1605       orntNew[3] = -1;
1606       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
1607       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
1608 #if 1
1609       if ((newp+6 < cStartNew) || (newp+6 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+6, cStartNew, cEndNew);
1610       for (p = 0; p < 4; ++p) {
1611         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1612       }
1613 #endif
1614       /* D' tetrahedron: {f, e, d, a} */
1615       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
1616       orntNew[0] = -3;
1617       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
1618       orntNew[1] = -3;
1619       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
1620       orntNew[2] = -2;
1621       coneNew[3] = fStartNew + (cone[1] - fStart)*4 + 3;
1622       orntNew[3] = ornt[2];
1623       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
1624       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
1625 #if 1
1626       if ((newp+7 < cStartNew) || (newp+7 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+7, cStartNew, cEndNew);
1627       for (p = 0; p < 4; ++p) {
1628         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1629       }
1630 #endif
1631     }
1632     /* Split faces have 3 edges and the same cells as the parent */
1633     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1634     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
1635     for (f = fStart; f < fEnd; ++f) {
1636       const PetscInt  newp = fStartNew + (f - fStart)*4;
1637       const PetscInt *cone, *ornt, *support;
1638       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
1639 
1640       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1641       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
1642       /* A triangle */
1643       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
1644       orntNew[0] = ornt[0];
1645       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
1646       orntNew[1] = -2;
1647       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
1648       orntNew[2] = ornt[2];
1649       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1650       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1651 #if 1
1652       if ((newp+0 < fStartNew) || (newp+0 >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+0, fStartNew, fEndNew);
1653       for (p = 0; p < 3; ++p) {
1654         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
1655       }
1656 #endif
1657       /* B triangle */
1658       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
1659       orntNew[0] = ornt[0];
1660       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
1661       orntNew[1] = ornt[1];
1662       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
1663       orntNew[2] = -2;
1664       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1665       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1666 #if 1
1667       if ((newp+1 < fStartNew) || (newp+1 >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+1, fStartNew, fEndNew);
1668       for (p = 0; p < 3; ++p) {
1669         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
1670       }
1671 #endif
1672       /* C triangle */
1673       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
1674       orntNew[0] = -2;
1675       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
1676       orntNew[1] = ornt[1];
1677       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
1678       orntNew[2] = ornt[2];
1679       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1680       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1681 #if 1
1682       if ((newp+2 < fStartNew) || (newp+2 >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+2, fStartNew, fEndNew);
1683       for (p = 0; p < 3; ++p) {
1684         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
1685       }
1686 #endif
1687       /* D triangle */
1688       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
1689       orntNew[0] = 0;
1690       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
1691       orntNew[1] = 0;
1692       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
1693       orntNew[2] = 0;
1694       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1695       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1696 #if 1
1697       if ((newp+3 < fStartNew) || (newp+3 >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+3, fStartNew, fEndNew);
1698       for (p = 0; p < 3; ++p) {
1699         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
1700       }
1701 #endif
1702       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1703       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1704       for (r = 0; r < 4; ++r) {
1705         for (s = 0; s < supportSize; ++s) {
1706           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1707           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1708           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1709           for (c = 0; c < coneSize; ++c) {
1710             if (cone[c] == f) break;
1711           }
1712           supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : (ornt[c] < 0 ? faces[c*3+(-(ornt[c]+1)+1+3-r)%3] : faces[c*3+r]));
1713         }
1714         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
1715 #if 1
1716         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1717         for (p = 0; p < supportSize; ++p) {
1718           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
1719         }
1720 #endif
1721       }
1722     }
1723     /* Interior faces have 3 edges and 2 cells */
1724     for (c = cStart; c < cEnd; ++c) {
1725       PetscInt        newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8;
1726       const PetscInt *cone, *ornt;
1727       PetscInt        coneNew[3], orntNew[3];
1728       PetscInt        supportNew[2];
1729 
1730       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1731       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1732       /* Face A: {c, a, d} */
1733       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + (ornt[0] < 0 ? (-(ornt[0]+1)+0)%3 : (ornt[0]+2)%3);
1734       orntNew[0] = ornt[0] < 0 ? -2 : 0;
1735       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + (ornt[1] < 0 ? (-(ornt[1]+1)+0)%3 : (ornt[1]+2)%3);
1736       orntNew[1] = ornt[1] < 0 ? -2 : 0;
1737       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + (ornt[2] < 0 ? (-(ornt[2]+1)+0)%3 : (ornt[2]+2)%3);
1738       orntNew[2] = ornt[2] < 0 ? -2 : 0;
1739       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1740       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
1741 #if 1
1742       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1743       for (p = 0; p < 3; ++p) {
1744         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
1745       }
1746 #endif
1747       supportNew[0] = (c - cStart)*8 + 0;
1748       supportNew[1] = (c - cStart)*8 + 0+4;
1749       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1750 #if 1
1751       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1752       for (p = 0; p < 2; ++p) {
1753         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
1754       }
1755 #endif
1756       ++newp;
1757       /* Face B: {a, b, e} */
1758       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + (ornt[0] < 0 ? (-(ornt[0]+1)+2)%3 : (ornt[0]+0)%3);
1759       orntNew[0] = ornt[0] < 0 ? -2 : 0;
1760       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + (ornt[3] < 0 ? (-(ornt[3]+1)+2)%3 : (ornt[3]+0)%3);
1761       orntNew[1] = ornt[3] < 0 ? -2 : 0;
1762       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + (ornt[1] < 0 ? (-(ornt[1]+1)+1)%3 : (ornt[1]+1)%3);
1763       orntNew[2] = ornt[1] < 0 ? -2 : 0;
1764       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1765       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
1766 #if 1
1767       if ((newp+1 < fStartNew) || (newp+1 >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+1, fStartNew, fEndNew);
1768       for (p = 0; p < 3; ++p) {
1769         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
1770       }
1771 #endif
1772       supportNew[0] = (c - cStart)*8 + 1;
1773       supportNew[1] = (c - cStart)*8 + 1+4;
1774       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1775 #if 1
1776       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1777       for (p = 0; p < 2; ++p) {
1778         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
1779       }
1780 #endif
1781       ++newp;
1782       /* Face C: {c, f, b} */
1783       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + (ornt[2] < 0 ? (-(ornt[2]+1)+2)%3 : (ornt[2]+0)%3);
1784       orntNew[0] = ornt[2] < 0 ? -2 : 0;
1785       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + (ornt[3] < 0 ? (-(ornt[3]+1)+0)%3 : (ornt[3]+2)%3);
1786       orntNew[1] = ornt[3] < 0 ? -2 : 0;
1787       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + (ornt[0] < 0 ? (-(ornt[0]+1)+1)%3 : (ornt[0]+1)%3);
1788       orntNew[2] = ornt[0] < 0 ? -2 : 0;
1789       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1790       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
1791 #if 1
1792       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1793       for (p = 0; p < 3; ++p) {
1794         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
1795       }
1796 #endif
1797       supportNew[0] = (c - cStart)*8 + 2;
1798       supportNew[1] = (c - cStart)*8 + 2+4;
1799       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1800 #if 1
1801       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1802       for (p = 0; p < 2; ++p) {
1803         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
1804       }
1805 #endif
1806       ++newp;
1807       /* Face D: {d, e, f} */
1808       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + (ornt[1] < 0 ? (-(ornt[1]+1)+2)%3 : (ornt[1]+0)%3);
1809       orntNew[0] = ornt[1] < 0 ? -2 : 0;
1810       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + (ornt[3] < 0 ? (-(ornt[3]+1)+1)%3 : (ornt[3]+1)%3);
1811       orntNew[1] = ornt[3] < 0 ? -2 : 0;
1812       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + (ornt[2] < 0 ? (-(ornt[2]+1)+1)%3 : (ornt[2]+1)%3);
1813       orntNew[2] = ornt[2] < 0 ? -2 : 0;
1814       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1815       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
1816 #if 1
1817       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1818       for (p = 0; p < 3; ++p) {
1819         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
1820       }
1821 #endif
1822       supportNew[0] = (c - cStart)*8 + 3;
1823       supportNew[1] = (c - cStart)*8 + 3+4;
1824       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1825 #if 1
1826       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1827       for (p = 0; p < 2; ++p) {
1828         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
1829       }
1830 #endif
1831       ++newp;
1832       /* Face E: {d, f, a} */
1833       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + (ornt[2] < 0 ? (-(ornt[2]+1)+1)%3 : (ornt[2]+1)%3);
1834       orntNew[0] = ornt[2] < 0 ? 0 : -2;
1835       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
1836       orntNew[1] = 0;
1837       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + (ornt[1] < 0 ? (-(ornt[1]+1)+0)%3 : (ornt[1]+2)%3);
1838       orntNew[2] = ornt[1] < 0 ? -2 : 0;
1839       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1840       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
1841 #if 1
1842       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1843       for (p = 0; p < 3; ++p) {
1844         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
1845       }
1846 #endif
1847       supportNew[0] = (c - cStart)*8 + 0+4;
1848       supportNew[1] = (c - cStart)*8 + 3+4;
1849       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1850 #if 1
1851       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1852       for (p = 0; p < 2; ++p) {
1853         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
1854       }
1855 #endif
1856       ++newp;
1857       /* Face F: {c, a, f} */
1858       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + (ornt[0] < 0 ? (-(ornt[0]+1)+0)%3 : (ornt[0]+2)%3);
1859       orntNew[0] = ornt[0] < 0 ? -2 : 0;
1860       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
1861       orntNew[1] = -2;
1862       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + (ornt[2] < 0 ? (-(ornt[2]+1)+2)%3 : (ornt[2]+0)%3);
1863       orntNew[2] = ornt[1] < 0 ? 0 : -2;
1864       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1865       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
1866 #if 1
1867       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1868       for (p = 0; p < 3; ++p) {
1869         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
1870       }
1871 #endif
1872       supportNew[0] = (c - cStart)*8 + 0+4;
1873       supportNew[1] = (c - cStart)*8 + 2+4;
1874       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1875 #if 1
1876       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1877       for (p = 0; p < 2; ++p) {
1878         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
1879       }
1880 #endif
1881       ++newp;
1882       /* Face G: {e, a, f} */
1883       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + (ornt[1] < 0 ? (-(ornt[1]+1)+1)%3 : (ornt[1]+1)%3);
1884       orntNew[0] = ornt[1] < 0 ? -2 : 0;
1885       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
1886       orntNew[1] = -2;
1887       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + (ornt[3] < 0 ? (-(ornt[3]+1)+1)%3 : (ornt[3]+1)%3);
1888       orntNew[2] = ornt[3] < 0 ? 0 : -2;
1889       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1890       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
1891 #if 1
1892       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1893       for (p = 0; p < 3; ++p) {
1894         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
1895       }
1896 #endif
1897       supportNew[0] = (c - cStart)*8 + 1+4;
1898       supportNew[1] = (c - cStart)*8 + 3+4;
1899       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1900 #if 1
1901       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1902       for (p = 0; p < 2; ++p) {
1903         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
1904       }
1905 #endif
1906       ++newp;
1907       /* Face H: {a, b, f} */
1908       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + (ornt[0] < 0 ? (-(ornt[0]+1)+2)%3 : (ornt[0]+0)%3);
1909       orntNew[0] = ornt[0] < 0 ? -2 : 0;
1910       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + (ornt[3] < 0 ? (-(ornt[3]+1)+0)%3 : (ornt[3]+2)%3);
1911       orntNew[1] = ornt[3] < 0 ? 0 : -2;
1912       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
1913       orntNew[2] = 0;
1914       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1915       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
1916 #if 1
1917       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1918       for (p = 0; p < 3; ++p) {
1919         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
1920       }
1921 #endif
1922       supportNew[0] = (c - cStart)*8 + 1+4;
1923       supportNew[1] = (c - cStart)*8 + 2+4;
1924       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1925 #if 1
1926       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1927       for (p = 0; p < 2; ++p) {
1928         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
1929       }
1930 #endif
1931       ++newp;
1932     }
1933     /* Split Edges have 2 vertices and the same faces as the parent */
1934     for (e = eStart; e < eEnd; ++e) {
1935       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
1936 
1937       for (r = 0; r < 2; ++r) {
1938         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
1939         const PetscInt *cone, *ornt, *support;
1940         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1941 
1942         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
1943         coneNew[0]       = vStartNew + (cone[0] - vStart);
1944         coneNew[1]       = vStartNew + (cone[1] - vStart);
1945         coneNew[(r+1)%2] = newv;
1946         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1947 #if 1
1948         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
1949         for (p = 0; p < 2; ++p) {
1950           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
1951         }
1952 #endif
1953         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
1954         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
1955         for (s = 0; s < supportSize; ++s) {
1956           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1957           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1958           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1959           for (c = 0; c < coneSize; ++c) {
1960             if (cone[c] == e) break;
1961           }
1962           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
1963         }
1964         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1965 #if 1
1966         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
1967         for (p = 0; p < supportSize; ++p) {
1968           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
1969         }
1970 #endif
1971       }
1972     }
1973     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
1974     for (f = fStart; f < fEnd; ++f) {
1975       const PetscInt *cone, *ornt, *support;
1976       PetscInt        coneSize, supportSize, s;
1977 
1978       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1979       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1980       for (r = 0; r < 3; ++r) {
1981         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
1982         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
1983         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
1984                                     -1, -1,  1,  6,  0,  4,
1985                                      2,  5,  3,  4, -1, -1,
1986                                     -1, -1,  3,  6,  2,  7};
1987 
1988         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1989         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
1990         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
1991         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1992 #if 1
1993         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
1994         for (p = 0; p < 2; ++p) {
1995           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
1996         }
1997 #endif
1998         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
1999         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
2000         for (s = 0; s < supportSize; ++s) {
2001           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2002           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2003           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2004           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
2005           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
2006           er   = ornt[c] < 0 ? (-(ornt[c]+1) + 2-r)%3 : (ornt[c] + r)%3;
2007           if (er == eint[c]) {
2008             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
2009           } else {
2010             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
2011             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
2012           }
2013         }
2014         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2015 #if 1
2016         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2017         for (p = 0; p < intFaces; ++p) {
2018           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
2019         }
2020 #endif
2021       }
2022     }
2023     /* Interior edges have 2 vertices and 4 faces */
2024     for (c = cStart; c < cEnd; ++c) {
2025       const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2026       const PetscInt *cone, *ornt, *fcone;
2027       PetscInt        coneNew[2], supportNew[4], find;
2028 
2029       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2030       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2031       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
2032       find = GetTriEdge_Static(ornt[0], 0);
2033       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
2034       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
2035       find = GetTriEdge_Static(ornt[2], 1);
2036       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
2037       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2038 #if 1
2039       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2040       for (p = 0; p < 2; ++p) {
2041         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2042       }
2043 #endif
2044       supportNew[0] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 4;
2045       supportNew[1] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 5;
2046       supportNew[2] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 6;
2047       supportNew[3] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 7;
2048       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2049 #if 1
2050       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2051       for (p = 0; p < 4; ++p) {
2052         if ((supportNew[p] < fStartNew) || (supportNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportNew[p], fStartNew, fEndNew);
2053       }
2054 #endif
2055     }
2056     /* Old vertices have identical supports */
2057     for (v = vStart; v < vEnd; ++v) {
2058       const PetscInt  newp = vStartNew + (v - vStart);
2059       const PetscInt *support, *cone;
2060       PetscInt        size, s;
2061 
2062       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2063       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2064       for (s = 0; s < size; ++s) {
2065         PetscInt r = 0;
2066 
2067         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2068         if (cone[1] == v) r = 1;
2069         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
2070       }
2071       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2072 #if 1
2073       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2074       for (p = 0; p < size; ++p) {
2075         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
2076       }
2077 #endif
2078     }
2079     /* Edge vertices have 2 + face*2 + 0/1 supports */
2080     for (e = eStart; e < eEnd; ++e) {
2081       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
2082       const PetscInt *cone, *support;
2083       PetscInt       *star = NULL, starSize, cellSize = 0, coneSize, size, s;
2084 
2085       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
2086       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
2087       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
2088       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
2089       for (s = 0; s < size; ++s) {
2090         PetscInt r = 0;
2091 
2092         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2093         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2094         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
2095         supportRef[2+s*2+0] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
2096         supportRef[2+s*2+1] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
2097       }
2098       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
2099       for (s = 0; s < starSize*2; s += 2) {
2100         const PetscInt *cone, *ornt;
2101         PetscInt        e01, e23;
2102 
2103         if ((star[s] >= cStart) && (star[s] < cEnd)) {
2104           /* Check edge 0-1 */
2105           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
2106           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
2107           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
2108           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
2109           /* Check edge 2-3 */
2110           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
2111           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
2112           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
2113           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
2114           if ((e01 == e) || (e23 == e)) {supportRef[2+size*2+cellSize++] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (star[s] - cStart);}
2115         }
2116       }
2117       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
2118       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2119 #if 1
2120       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2121       for (p = 0; p < 2+size*2+cellSize; ++p) {
2122         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
2123       }
2124 #endif
2125     }
2126     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2127     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
2128     break;
2129   case 7:
2130     /* Hybrid Simplicial 3D */
2131     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
2132     /* Interior cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
2133     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
2134     for (c = cStart; c < cMax; ++c) {
2135       const PetscInt  newp = cStartNew + (c - cStart)*8;
2136       const PetscInt *cone, *ornt;
2137       PetscInt        coneNew[4], orntNew[4];
2138 
2139       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2140       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2141       /* A tetrahedron: {0, a, c, d} */
2142       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
2143       orntNew[0] = ornt[0];
2144       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
2145       orntNew[1] = ornt[1];
2146       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
2147       orntNew[2] = ornt[2];
2148       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
2149       orntNew[3] = 0;
2150       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2151       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2152 #if 1
2153       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cMaxNew);
2154       for (p = 0; p < 4; ++p) {
2155         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2156       }
2157 #endif
2158       /* B tetrahedron: {a, 1, b, e} */
2159       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
2160       orntNew[0] = ornt[0];
2161       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
2162       orntNew[1] = ornt[1];
2163       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
2164       orntNew[2] = 0;
2165       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
2166       orntNew[3] = ornt[3];
2167       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2168       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2169 #if 1
2170       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cMaxNew);
2171       for (p = 0; p < 4; ++p) {
2172         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2173       }
2174 #endif
2175       /* C tetrahedron: {c, b, 2, f} */
2176       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
2177       orntNew[0] = ornt[0];
2178       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
2179       orntNew[1] = 0;
2180       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
2181       orntNew[2] = ornt[2];
2182       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
2183       orntNew[3] = ornt[3];
2184       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2185       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2186 #if 1
2187       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cMaxNew);
2188       for (p = 0; p < 4; ++p) {
2189         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2190       }
2191 #endif
2192       /* D tetrahedron: {d, e, f, 3} */
2193       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
2194       orntNew[0] = 0;
2195       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
2196       orntNew[1] = ornt[1];
2197       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
2198       orntNew[2] = ornt[2];
2199       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
2200       orntNew[3] = ornt[3];
2201       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2202       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2203 #if 1
2204       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cMaxNew);
2205       for (p = 0; p < 4; ++p) {
2206         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2207       }
2208 #endif
2209       /* A' tetrahedron: {d, a, c, f} */
2210       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
2211       orntNew[0] = -3;
2212       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
2213       orntNew[1] = 0;
2214       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + 3;
2215       orntNew[2] = ornt[2] < 0 ? -((-(ornt[2]+1)+2)%3+1) : (ornt[2]+2)%3;
2216       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
2217       orntNew[3] = 0;
2218       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
2219       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
2220 #if 1
2221       if ((newp+4 < cStartNew) || (newp+4 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+4, cStartNew, cMaxNew);
2222       for (p = 0; p < 4; ++p) {
2223         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2224       }
2225 #endif
2226       /* B' tetrahedron: {e, b, a, f} */
2227       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
2228       orntNew[0] = -3;
2229       coneNew[1] = fStartNew + (cone[3] - fStart)*4 + 3;
2230       orntNew[1] = ornt[3] < 0 ? -((-(ornt[3]+1)+1)%3+1) : (ornt[3]+1)%3;
2231       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
2232       orntNew[2] = 0;
2233       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
2234       orntNew[3] = 0;
2235       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
2236       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
2237 #if 1
2238       if ((newp+5 < cStartNew) || (newp+5 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+5, cStartNew, cMaxNew);
2239       for (p = 0; p < 4; ++p) {
2240         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2241       }
2242 #endif
2243       /* C' tetrahedron: {b, f, c, a} */
2244       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
2245       orntNew[0] = -3;
2246       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
2247       orntNew[1] = -2;
2248       coneNew[2] = fStartNew + (cone[0] - fStart)*4 + 3;
2249       orntNew[2] = ornt[0] < 0 ? (-(ornt[0]+1)+1)%3 : -((ornt[0]+1)%3+1);
2250       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
2251       orntNew[3] = -1;
2252       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
2253       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
2254 #if 1
2255       if ((newp+6 < cStartNew) || (newp+6 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+6, cStartNew, cMaxNew);
2256       for (p = 0; p < 4; ++p) {
2257         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2258       }
2259 #endif
2260       /* D' tetrahedron: {f, e, d, a} */
2261       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
2262       orntNew[0] = -3;
2263       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
2264       orntNew[1] = -3;
2265       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
2266       orntNew[2] = -2;
2267       coneNew[3] = fStartNew + (cone[1] - fStart)*4 + 3;
2268       orntNew[3] = ornt[2];
2269       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
2270       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
2271 #if 1
2272       if ((newp+7 < cStartNew) || (newp+7 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+7, cStartNew, cMaxNew);
2273       for (p = 0; p < 4; ++p) {
2274         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2275       }
2276 #endif
2277     }
2278     /* Hybrid cells have 5 faces */
2279     for (c = cMax; c < cEnd; ++c) {
2280       const PetscInt  newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4;
2281       const PetscInt *cone, *ornt;
2282       PetscInt        coneNew[5], orntNew[5];
2283 
2284       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2285       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2286       for (r = 0; r < 3; ++r) {
2287         coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], r);
2288         orntNew[0] = ornt[0];
2289         coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], r);
2290         orntNew[1] = ornt[1];
2291         coneNew[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriSubface_Static(ornt[0], (r+2)%3)] - fMax)*2 + (ornt[2+GetTriSubface_Static(ornt[0], (r+2)%3)] < 0 ? 0 : 1);
2292         orntNew[2] = 0;
2293         coneNew[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriSubface_Static(ornt[0], r)]       - fMax)*2 + (ornt[2+GetTriSubface_Static(ornt[0], r)]       < 0 ? 1 : 0);
2294         orntNew[3] = 0;
2295         coneNew[4] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + GetTriSubface_Static(ornt[0], r);
2296         orntNew[4] = 0;
2297         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
2298         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
2299 #if 1
2300         if ((newp+r < cMaxNew) || (newp+r >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", newp+r, cMaxNew, cEndNew);
2301         for (p = 0; p < 2; ++p) {
2302           if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2303         }
2304         for (p = 2; p < 5; ++p) {
2305           if ((coneNew[p] < fMaxNew)   || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", coneNew[p], fMaxNew, fEndNew);
2306         }
2307 #endif
2308       }
2309       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + 3;
2310       orntNew[0] = 0;
2311       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + 3;
2312       orntNew[1] = 0;
2313       coneNew[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
2314       orntNew[2] = 0;
2315       coneNew[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
2316       orntNew[3] = 0;
2317       coneNew[4] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
2318       orntNew[4] = 0;
2319       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2320       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2321 #if 1
2322       if ((newp+3 < cMaxNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", newp+3, cMaxNew, cEndNew);
2323       for (p = 0; p < 2; ++p) {
2324         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2325       }
2326       for (p = 2; p < 5; ++p) {
2327         if ((coneNew[p] < fMaxNew)   || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", coneNew[p], fMaxNew, fEndNew);
2328       }
2329 #endif
2330     }
2331     /* Split faces have 3 edges and the same cells as the parent */
2332     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2333     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
2334     for (f = fStart; f < fMax; ++f) {
2335       const PetscInt  newp = fStartNew + (f - fStart)*4;
2336       const PetscInt *cone, *ornt, *support;
2337       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
2338 
2339       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2340       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
2341       /* A triangle */
2342       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
2343       orntNew[0] = ornt[0];
2344       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
2345       orntNew[1] = -2;
2346       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
2347       orntNew[2] = ornt[2];
2348       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2349       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2350 #if 1
2351       if ((newp+0 < fStartNew) || (newp+0 >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+0, fStartNew, fMaxNew);
2352       for (p = 0; p < 3; ++p) {
2353         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
2354       }
2355 #endif
2356       /* B triangle */
2357       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
2358       orntNew[0] = ornt[0];
2359       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
2360       orntNew[1] = ornt[1];
2361       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
2362       orntNew[2] = -2;
2363       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2364       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2365 #if 1
2366       if ((newp+1 < fStartNew) || (newp+1 >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+1, fStartNew, fMaxNew);
2367       for (p = 0; p < 3; ++p) {
2368         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
2369       }
2370 #endif
2371       /* C triangle */
2372       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
2373       orntNew[0] = -2;
2374       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
2375       orntNew[1] = ornt[1];
2376       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
2377       orntNew[2] = ornt[2];
2378       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2379       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2380 #if 1
2381       if ((newp+2 < fStartNew) || (newp+2 >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+2, fStartNew, fMaxNew);
2382       for (p = 0; p < 3; ++p) {
2383         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
2384       }
2385 #endif
2386       /* D triangle */
2387       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
2388       orntNew[0] = 0;
2389       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
2390       orntNew[1] = 0;
2391       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
2392       orntNew[2] = 0;
2393       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2394       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2395 #if 1
2396       if ((newp+3 < fStartNew) || (newp+3 >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+3, fStartNew, fMaxNew);
2397       for (p = 0; p < 3; ++p) {
2398         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
2399       }
2400 #endif
2401       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2402       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2403       for (r = 0; r < 4; ++r) {
2404         for (s = 0; s < supportSize; ++s) {
2405           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2406           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2407           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2408           for (c = 0; c < coneSize; ++c) {
2409             if (cone[c] == f) break;
2410           }
2411           if (support[s] < cMax) {
2412             supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : (ornt[c] < 0 ? faces[c*3+(-(ornt[c]+1)+1+3-r)%3] : faces[c*3+r]));
2413           } else {
2414             supportRef[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + r;
2415           }
2416         }
2417         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
2418 #if 1
2419         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2420         for (p = 0; p < supportSize; ++p) {
2421           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior or hybrid cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
2422         }
2423 #endif
2424       }
2425     }
2426     /* Interior cell faces have 3 edges and 2 cells */
2427     for (c = cStart; c < cMax; ++c) {
2428       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8;
2429       const PetscInt *cone, *ornt;
2430       PetscInt        coneNew[3], orntNew[3];
2431       PetscInt        supportNew[2];
2432 
2433       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2434       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2435       /* Face A: {c, a, d} */
2436       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + (ornt[0] < 0 ? (-(ornt[0]+1)+0)%3 : (ornt[0]+2)%3);
2437       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2438       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + (ornt[1] < 0 ? (-(ornt[1]+1)+0)%3 : (ornt[1]+2)%3);
2439       orntNew[1] = ornt[1] < 0 ? -2 : 0;
2440       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + (ornt[2] < 0 ? (-(ornt[2]+1)+0)%3 : (ornt[2]+2)%3);
2441       orntNew[2] = ornt[2] < 0 ? -2 : 0;
2442       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2443       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2444 #if 1
2445       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2446       for (p = 0; p < 3; ++p) {
2447         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
2448       }
2449 #endif
2450       supportNew[0] = (c - cStart)*8 + 0;
2451       supportNew[1] = (c - cStart)*8 + 0+4;
2452       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2453 #if 1
2454       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2455       for (p = 0; p < 2; ++p) {
2456         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
2457       }
2458 #endif
2459       ++newp;
2460       /* Face B: {a, b, e} */
2461       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + (ornt[0] < 0 ? (-(ornt[0]+1)+2)%3 : (ornt[0]+0)%3);
2462       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2463       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + (ornt[3] < 0 ? (-(ornt[3]+1)+2)%3 : (ornt[3]+0)%3);
2464       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2465       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + (ornt[1] < 0 ? (-(ornt[1]+1)+1)%3 : (ornt[1]+1)%3);
2466       orntNew[2] = ornt[1] < 0 ? -2 : 0;
2467       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2468       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2469 #if 1
2470       if ((newp+1 < fStartNew) || (newp+1 >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+1, fStartNew, fMaxNew);
2471       for (p = 0; p < 3; ++p) {
2472         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
2473       }
2474 #endif
2475       supportNew[0] = (c - cStart)*8 + 1;
2476       supportNew[1] = (c - cStart)*8 + 1+4;
2477       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2478 #if 1
2479       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2480       for (p = 0; p < 2; ++p) {
2481         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
2482       }
2483 #endif
2484       ++newp;
2485       /* Face C: {c, f, b} */
2486       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + (ornt[2] < 0 ? (-(ornt[2]+1)+2)%3 : (ornt[2]+0)%3);
2487       orntNew[0] = ornt[2] < 0 ? -2 : 0;
2488       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + (ornt[3] < 0 ? (-(ornt[3]+1)+0)%3 : (ornt[3]+2)%3);
2489       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2490       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + (ornt[0] < 0 ? (-(ornt[0]+1)+1)%3 : (ornt[0]+1)%3);
2491       orntNew[2] = ornt[0] < 0 ? -2 : 0;
2492       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2493       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2494 #if 1
2495       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2496       for (p = 0; p < 3; ++p) {
2497         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
2498       }
2499 #endif
2500       supportNew[0] = (c - cStart)*8 + 2;
2501       supportNew[1] = (c - cStart)*8 + 2+4;
2502       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2503 #if 1
2504       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2505       for (p = 0; p < 2; ++p) {
2506         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
2507       }
2508 #endif
2509       ++newp;
2510       /* Face D: {d, e, f} */
2511       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + (ornt[1] < 0 ? (-(ornt[1]+1)+2)%3 : (ornt[1]+0)%3);
2512       orntNew[0] = ornt[1] < 0 ? -2 : 0;
2513       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + (ornt[3] < 0 ? (-(ornt[3]+1)+1)%3 : (ornt[3]+1)%3);
2514       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2515       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + (ornt[2] < 0 ? (-(ornt[2]+1)+1)%3 : (ornt[2]+1)%3);
2516       orntNew[2] = ornt[2] < 0 ? -2 : 0;
2517       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2518       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2519 #if 1
2520       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2521       for (p = 0; p < 3; ++p) {
2522         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
2523       }
2524 #endif
2525       supportNew[0] = (c - cStart)*8 + 3;
2526       supportNew[1] = (c - cStart)*8 + 3+4;
2527       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2528 #if 1
2529       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2530       for (p = 0; p < 2; ++p) {
2531         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
2532       }
2533 #endif
2534       ++newp;
2535       /* Face E: {d, f, a} */
2536       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + (ornt[2] < 0 ? (-(ornt[2]+1)+1)%3 : (ornt[2]+1)%3);
2537       orntNew[0] = ornt[2] < 0 ? 0 : -2;
2538       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
2539       orntNew[1] = 0;
2540       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + (ornt[1] < 0 ? (-(ornt[1]+1)+0)%3 : (ornt[1]+2)%3);
2541       orntNew[2] = ornt[1] < 0 ? -2 : 0;
2542       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2543       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2544 #if 1
2545       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2546       for (p = 0; p < 3; ++p) {
2547         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
2548       }
2549 #endif
2550       supportNew[0] = (c - cStart)*8 + 0+4;
2551       supportNew[1] = (c - cStart)*8 + 3+4;
2552       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2553 #if 1
2554       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2555       for (p = 0; p < 2; ++p) {
2556         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
2557       }
2558 #endif
2559       ++newp;
2560       /* Face F: {c, a, f} */
2561       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + (ornt[0] < 0 ? (-(ornt[0]+1)+0)%3 : (ornt[0]+2)%3);
2562       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2563       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
2564       orntNew[1] = -2;
2565       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + (ornt[2] < 0 ? (-(ornt[2]+1)+2)%3 : (ornt[2]+0)%3);
2566       orntNew[2] = ornt[1] < 0 ? 0 : -2;
2567       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2568       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2569 #if 1
2570       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2571       for (p = 0; p < 3; ++p) {
2572         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
2573       }
2574 #endif
2575       supportNew[0] = (c - cStart)*8 + 0+4;
2576       supportNew[1] = (c - cStart)*8 + 2+4;
2577       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2578 #if 1
2579       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2580       for (p = 0; p < 2; ++p) {
2581         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
2582       }
2583 #endif
2584       ++newp;
2585       /* Face G: {e, a, f} */
2586       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + (ornt[1] < 0 ? (-(ornt[1]+1)+1)%3 : (ornt[1]+1)%3);
2587       orntNew[0] = ornt[1] < 0 ? -2 : 0;
2588       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
2589       orntNew[1] = -2;
2590       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + (ornt[3] < 0 ? (-(ornt[3]+1)+1)%3 : (ornt[3]+1)%3);
2591       orntNew[2] = ornt[3] < 0 ? 0 : -2;
2592       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2593       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2594 #if 1
2595       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2596       for (p = 0; p < 3; ++p) {
2597         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
2598       }
2599 #endif
2600       supportNew[0] = (c - cStart)*8 + 1+4;
2601       supportNew[1] = (c - cStart)*8 + 3+4;
2602       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2603 #if 1
2604       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2605       for (p = 0; p < 2; ++p) {
2606         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
2607       }
2608 #endif
2609       ++newp;
2610       /* Face H: {a, b, f} */
2611       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + (ornt[0] < 0 ? (-(ornt[0]+1)+2)%3 : (ornt[0]+0)%3);
2612       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2613       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + (ornt[3] < 0 ? (-(ornt[3]+1)+0)%3 : (ornt[3]+2)%3);
2614       orntNew[1] = ornt[3] < 0 ? 0 : -2;
2615       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
2616       orntNew[2] = 0;
2617       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2618       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2619 #if 1
2620       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2621       for (p = 0; p < 3; ++p) {
2622         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
2623       }
2624 #endif
2625       supportNew[0] = (c - cStart)*8 + 1+4;
2626       supportNew[1] = (c - cStart)*8 + 2+4;
2627       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2628 #if 1
2629       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2630       for (p = 0; p < 2; ++p) {
2631         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
2632       }
2633 #endif
2634       ++newp;
2635     }
2636     /* Hybrid split faces have 4 edges and same cells */
2637     for (f = fMax; f < fEnd; ++f) {
2638       const PetscInt *cone, *ornt, *support;
2639       PetscInt        coneNew[4], orntNew[4];
2640       PetscInt        supportNew[2], size, s, c;
2641 
2642       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2643       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
2644       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2645       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2646       for (r = 0; r < 2; ++r) {
2647         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
2648 
2649         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
2650         orntNew[0]   = ornt[0];
2651         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
2652         orntNew[1]   = ornt[1];
2653         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (cone[2+r] - eMax);
2654         orntNew[2+r] = 0;
2655         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd      - eMax) + (f - fMax);
2656         orntNew[3-r] = 0;
2657         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2658         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2659 #if 1
2660         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
2661         for (p = 0; p < 2; ++p) {
2662           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
2663         }
2664         for (p = 2; p < 4; ++p) {
2665           if ((coneNew[p] < eMaxNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", coneNew[p], eMaxNew, eEndNew);
2666         }
2667 #endif
2668         for (s = 0; s < size; ++s) {
2669           const PetscInt *coneCell, *orntCell;
2670 
2671           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
2672           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
2673           for (c = 2; c < 5; ++c) if (coneCell[c] == f) break;
2674           if (c >= 5) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
2675           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + GetTriSubface_Static(orntCell[c], (c-2+r)%3);
2676         }
2677         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2678 #if 1
2679         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
2680         for (p = 0; p < size; ++p) {
2681           if ((supportNew[p] < cMaxNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", supportNew[p], cMaxNew, cEndNew);
2682         }
2683 #endif
2684       }
2685     }
2686     /* Hybrid cell faces have 4 edges and 2 cells */
2687     for (c = cMax; c < cEnd; ++c) {
2688       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3;
2689       const PetscInt *cone, *ornt;
2690       PetscInt        coneNew[4], orntNew[4];
2691       PetscInt        supportNew[2];
2692 
2693       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2694       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2695       for (r = 0; r < 3; ++r) {
2696         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], (r+2)%3);
2697         orntNew[0] = 0;
2698         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], (r+2)%3);
2699         orntNew[1] = 0;
2700         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+GetTriSubface_Static(ornt[0], (r+2)%3)] - fMax);
2701         orntNew[2] = 0;
2702         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+GetTriSubface_Static(ornt[0], r)]       - fMax);
2703         orntNew[3] = 0;
2704         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
2705         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
2706 #if 1
2707         if ((newp+r < fMaxNew) || (newp+r >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp+r, fMaxNew, fEndNew);
2708         for (p = 0; p < 2; ++p) {
2709           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
2710         }
2711         for (p = 2; p < 4; ++p) {
2712           if ((coneNew[p] < eMaxNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", coneNew[p], eMaxNew, eEndNew);
2713         }
2714 #endif
2715         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetTriSubface_Static(ornt[0], r);
2716         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + 3;
2717         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
2718 #if 1
2719         if ((newp+r < fMaxNew) || (newp+r >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp+r, fMaxNew, fEndNew);
2720         for (p = 0; p < 2; ++p) {
2721           if ((supportNew[p] < cMaxNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", supportNew[p], cMaxNew, cEndNew);
2722         }
2723 #endif
2724       }
2725     }
2726     /* Interior split edges have 2 vertices and the same faces as the parent */
2727     for (e = eStart; e < eMax; ++e) {
2728       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
2729 
2730       for (r = 0; r < 2; ++r) {
2731         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
2732         const PetscInt *cone, *ornt, *support;
2733         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2734 
2735         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
2736         coneNew[0]       = vStartNew + (cone[0] - vStart);
2737         coneNew[1]       = vStartNew + (cone[1] - vStart);
2738         coneNew[(r+1)%2] = newv;
2739         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2740 #if 1
2741         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
2742         for (p = 0; p < 2; ++p) {
2743           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2744         }
2745 #endif
2746         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
2747         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
2748         for (s = 0; s < supportSize; ++s) {
2749           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2750           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2751           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2752           for (c = 0; c < coneSize; ++c) if (cone[c] == e) break;
2753           if (support[s] < fMax) {
2754             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
2755           } else {
2756             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
2757           }
2758         }
2759         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2760 #if 1
2761         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
2762         for (p = 0; p < supportSize; ++p) {
2763           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior or hybrid face [%d, %d)", supportRef[p], fStartNew, fEndNew);
2764         }
2765 #endif
2766       }
2767     }
2768     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
2769     for (f = fStart; f < fMax; ++f) {
2770       const PetscInt *cone, *ornt, *support;
2771       PetscInt        coneSize, supportSize, s;
2772 
2773       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2774       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2775       for (r = 0; r < 3; ++r) {
2776         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
2777         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
2778         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
2779                                     -1, -1,  1,  6,  0,  4,
2780                                      2,  5,  3,  4, -1, -1,
2781                                     -1, -1,  3,  6,  2,  7};
2782 
2783         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2784         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
2785         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
2786         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2787 #if 1
2788         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
2789         for (p = 0; p < 2; ++p) {
2790           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2791         }
2792 #endif
2793         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
2794         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
2795         for (s = 0; s < supportSize; ++s) {
2796           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2797           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2798           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2799           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
2800           if (support[s] < cMax) {
2801             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
2802             er   = ornt[c] < 0 ? (-(ornt[c]+1) + 2-r)%3 : (ornt[c] + r)%3;
2803             if (er == eint[c]) {
2804               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
2805             } else {
2806               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
2807               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
2808             }
2809           } else {
2810             supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (r+1)%3;
2811           }
2812         }
2813         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2814 #if 1
2815         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
2816         for (p = 0; p < intFaces; ++p) {
2817           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior or hybrid face [%d, %d)", supportRef[p], fStartNew, fEndNew);
2818         }
2819 #endif
2820       }
2821     }
2822     /* Interior cell edges have 2 vertices and 4 faces */
2823     for (c = cStart; c < cMax; ++c) {
2824       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
2825       const PetscInt *cone, *ornt, *fcone;
2826       PetscInt        coneNew[2], supportNew[4], find;
2827 
2828       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2829       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2830       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
2831       find = GetTriEdge_Static(ornt[0], 0);
2832       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
2833       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
2834       find = GetTriEdge_Static(ornt[2], 1);
2835       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
2836       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2837 #if 1
2838       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
2839       for (p = 0; p < 2; ++p) {
2840         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2841       }
2842 #endif
2843       supportNew[0] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 4;
2844       supportNew[1] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 5;
2845       supportNew[2] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 6;
2846       supportNew[3] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 7;
2847       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2848 #if 1
2849       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
2850       for (p = 0; p < 4; ++p) {
2851         if ((supportNew[p] < fStartNew) || (supportNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportNew[p], fStartNew, fMaxNew);
2852       }
2853 #endif
2854     }
2855     /* Hybrid edges have two vertices and the same faces */
2856     for (e = eMax; e < eEnd; ++e) {
2857       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
2858       const PetscInt *cone, *support, *fcone;
2859       PetscInt        coneNew[2], size, fsize, s;
2860 
2861       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
2862       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
2863       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
2864       coneNew[0] = vStartNew + (cone[0] - vStart);
2865       coneNew[1] = vStartNew + (cone[1] - vStart);
2866       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2867 #if 1
2868       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
2869       for (p = 0; p < 2; ++p) {
2870         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2871       }
2872 #endif
2873       for (s = 0; s < size; ++s) {
2874         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
2875         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
2876         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
2877         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
2878         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + c-2;
2879       }
2880       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2881 #if 1
2882       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
2883       for (p = 0; p < size; ++p) {
2884         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", supportRef[p], fMaxNew, fEndNew);
2885       }
2886 #endif
2887     }
2888     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
2889     for (f = fMax; f < fEnd; ++f) {
2890       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
2891       const PetscInt *cone, *support, *ccone;
2892       PetscInt        coneNew[2], size, csize, s;
2893 
2894       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2895       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2896       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2897       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
2898       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
2899       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2900 #if 1
2901       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
2902       for (p = 0; p < 2; ++p) {
2903         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2904       }
2905 #endif
2906       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 0;
2907       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 1;
2908       for (s = 0; s < size; ++s) {
2909         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
2910         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
2911         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
2912         if ((c < 2) || (c >= csize)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Hybrid face %d is not in cone of hybrid cell %d", f, support[s]);
2913         supportRef[2+s*2+0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (c-2)%3;
2914         supportRef[2+s*2+1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (c-1)%3;
2915       }
2916       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2917 #if 1
2918       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
2919       for (p = 0; p < 2+size*2; ++p) {
2920         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", supportRef[p], fMaxNew, fEndNew);
2921       }
2922 #endif
2923     }
2924     /* Interior vertices have identical supports */
2925     for (v = vStart; v < vEnd; ++v) {
2926       const PetscInt  newp = vStartNew + (v - vStart);
2927       const PetscInt *support, *cone;
2928       PetscInt        size, s;
2929 
2930       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2931       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2932       for (s = 0; s < size; ++s) {
2933         PetscInt r = 0;
2934 
2935         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2936         if (cone[1] == v) r = 1;
2937         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
2938         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (support[s] - eMax);
2939       }
2940       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2941 #if 1
2942       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2943       for (p = 0; p < size; ++p) {
2944         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior or hybrid edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
2945       }
2946 #endif
2947     }
2948     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
2949     for (e = eStart; e < eMax; ++e) {
2950       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
2951       const PetscInt *cone, *support;
2952       PetscInt       *star = NULL, starSize, faceSize = 0, cellSize = 0, coneSize, size, s;
2953 
2954       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
2955       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
2956       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
2957       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
2958       for (s = 0; s < size; ++s) {
2959         PetscInt r = 0;
2960 
2961         if (support[s] < fMax) {
2962           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2963           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2964           for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
2965           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
2966           supportRef[2+faceSize+1] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
2967           faceSize += 2;
2968         } else {
2969           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (support[s] - fMax);
2970           ++faceSize;
2971         }
2972       }
2973       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
2974       for (s = 0; s < starSize*2; s += 2) {
2975         const PetscInt *cone, *ornt;
2976         PetscInt        e01, e23;
2977 
2978         if ((star[s] >= cStart) && (star[s] < cMax)) {
2979           /* Check edge 0-1 */
2980           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
2981           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
2982           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
2983           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
2984           /* Check edge 2-3 */
2985           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
2986           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
2987           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
2988           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
2989           if ((e01 == e) || (e23 == e)) {supportRef[2+faceSize+cellSize++] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (star[s] - cStart);}
2990         }
2991       }
2992       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
2993       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2994 #if 1
2995       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2996       for (p = 0; p < 2+faceSize+cellSize; ++p) {
2997         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior or hybrid edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
2998       }
2999 #endif
3000     }
3001     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3002     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
3003     break;
3004   case 6:
3005     /* Hex 3D */
3006     /*
3007      Bottom (viewed from top)    Top
3008      1---------2---------2       7---------2---------6
3009      |         |         |       |         |         |
3010      |    B    2    C    |       |    H    2    G    |
3011      |         |         |       |         |         |
3012      3----3----0----1----1       3----3----0----1----1
3013      |         |         |       |         |         |
3014      |    A    0    D    |       |    E    0    F    |
3015      |         |         |       |         |         |
3016      0---------0---------3       4---------0---------5
3017      */
3018     /* All cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
3019     for (c = cStart; c < cEnd; ++c) {
3020       const PetscInt  newp = (c - cStart)*8;
3021       const PetscInt *cone, *ornt;
3022       PetscInt        coneNew[6], orntNew[6];
3023 
3024       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3025       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3026       /* A hex */
3027       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
3028       orntNew[0] = ornt[0];
3029       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
3030       orntNew[1] = 0;
3031       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
3032       orntNew[2] = ornt[2];
3033       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
3034       orntNew[3] = 0;
3035       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
3036       orntNew[4] = 0;
3037       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
3038       orntNew[5] = ornt[5];
3039       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3040       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3041 #if 1
3042       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
3043       for (p = 0; p < 6; ++p) {
3044         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
3045       }
3046 #endif
3047       /* B hex */
3048       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
3049       orntNew[0] = ornt[0];
3050       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
3051       orntNew[1] = 0;
3052       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
3053       orntNew[2] = -3;
3054       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
3055       orntNew[3] = ornt[3];
3056       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
3057       orntNew[4] = 0;
3058       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
3059       orntNew[5] = ornt[5];
3060       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3061       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3062 #if 1
3063       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
3064       for (p = 0; p < 6; ++p) {
3065         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
3066       }
3067 #endif
3068       /* C hex */
3069       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
3070       orntNew[0] = ornt[0];
3071       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
3072       orntNew[1] = 0;
3073       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
3074       orntNew[2] = 0;
3075       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
3076       orntNew[3] = ornt[3];
3077       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
3078       orntNew[4] = ornt[4];
3079       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
3080       orntNew[5] = -3;
3081       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3082       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3083 #if 1
3084       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
3085       for (p = 0; p < 6; ++p) {
3086         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
3087       }
3088 #endif
3089       /* D hex */
3090       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
3091       orntNew[0] = ornt[0];
3092       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
3093       orntNew[1] = 0;
3094       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
3095       orntNew[2] = ornt[2];
3096       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
3097       orntNew[3] = -3;
3098       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
3099       orntNew[4] = ornt[4];
3100       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
3101       orntNew[5] = -3;
3102       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3103       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3104 #if 1
3105       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
3106       for (p = 0; p < 6; ++p) {
3107         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
3108       }
3109 #endif
3110       /* E hex */
3111       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
3112       orntNew[0] = -3;
3113       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
3114       orntNew[1] = ornt[1];
3115       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
3116       orntNew[2] = ornt[2];
3117       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
3118       orntNew[3] = 0;
3119       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
3120       orntNew[4] = 0;
3121       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
3122       orntNew[5] = ornt[5];
3123       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
3124       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
3125 #if 1
3126       if ((newp+4 < cStartNew) || (newp+4 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+4, cStartNew, cEndNew);
3127       for (p = 0; p < 6; ++p) {
3128         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
3129       }
3130 #endif
3131       /* F hex */
3132       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
3133       orntNew[0] = -3;
3134       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
3135       orntNew[1] = ornt[1];
3136       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
3137       orntNew[2] = ornt[2];
3138       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
3139       orntNew[3] = 0;
3140       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
3141       orntNew[4] = ornt[4];
3142       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
3143       orntNew[5] = -3;
3144       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
3145       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
3146 #if 1
3147       if ((newp+5 < cStartNew) || (newp+5 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+5, cStartNew, cEndNew);
3148       for (p = 0; p < 6; ++p) {
3149         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
3150       }
3151 #endif
3152       /* G hex */
3153       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
3154       orntNew[0] = -3;
3155       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
3156       orntNew[1] = ornt[1];
3157       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
3158       orntNew[2] = -3;
3159       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
3160       orntNew[3] = ornt[3];
3161       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
3162       orntNew[4] = ornt[4];
3163       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
3164       orntNew[5] = 0;
3165       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
3166       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
3167 #if 1
3168       if ((newp+6 < cStartNew) || (newp+6 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+6, cStartNew, cEndNew);
3169       for (p = 0; p < 6; ++p) {
3170         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
3171       }
3172 #endif
3173       /* H hex */
3174       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
3175       orntNew[0] = -3;
3176       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
3177       orntNew[1] = ornt[1];
3178       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
3179       orntNew[2] = -3;
3180       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
3181       orntNew[3] = ornt[3];
3182       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
3183       orntNew[4] = -3;
3184       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
3185       orntNew[5] = ornt[5];
3186       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
3187       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
3188 #if 1
3189       if ((newp+7 < cStartNew) || (newp+7 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+7, cStartNew, cEndNew);
3190       for (p = 0; p < 6; ++p) {
3191         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
3192       }
3193 #endif
3194     }
3195     /* Split faces have 4 edges and the same cells as the parent */
3196     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3197     ierr = PetscMalloc((4 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
3198     for (f = fStart; f < fEnd; ++f) {
3199       for (r = 0; r < 4; ++r) {
3200         /* TODO: This can come from GetFaces_Internal() */
3201         const PetscInt  newCells[24] = {0, 1, 2, 3,  4, 5, 6, 7,  0, 3, 5, 4,  2, 1, 7, 6,  3, 2, 6, 5,  0, 4, 7, 1};
3202         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
3203         const PetscInt *cone, *ornt, *support;
3204         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
3205 
3206         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3207         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3208         coneNew[0] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
3209         orntNew[0] = ornt[(r+3)%4];
3210         coneNew[1] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
3211         orntNew[1] = ornt[r];
3212         coneNew[2] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
3213         orntNew[2] = 0;
3214         coneNew[3] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + (r+3)%4;
3215         orntNew[3] = -2;
3216         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3217         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3218 #if 1
3219         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3220         for (p = 0; p < 4; ++p) {
3221           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3222         }
3223 #endif
3224         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3225         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3226         for (s = 0; s < supportSize; ++s) {
3227           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3228           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3229           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3230           for (c = 0; c < coneSize; ++c) {
3231             if (cone[c] == f) break;
3232           }
3233           supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+GetQuadSubface_Static(ornt[c], r)];
3234         }
3235         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3236 #if 1
3237         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3238         for (p = 0; p < supportSize; ++p) {
3239           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
3240         }
3241 #endif
3242       }
3243     }
3244     /* Interior faces have 4 edges and 2 cells */
3245     for (c = cStart; c < cEnd; ++c) {
3246       const PetscInt  newCells[24] = {0, 3,  2, 3,  1, 2,  0, 1,  4, 5,  5, 6,  6, 7,  4, 7,  0, 4,  3, 5,  2, 6,  1, 7};
3247       const PetscInt *cone, *ornt;
3248       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
3249 
3250       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3251       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3252       /* A-D face */
3253       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 0;
3254       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
3255       orntNew[0] = -2;
3256       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
3257       orntNew[1] = 0;
3258       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
3259       orntNew[2] = 0;
3260       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
3261       orntNew[3] = -2;
3262       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3263       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3264 #if 1
3265       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3266       for (p = 0; p < 4; ++p) {
3267         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3268       }
3269 #endif
3270       /* C-D face */
3271       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 1;
3272       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
3273       orntNew[0] = -2;
3274       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
3275       orntNew[1] = 0;
3276       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
3277       orntNew[2] = 0;
3278       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
3279       orntNew[3] = -2;
3280       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3281       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3282 #if 1
3283       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3284       for (p = 0; p < 4; ++p) {
3285         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3286       }
3287 #endif
3288       /* B-C face */
3289       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 2;
3290       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
3291       orntNew[0] = -2;
3292       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
3293       orntNew[1] = 0;
3294       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
3295       orntNew[2] = 0;
3296       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
3297       orntNew[3] = -2;
3298       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3299       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3300 #if 1
3301       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3302       for (p = 0; p < 4; ++p) {
3303         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3304       }
3305 #endif
3306       /* A-B face */
3307       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 3;
3308       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
3309       orntNew[0] = -2;
3310       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
3311       orntNew[1] = 0;
3312       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
3313       orntNew[2] = 0;
3314       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
3315       orntNew[3] = -2;
3316       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3317       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3318 #if 1
3319       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3320       for (p = 0; p < 4; ++p) {
3321         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3322       }
3323 #endif
3324       /* E-F face */
3325       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 4;
3326       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
3327       orntNew[0] = -2;
3328       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
3329       orntNew[1] = 0;
3330       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
3331       orntNew[2] = 0;
3332       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
3333       orntNew[3] = -2;
3334       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3335       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3336 #if 1
3337       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3338       for (p = 0; p < 4; ++p) {
3339         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3340       }
3341 #endif
3342       /* F-G face */
3343       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 5;
3344       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
3345       orntNew[0] = -2;
3346       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
3347       orntNew[1] = 0;
3348       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
3349       orntNew[2] = 0;
3350       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
3351       orntNew[3] = -2;
3352       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3353       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3354 #if 1
3355       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3356       for (p = 0; p < 4; ++p) {
3357         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3358       }
3359 #endif
3360       /* G-H face */
3361       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 6;
3362       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
3363       orntNew[0] = -2;
3364       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
3365       orntNew[1] = 0;
3366       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
3367       orntNew[2] = 0;
3368       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
3369       orntNew[3] = -2;
3370       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3371       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3372 #if 1
3373       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3374       for (p = 0; p < 4; ++p) {
3375         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3376       }
3377 #endif
3378       /* E-H face */
3379       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 7;
3380       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
3381       orntNew[0] = -2;
3382       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
3383       orntNew[1] = 0;
3384       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
3385       orntNew[2] = 0;
3386       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
3387       orntNew[3] = -2;
3388       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3389       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3390 #if 1
3391       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3392       for (p = 0; p < 4; ++p) {
3393         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3394       }
3395 #endif
3396       /* A-E face */
3397       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 8;
3398       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
3399       orntNew[0] = -2;
3400       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
3401       orntNew[1] = 0;
3402       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
3403       orntNew[2] = 0;
3404       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
3405       orntNew[3] = -2;
3406       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3407       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3408 #if 1
3409       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3410       for (p = 0; p < 4; ++p) {
3411         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3412       }
3413 #endif
3414       /* D-F face */
3415       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 9;
3416       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
3417       orntNew[0] = -2;
3418       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
3419       orntNew[1] = 0;
3420       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
3421       orntNew[2] = 0;
3422       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
3423       orntNew[3] = -2;
3424       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3425       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3426 #if 1
3427       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3428       for (p = 0; p < 4; ++p) {
3429         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3430       }
3431 #endif
3432       /* C-G face */
3433       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 10;
3434       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
3435       orntNew[0] = -2;
3436       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
3437       orntNew[1] = 0;
3438       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
3439       orntNew[2] = 0;
3440       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
3441       orntNew[3] = -2;
3442       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3443       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3444 #if 1
3445       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3446       for (p = 0; p < 4; ++p) {
3447         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3448       }
3449 #endif
3450       /* B-H face */
3451       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 11;
3452       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
3453       orntNew[0] = -2;
3454       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
3455       orntNew[1] = 0;
3456       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
3457       orntNew[2] = 0;
3458       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
3459       orntNew[3] = -2;
3460       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3461       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3462 #if 1
3463       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3464       for (p = 0; p < 4; ++p) {
3465         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3466       }
3467 #endif
3468       for (r = 0; r < 12; ++r) {
3469         newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
3470         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
3471         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
3472         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3473 #if 1
3474         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3475         for (p = 0; p < 2; ++p) {
3476           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
3477         }
3478 #endif
3479       }
3480     }
3481     /* Split edges have 2 vertices and the same faces as the parent */
3482     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3483     for (e = eStart; e < eEnd; ++e) {
3484       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
3485 
3486       for (r = 0; r < 2; ++r) {
3487         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
3488         const PetscInt *cone, *ornt, *support;
3489         PetscInt        coneNew[2], coneSize, c, supportSize, s;
3490 
3491         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3492         coneNew[0]       = vStartNew + (cone[0] - vStart);
3493         coneNew[1]       = vStartNew + (cone[1] - vStart);
3494         coneNew[(r+1)%2] = newv;
3495         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3496 #if 1
3497         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3498         for (p = 0; p < 2; ++p) {
3499           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
3500         }
3501 #endif
3502         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
3503         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3504         for (s = 0; s < supportSize; ++s) {
3505           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3506           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3507           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3508           for (c = 0; c < coneSize; ++c) {
3509             if (cone[c] == e) break;
3510           }
3511           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
3512         }
3513         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3514 #if 1
3515         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3516         for (p = 0; p < supportSize; ++p) {
3517           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
3518         }
3519 #endif
3520       }
3521     }
3522     /* Face edges have 2 vertices and 2+cells faces */
3523     for (f = fStart; f < fEnd; ++f) {
3524       const PetscInt  newFaces[24] = {3, 2, 1, 0,  4, 5, 6, 7,  0, 9, 4, 8,  2, 11, 6, 10,  1, 10, 5, 9,  8, 7, 11, 3};
3525       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
3526       const PetscInt *cone, *coneCell, *orntCell, *support;
3527       PetscInt        coneNew[2], coneSize, c, supportSize, s;
3528 
3529       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3530       for (r = 0; r < 4; ++r) {
3531         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
3532 
3533         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
3534         coneNew[1] = newv;
3535         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3536 #if 1
3537         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3538         for (p = 0; p < 2; ++p) {
3539           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
3540         }
3541 #endif
3542         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3543         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3544         supportRef[0] = fStartNew + (f - fStart)*4 + r;
3545         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
3546         for (s = 0; s < supportSize; ++s) {
3547           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3548           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
3549           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
3550           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
3551           supportRef[2+s] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdge_Static(orntCell[c], r)];
3552         }
3553         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3554 #if 1
3555         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3556         for (p = 0; p < 2+supportSize; ++p) {
3557           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
3558         }
3559 #endif
3560       }
3561     }
3562     /* Cell edges have 2 vertices and 4 faces */
3563     for (c = cStart; c < cEnd; ++c) {
3564       const PetscInt  newFaces[24] = {0, 1, 2, 3,  4, 5, 6, 7,  0, 9, 4, 8,  2, 11, 6, 10,  1, 10, 5, 9,  3, 8, 7, 11};
3565       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
3566       const PetscInt *cone;
3567       PetscInt        coneNew[2], supportNew[4];
3568 
3569       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3570       for (r = 0; r < 6; ++r) {
3571         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
3572 
3573         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
3574         coneNew[1] = newv;
3575         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3576 #if 1
3577         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3578         for (p = 0; p < 2; ++p) {
3579           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
3580         }
3581 #endif
3582         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
3583         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3584 #if 1
3585         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3586         for (p = 0; p < 4; ++p) {
3587           if ((supportNew[p] < fStartNew) || (supportNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportNew[p], fStartNew, fEndNew);
3588         }
3589 #endif
3590       }
3591     }
3592     /* Old vertices have identical supports */
3593     for (v = vStart; v < vEnd; ++v) {
3594       const PetscInt  newp = vStartNew + (v - vStart);
3595       const PetscInt *support, *cone;
3596       PetscInt        size, s;
3597 
3598       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
3599       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
3600       for (s = 0; s < size; ++s) {
3601         PetscInt r = 0;
3602 
3603         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3604         if (cone[1] == v) r = 1;
3605         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
3606       }
3607       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3608 #if 1
3609       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3610       for (p = 0; p < size; ++p) {
3611         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
3612       }
3613 #endif
3614     }
3615     /* Edge vertices have 2 + faces supports */
3616     for (e = eStart; e < eEnd; ++e) {
3617       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
3618       const PetscInt *cone, *support;
3619       PetscInt        size, s;
3620 
3621       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
3622       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3623       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
3624       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
3625       for (s = 0; s < size; ++s) {
3626         PetscInt r;
3627 
3628         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3629         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
3630         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*4 + r;
3631       }
3632       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3633 #if 1
3634       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3635       for (p = 0; p < 2+size; ++p) {
3636         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
3637       }
3638 #endif
3639     }
3640     /* Face vertices have 4 + cells supports */
3641     for (f = fStart; f < fEnd; ++f) {
3642       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
3643       const PetscInt *cone, *support;
3644       PetscInt        size, s;
3645 
3646       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3647       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3648       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (e - eStart)*2 +  (f - fStart)*4 + r;
3649       for (s = 0; s < size; ++s) {
3650         PetscInt r;
3651 
3652         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3653         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
3654         supportRef[4+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (support[s] - cStart)*6 + r;
3655       }
3656       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3657 #if 1
3658       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3659       for (p = 0; p < 4+size; ++p) {
3660         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
3661       }
3662 #endif
3663     }
3664     /* Cell vertices have 6 supports */
3665     for (c = cStart; c < cEnd; ++c) {
3666       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
3667       PetscInt       supportNew[6];
3668 
3669       for (r = 0; r < 6; ++r) {
3670         supportNew[r] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
3671       }
3672       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3673     }
3674     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3675     break;
3676   default:
3677     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
3678   }
3679   PetscFunctionReturn(0);
3680 }
3681 
3682 #undef __FUNCT__
3683 #define __FUNCT__ "CellRefinerSetCoordinates"
3684 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
3685 {
3686   PetscSection   coordSection, coordSectionNew;
3687   Vec            coordinates, coordinatesNew;
3688   PetscScalar   *coords, *coordsNew;
3689   const PetscInt numVertices = depthSize ? depthSize[0] : 0;
3690   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, eStart, eEnd, eMax, e, fStart, fEnd, fMax, f;
3691   PetscErrorCode ierr;
3692 
3693   PetscFunctionBegin;
3694   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3695   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3696   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3697   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
3698   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3699   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
3700   ierr = DMPlexGetHybridBounds(dm, NULL, &fMax, &eMax, NULL);CHKERRQ(ierr);
3701   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);}
3702   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
3703   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3704   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
3705   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
3706   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
3707   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+numVertices);CHKERRQ(ierr);
3708   if (fMax < 0) fMax = fEnd;
3709   if (eMax < 0) eMax = eEnd;
3710   /* All vertices have the dim coordinates */
3711   for (v = vStartNew; v < vStartNew+numVertices; ++v) {
3712     ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
3713     ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
3714   }
3715   ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
3716   ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
3717   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3718   ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
3719   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);CHKERRQ(ierr);
3720   ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
3721   ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
3722   ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
3723   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
3724   ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
3725   switch (refiner) {
3726   case 0: break;
3727   case 6: /* Hex 3D */
3728     /* Face vertices have the average of corner coordinates */
3729     for (f = fStart; f < fEnd; ++f) {
3730       const PetscInt newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
3731       PetscInt      *cone = NULL;
3732       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
3733 
3734       ierr = DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
3735       for (p = 0; p < closureSize*2; p += 2) {
3736         const PetscInt point = cone[p];
3737         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
3738       }
3739       for (v = 0; v < coneSize; ++v) {
3740         ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
3741       }
3742       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
3743       for (d = 0; d < dim; ++d) {
3744         coordsNew[offnew+d] = 0.0;
3745         for (v = 0; v < coneSize; ++v) coordsNew[offnew+d] += coords[off[v]+d];
3746         coordsNew[offnew+d] /= coneSize;
3747       }
3748       ierr = DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
3749     }
3750   case 2: /* Hex 2D */
3751     /* Cell vertices have the average of corner coordinates */
3752     for (c = cStart; c < cEnd; ++c) {
3753       const PetscInt newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (c - cStart) + (dim > 2 ? (fEnd - fStart) : 0);
3754       PetscInt      *cone = NULL;
3755       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
3756 
3757       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
3758       for (p = 0; p < closureSize*2; p += 2) {
3759         const PetscInt point = cone[p];
3760         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
3761       }
3762       for (v = 0; v < coneSize; ++v) {
3763         ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
3764       }
3765       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
3766       for (d = 0; d < dim; ++d) {
3767         coordsNew[offnew+d] = 0.0;
3768         for (v = 0; v < coneSize; ++v) coordsNew[offnew+d] += coords[off[v]+d];
3769         coordsNew[offnew+d] /= coneSize;
3770       }
3771       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
3772     }
3773   case 1: /* Simplicial 2D */
3774   case 3: /* Hybrid Simplicial 2D */
3775   case 5: /* Simplicial 3D */
3776   case 7: /* Hybrid Simplicial 3D */
3777     /* Edge vertices have the average of endpoint coordinates */
3778     for (e = eStart; e < eMax; ++e) {
3779       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
3780       const PetscInt *cone;
3781       PetscInt        coneSize, offA, offB, offnew, d;
3782 
3783       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
3784       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
3785       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3786       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
3787       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
3788       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
3789       for (d = 0; d < dim; ++d) {
3790         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
3791       }
3792     }
3793     /* Old vertices have the same coordinates */
3794     for (v = vStart; v < vEnd; ++v) {
3795       const PetscInt newv = vStartNew + (v - vStart);
3796       PetscInt       off, offnew, d;
3797 
3798       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3799       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
3800       for (d = 0; d < dim; ++d) {
3801         coordsNew[offnew+d] = coords[off+d];
3802       }
3803     }
3804     break;
3805   default:
3806     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
3807   }
3808   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
3809   ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
3810   ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
3811   ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
3812   ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
3813   PetscFunctionReturn(0);
3814 }
3815 
3816 #undef __FUNCT__
3817 #define __FUNCT__ "DMPlexCreateProcessSF"
3818 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
3819 {
3820   PetscInt           numRoots, numLeaves, l;
3821   const PetscInt    *localPoints;
3822   const PetscSFNode *remotePoints;
3823   PetscInt          *localPointsNew;
3824   PetscSFNode       *remotePointsNew;
3825   PetscInt          *ranks, *ranksNew;
3826   PetscErrorCode     ierr;
3827 
3828   PetscFunctionBegin;
3829   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3830   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
3831   for (l = 0; l < numLeaves; ++l) {
3832     ranks[l] = remotePoints[l].rank;
3833   }
3834   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
3835   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
3836   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
3837   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
3838   for (l = 0; l < numLeaves; ++l) {
3839     ranksNew[l]              = ranks[l];
3840     localPointsNew[l]        = l;
3841     remotePointsNew[l].index = 0;
3842     remotePointsNew[l].rank  = ranksNew[l];
3843   }
3844   ierr = PetscFree(ranks);CHKERRQ(ierr);
3845   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
3846   ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
3847   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
3848   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
3849   PetscFunctionReturn(0);
3850 }
3851 
3852 #undef __FUNCT__
3853 #define __FUNCT__ "CellRefinerCreateSF"
3854 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
3855 {
3856   PetscSF            sf, sfNew, sfProcess;
3857   IS                 processRanks;
3858   MPI_Datatype       depthType;
3859   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
3860   const PetscInt    *localPoints, *neighbors;
3861   const PetscSFNode *remotePoints;
3862   PetscInt          *localPointsNew;
3863   PetscSFNode       *remotePointsNew;
3864   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
3865   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
3866   PetscErrorCode     ierr;
3867 
3868   PetscFunctionBegin;
3869   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
3870   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3871   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3872   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
3873   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3874   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
3875   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
3876   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
3877   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
3878   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
3879   /* Caculate size of new SF */
3880   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3881   if (numRoots < 0) PetscFunctionReturn(0);
3882   for (l = 0; l < numLeaves; ++l) {
3883     const PetscInt p = localPoints[l];
3884 
3885     switch (refiner) {
3886     case 1:
3887       /* Simplicial 2D */
3888       if ((p >= vStart) && (p < vEnd)) {
3889         /* Old vertices stay the same */
3890         ++numLeavesNew;
3891       } else if ((p >= fStart) && (p < fEnd)) {
3892         /* Old faces add new faces and vertex */
3893         numLeavesNew += 2 + 1;
3894       } else if ((p >= cStart) && (p < cEnd)) {
3895         /* Old cells add new cells and interior faces */
3896         numLeavesNew += 4 + 3;
3897       }
3898       break;
3899     case 2:
3900       /* Hex 2D */
3901       if ((p >= vStart) && (p < vEnd)) {
3902         /* Old vertices stay the same */
3903         ++numLeavesNew;
3904       } else if ((p >= fStart) && (p < fEnd)) {
3905         /* Old faces add new faces and vertex */
3906         numLeavesNew += 2 + 1;
3907       } else if ((p >= cStart) && (p < cEnd)) {
3908         /* Old cells add new cells, interior faces, and vertex */
3909         numLeavesNew += 4 + 4 + 1;
3910       }
3911       break;
3912     case 5:
3913       /* Simplicial 3D */
3914       if ((p >= vStart) && (p < vEnd)) {
3915         /* Old vertices stay the same */
3916         ++numLeavesNew;
3917       } else if ((p >= eStart) && (p < eEnd)) {
3918         /* Old edges add new edges and vertex */
3919         numLeavesNew += 2 + 1;
3920       } else if ((p >= fStart) && (p < fEnd)) {
3921         /* Old faces add new faces and face edges */
3922         numLeavesNew += 4 + 3;
3923       } else if ((p >= cStart) && (p < cEnd)) {
3924         /* Old cells add new cells and interior faces and edges */
3925         numLeavesNew += 8 + 8 + 1;
3926       }
3927       break;
3928     case 7:
3929       /* Hybrid Simplicial 3D */
3930       if ((p >= vStart) && (p < vEnd)) {
3931         /* Interior vertices stay the same */
3932         ++numLeavesNew;
3933       } else if ((p >= eStart) && (p < eMax)) {
3934         /* Interior edges add new edges and vertex */
3935         numLeavesNew += 2 + 1;
3936       } else if ((p >= eMax) && (p < eEnd)) {
3937         /* Hybrid edges stay the same */
3938         ++numLeavesNew;
3939       } else if ((p >= fStart) && (p < fMax)) {
3940         /* Interior faces add new faces and edges */
3941         numLeavesNew += 4 + 3;
3942       } else if ((p >= fMax) && (p < fEnd)) {
3943         /* Hybrid faces add new faces and edges */
3944         numLeavesNew += 2 + 1;
3945       } else if ((p >= cStart) && (p < cMax)) {
3946         /* Interior cells add new cells, faces, and edges */
3947         numLeavesNew += 8 + 8 + 1;
3948       } else if ((p >= cMax) && (p < cEnd)) {
3949         /* Hybrid cells add new cells and faces */
3950         numLeavesNew += 4 + 3;
3951       }
3952       break;
3953     case 6:
3954       /* Hex 3D */
3955       if ((p >= vStart) && (p < vEnd)) {
3956         /* Old vertices stay the same */
3957         ++numLeavesNew;
3958       } else if ((p >= eStart) && (p < eEnd)) {
3959         /* Old edges add new edges, and vertex */
3960         numLeavesNew += 2 + 1;
3961       } else if ((p >= fStart) && (p < fEnd)) {
3962         /* Old faces add new faces, edges, and vertex */
3963         numLeavesNew += 4 + 4 + 1;
3964       } else if ((p >= cStart) && (p < cEnd)) {
3965         /* Old cells add new cells, faces, edges, and vertex */
3966         numLeavesNew += 8 + 12 + 6 + 1;
3967       }
3968       break;
3969     default:
3970       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
3971     }
3972   }
3973   /* Communicate depthSizes for each remote rank */
3974   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
3975   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
3976   ierr = PetscMalloc5((depth+1)*numNeighbors,&rdepthSize,numNeighbors,&rvStartNew,numNeighbors,&reStartNew,numNeighbors,&rfStartNew,numNeighbors,&rcStartNew);CHKERRQ(ierr);
3977   ierr = PetscMalloc7(depth+1,&depthSizeOld,(depth+1)*numNeighbors,&rdepthSizeOld,(depth+1)*numNeighbors,&rdepthMaxOld,numNeighbors,&rvStart,numNeighbors,&reStart,numNeighbors,&rfStart,numNeighbors,&rcStart);CHKERRQ(ierr);
3978   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
3979   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
3980   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
3981   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
3982   for (n = 0; n < numNeighbors; ++n) {
3983     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
3984   }
3985   depthSizeOld[depth]   = cMax;
3986   depthSizeOld[0]       = vMax;
3987   depthSizeOld[depth-1] = fMax;
3988   depthSizeOld[1]       = eMax;
3989 
3990   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
3991   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
3992 
3993   depthSizeOld[depth]   = cEnd - cStart;
3994   depthSizeOld[0]       = vEnd - vStart;
3995   depthSizeOld[depth-1] = fEnd - fStart;
3996   depthSizeOld[1]       = eEnd - eStart;
3997 
3998   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
3999   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
4000   for (n = 0; n < numNeighbors; ++n) {
4001     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
4002   }
4003   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
4004   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
4005   /* Calculate new point SF */
4006   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
4007   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
4008   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
4009   for (l = 0, m = 0; l < numLeaves; ++l) {
4010     PetscInt    p     = localPoints[l];
4011     PetscInt    rp    = remotePoints[l].index, n;
4012     PetscMPIInt rrank = remotePoints[l].rank;
4013 
4014     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
4015     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
4016     switch (refiner) {
4017     case 1:
4018       /* Simplicial 2D */
4019       if ((p >= vStart) && (p < vEnd)) {
4020         /* Old vertices stay the same */
4021         localPointsNew[m]        = vStartNew     + (p  - vStart);
4022         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
4023         remotePointsNew[m].rank  = rrank;
4024         ++m;
4025       } else if ((p >= fStart) && (p < fEnd)) {
4026         /* Old faces add new faces and vertex */
4027         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
4028         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
4029         remotePointsNew[m].rank  = rrank;
4030         ++m;
4031         for (r = 0; r < 2; ++r, ++m) {
4032           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
4033           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
4034           remotePointsNew[m].rank  = rrank;
4035         }
4036       } else if ((p >= cStart) && (p < cEnd)) {
4037         /* Old cells add new cells and interior faces */
4038         for (r = 0; r < 4; ++r, ++m) {
4039           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
4040           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
4041           remotePointsNew[m].rank  = rrank;
4042         }
4043         for (r = 0; r < 3; ++r, ++m) {
4044           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
4045           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
4046           remotePointsNew[m].rank  = rrank;
4047         }
4048       }
4049       break;
4050     case 2:
4051       /* Hex 2D */
4052       if ((p >= vStart) && (p < vEnd)) {
4053         /* Old vertices stay the same */
4054         localPointsNew[m]        = vStartNew     + (p  - vStart);
4055         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
4056         remotePointsNew[m].rank  = rrank;
4057         ++m;
4058       } else if ((p >= fStart) && (p < fEnd)) {
4059         /* Old faces add new faces and vertex */
4060         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
4061         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
4062         remotePointsNew[m].rank  = rrank;
4063         ++m;
4064         for (r = 0; r < 2; ++r, ++m) {
4065           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
4066           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
4067           remotePointsNew[m].rank  = rrank;
4068         }
4069       } else if ((p >= cStart) && (p < cEnd)) {
4070         /* Old cells add new cells, interior faces, and vertex */
4071         for (r = 0; r < 4; ++r, ++m) {
4072           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
4073           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
4074           remotePointsNew[m].rank  = rrank;
4075         }
4076         for (r = 0; r < 4; ++r, ++m) {
4077           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
4078           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
4079           remotePointsNew[m].rank  = rrank;
4080         }
4081         for (r = 0; r < 1; ++r, ++m) {
4082           localPointsNew[m]        = vStartNew     + (fEnd - fStart)                    + (p  - cStart)     + r;
4083           remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]) + r;
4084           remotePointsNew[m].rank  = rrank;
4085         }
4086       }
4087       break;
4088     case 3:
4089       /* Hybrid simplicial 2D */
4090       if ((p >= vStart) && (p < vEnd)) {
4091         /* Old vertices stay the same */
4092         localPointsNew[m]        = vStartNew     + (p  - vStart);
4093         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
4094         remotePointsNew[m].rank  = rrank;
4095         ++m;
4096       } else if ((p >= fStart) && (p < fMax)) {
4097         /* Old interior faces add new faces and vertex */
4098         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
4099         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
4100         remotePointsNew[m].rank  = rrank;
4101         ++m;
4102         for (r = 0; r < 2; ++r, ++m) {
4103           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
4104           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
4105           remotePointsNew[m].rank  = rrank;
4106         }
4107       } else if ((p >= fMax) && (p < fEnd)) {
4108         /* Old hybrid faces stay the same */
4109         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
4110         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
4111         remotePointsNew[m].rank  = rrank;
4112         ++m;
4113       } else if ((p >= cStart) && (p < cMax)) {
4114         /* Old interior cells add new cells and interior faces */
4115         for (r = 0; r < 4; ++r, ++m) {
4116           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
4117           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
4118           remotePointsNew[m].rank  = rrank;
4119         }
4120         for (r = 0; r < 3; ++r, ++m) {
4121           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
4122           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
4123           remotePointsNew[m].rank  = rrank;
4124         }
4125       } else if ((p >= cStart) && (p < cMax)) {
4126         /* Old hybrid cells add new cells and hybrid face */
4127         for (r = 0; r < 2; ++r, ++m) {
4128           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
4129           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
4130           remotePointsNew[m].rank  = rrank;
4131         }
4132         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
4133         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*3 + (rp - rdepthMaxOld[n*(depth+1)+depth]);
4134         remotePointsNew[m].rank  = rrank;
4135         ++m;
4136       }
4137       break;
4138     case 5:
4139       /* Simplicial 3D */
4140       if ((p >= vStart) && (p < vEnd)) {
4141         /* Old vertices stay the same */
4142         localPointsNew[m]        = vStartNew     + (p  - vStart);
4143         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
4144         remotePointsNew[m].rank  = rrank;
4145         ++m;
4146       } else if ((p >= eStart) && (p < eEnd)) {
4147         /* Old edges add new edges and vertex */
4148         for (r = 0; r < 2; ++r, ++m) {
4149           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
4150           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
4151           remotePointsNew[m].rank  = rrank;
4152         }
4153         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
4154         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
4155         remotePointsNew[m].rank  = rrank;
4156         ++m;
4157       } else if ((p >= fStart) && (p < fEnd)) {
4158         /* Old faces add new faces and face edges */
4159         for (r = 0; r < 4; ++r, ++m) {
4160           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
4161           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
4162           remotePointsNew[m].rank  = rrank;
4163         }
4164         for (r = 0; r < 3; ++r, ++m) {
4165           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (p  - fStart)*3     + r;
4166           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + (rp - rfStart[n])*3 + r;
4167           remotePointsNew[m].rank  = rrank;
4168         }
4169       } else if ((p >= cStart) && (p < cEnd)) {
4170         /* Old cells add new cells and interior faces and edges */
4171         for (r = 0; r < 8; ++r, ++m) {
4172           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
4173           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
4174           remotePointsNew[m].rank  = rrank;
4175         }
4176         for (r = 0; r < 8; ++r, ++m) {
4177           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*4                    + (p  - cStart)*8     + r;
4178           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*4 + (rp - rcStart[n])*8 + r;
4179           remotePointsNew[m].rank  = rrank;
4180         }
4181         for (r = 0; r < 1; ++r, ++m) {
4182           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (fEnd - fStart)*3                    + (p  - cStart)*1     + r;
4183           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + rdepthSizeOld[n*(depth+1)+depth-1]*3 + (rp - rcStart[n])*1 + r;
4184           remotePointsNew[m].rank  = rrank;
4185         }
4186       }
4187       break;
4188     case 7:
4189       /* Hybrid Simplicial 3D */
4190       if ((p >= vStart) && (p < vEnd)) {
4191         /* Interior vertices stay the same */
4192         localPointsNew[m]        = vStartNew     + (p  - vStart);
4193         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
4194         remotePointsNew[m].rank  = rrank;
4195         ++m;
4196       } else if ((p >= eStart) && (p < eMax)) {
4197         /* Interior edges add new edges and vertex */
4198         for (r = 0; r < 2; ++r, ++m) {
4199           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
4200           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
4201           remotePointsNew[m].rank  = rrank;
4202         }
4203         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
4204         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
4205         remotePointsNew[m].rank  = rrank;
4206         ++m;
4207       } else if ((p >= eMax) && (p < eEnd)) {
4208         /* Hybrid edges stay the same */
4209         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - eMax);
4210         remotePointsNew[m].index = rvStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*3 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n]) + (rp - rdepthMaxOld[n*(depth+1)+1]);
4211         remotePointsNew[m].rank  = rrank;
4212         ++m;
4213       } else if ((p >= fStart) && (p < fMax)) {
4214         /* Interior faces add new faces and edges */
4215         for (r = 0; r < 4; ++r, ++m) {
4216           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
4217           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
4218           remotePointsNew[m].rank  = rrank;
4219         }
4220         for (r = 0; r < 3; ++r, ++m) {
4221           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*3     + r;
4222           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
4223           remotePointsNew[m].rank  = rrank;
4224         }
4225       } else if ((p >= fMax) && (p < fEnd)) {
4226         /* Hybrid faces add new faces and edges */
4227         for (r = 0; r < 2; ++r, ++m) {
4228           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fStart)*2     + r;
4229           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rfStart[n])*2 + r;
4230           remotePointsNew[m].rank  = rrank;
4231         }
4232         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)     + (cMax                            - cStart)     + (fEnd                                          - fMax);
4233         remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n]) + (rdepthSizeOld[n*(depth+1)+depth-1]+rfStart[n] - rdepthMaxOld[n*(depth+1)+depth-1]);
4234         remotePointsNew[m].rank  = rrank;
4235       } else if ((p >= cStart) && (p < cMax)) {
4236         /* Interior cells add new cells, faces, and edges */
4237         for (r = 0; r < 8; ++r, ++m) {
4238           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
4239           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
4240           remotePointsNew[m].rank  = rrank;
4241         }
4242         for (r = 0; r < 8; ++r, ++m) {
4243           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*8     + r;
4244           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*8 + r;
4245           remotePointsNew[m].rank  = rrank;
4246         }
4247         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (p  - cStart)*1     + r;
4248         remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*3 + (rp - rcStart[n])*1 + r;
4249         remotePointsNew[m].rank  = rrank;
4250       } else if ((p >= cMax) && (p < cEnd)) {
4251         /* Hybrid cells add new cells and faces */
4252         for (r = 0; r < 4; ++r, ++m) {
4253           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
4254           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
4255           remotePointsNew[m].rank  = rrank;
4256         }
4257         for (r = 0; r < 3; ++r, ++m) {
4258           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*4                              + (p  - cMax)*3                            + r;
4259           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rdepthSizeOld[n*(depth+1)+depth-1]+rfStart[n] - rdepthMaxOld[n*(depth+1)+depth-1])*4 + (rp - rdepthMaxOld[n*(depth+1)+depth])*3 + r;
4260           remotePointsNew[m].rank  = rrank;
4261         }
4262       }
4263       break;
4264     case 6:
4265       /* Hex 3D */
4266       if ((p >= vStart) && (p < vEnd)) {
4267         /* Old vertices stay the same */
4268         localPointsNew[m]        = vStartNew     + (p  - vStart);
4269         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
4270         remotePointsNew[m].rank  = rrank;
4271         ++m;
4272       } else if ((p >= eStart) && (p < eEnd)) {
4273         /* Old edges add new edges and vertex */
4274         for (r = 0; r < 2; ++r, ++m) {
4275           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
4276           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
4277           remotePointsNew[m].rank  = rrank;
4278         }
4279         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
4280         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
4281         remotePointsNew[m].rank  = rrank;
4282         ++m;
4283       } else if ((p >= fStart) && (p < fEnd)) {
4284         /* Old faces add new faces, edges, and vertex */
4285         for (r = 0; r < 4; ++r, ++m) {
4286           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
4287           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
4288           remotePointsNew[m].rank  = rrank;
4289         }
4290         for (r = 0; r < 4; ++r, ++m) {
4291           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (p  - fStart)*4     + r;
4292           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + (rp - rfStart[n])*4 + r;
4293           remotePointsNew[m].rank  = rrank;
4294         }
4295         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eEnd - eStart)              + (p  - fStart);
4296         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+1] + (rp - rfStart[n]);
4297         remotePointsNew[m].rank  = rrank;
4298         ++m;
4299       } else if ((p >= cStart) && (p < cEnd)) {
4300         /* Old cells add new cells, faces, edges, and vertex */
4301         for (r = 0; r < 8; ++r, ++m) {
4302           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
4303           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
4304           remotePointsNew[m].rank  = rrank;
4305         }
4306         for (r = 0; r < 12; ++r, ++m) {
4307           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*4                    + (p  - cStart)*12     + r;
4308           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*4 + (rp - rcStart[n])*12 + r;
4309           remotePointsNew[m].rank  = rrank;
4310         }
4311         for (r = 0; r < 6; ++r, ++m) {
4312           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (fEnd - fStart)*4                    + (p  - cStart)*6     + r;
4313           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + rdepthSizeOld[n*(depth+1)+depth-1]*4 + (rp - rcStart[n])*6 + r;
4314           remotePointsNew[m].rank  = rrank;
4315         }
4316         for (r = 0; r < 1; ++r, ++m) {
4317           localPointsNew[m]        = vStartNew     + (eEnd - eStart)              + (fEnd - fStart)                    + (p  - cStart)     + r;
4318           remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+1] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]) + r;
4319           remotePointsNew[m].rank  = rrank;
4320         }
4321       }
4322       break;
4323     default:
4324       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
4325     }
4326   }
4327   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
4328   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
4329   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
4330   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
4331   ierr = PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
4332   PetscFunctionReturn(0);
4333 }
4334 
4335 #undef __FUNCT__
4336 #define __FUNCT__ "CellRefinerCreateLabels"
4337 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
4338 {
4339   PetscInt       numLabels, l;
4340   PetscInt       depth, newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r;
4341   PetscErrorCode ierr;
4342 
4343   PetscFunctionBegin;
4344   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4345   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
4346   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4347   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
4348   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4349   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
4350   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
4351   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
4352   switch (refiner) {
4353   case 0: break;
4354   case 7:
4355   case 8:
4356     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
4357   case 3:
4358   case 4:
4359     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
4360     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
4361   }
4362   for (l = 0; l < numLabels; ++l) {
4363     DMLabel         label, labelNew;
4364     const char     *lname;
4365     PetscBool       isDepth;
4366     IS              valueIS;
4367     const PetscInt *values;
4368     PetscInt        numValues, val;
4369 
4370     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
4371     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
4372     if (isDepth) continue;
4373     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
4374     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
4375     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
4376     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
4377     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
4378     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
4379     for (val = 0; val < numValues; ++val) {
4380       IS              pointIS;
4381       const PetscInt *points;
4382       PetscInt        numPoints, n;
4383 
4384       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
4385       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
4386       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
4387       for (n = 0; n < numPoints; ++n) {
4388         const PetscInt p = points[n];
4389         switch (refiner) {
4390         case 1:
4391           /* Simplicial 2D */
4392           if ((p >= vStart) && (p < vEnd)) {
4393             /* Old vertices stay the same */
4394             newp = vStartNew + (p - vStart);
4395             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4396           } else if ((p >= fStart) && (p < fEnd)) {
4397             /* Old faces add new faces and vertex */
4398             newp = vStartNew + (vEnd - vStart) + (p - fStart);
4399             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4400             for (r = 0; r < 2; ++r) {
4401               newp = fStartNew + (p - fStart)*2 + r;
4402               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4403             }
4404           } else if ((p >= cStart) && (p < cEnd)) {
4405             /* Old cells add new cells and interior faces */
4406             for (r = 0; r < 4; ++r) {
4407               newp = cStartNew + (p - cStart)*4 + r;
4408               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4409             }
4410             for (r = 0; r < 3; ++r) {
4411               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
4412               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4413             }
4414           }
4415           break;
4416         case 2:
4417           /* Hex 2D */
4418           if ((p >= vStart) && (p < vEnd)) {
4419             /* Old vertices stay the same */
4420             newp = vStartNew + (p - vStart);
4421             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4422           } else if ((p >= fStart) && (p < fEnd)) {
4423             /* Old faces add new faces and vertex */
4424             newp = vStartNew + (vEnd - vStart) + (p - fStart);
4425             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4426             for (r = 0; r < 2; ++r) {
4427               newp = fStartNew + (p - fStart)*2 + r;
4428               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4429             }
4430           } else if ((p >= cStart) && (p < cEnd)) {
4431             /* Old cells add new cells and interior faces and vertex */
4432             for (r = 0; r < 4; ++r) {
4433               newp = cStartNew + (p - cStart)*4 + r;
4434               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4435             }
4436             for (r = 0; r < 4; ++r) {
4437               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
4438               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4439             }
4440             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
4441             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4442           }
4443           break;
4444         case 3:
4445           /* Hybrid simplicial 2D */
4446           if ((p >= vStart) && (p < vEnd)) {
4447             /* Old vertices stay the same */
4448             newp = vStartNew + (p - vStart);
4449             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4450           } else if ((p >= fStart) && (p < fMax)) {
4451             /* Old interior faces add new faces and vertex */
4452             newp = vStartNew + (vEnd - vStart) + (p - fStart);
4453             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4454             for (r = 0; r < 2; ++r) {
4455               newp = fStartNew + (p - fStart)*2 + r;
4456               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4457             }
4458           } else if ((p >= fMax) && (p < fEnd)) {
4459             /* Old hybrid faces stay the same */
4460             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
4461             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4462           } else if ((p >= cStart) && (p < cMax)) {
4463             /* Old interior cells add new cells and interior faces */
4464             for (r = 0; r < 4; ++r) {
4465               newp = cStartNew + (p - cStart)*4 + r;
4466               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4467             }
4468             for (r = 0; r < 3; ++r) {
4469               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
4470               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4471             }
4472           } else if ((p >= cMax) && (p < cEnd)) {
4473             /* Old hybrid cells add new cells and hybrid face */
4474             for (r = 0; r < 2; ++r) {
4475               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
4476               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4477             }
4478             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
4479             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4480           }
4481           break;
4482         case 5:
4483           /* Simplicial 3D */
4484           if ((p >= vStart) && (p < vEnd)) {
4485             /* Old vertices stay the same */
4486             newp = vStartNew + (p - vStart);
4487             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4488           } else if ((p >= eStart) && (p < eEnd)) {
4489             /* Old edges add new edges and vertex */
4490             for (r = 0; r < 2; ++r) {
4491               newp = eStartNew + (p - eStart)*2 + r;
4492               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4493             }
4494             newp = vStartNew + (vEnd - vStart) + (p - eStart);
4495             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4496           } else if ((p >= fStart) && (p < fEnd)) {
4497             /* Old faces add new faces and edges */
4498             for (r = 0; r < 4; ++r) {
4499               newp = fStartNew + (p - fStart)*4 + r;
4500               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4501             }
4502             for (r = 0; r < 3; ++r) {
4503               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
4504               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4505             }
4506           } else if ((p >= cStart) && (p < cEnd)) {
4507             /* Old cells add new cells and interior faces and edges */
4508             for (r = 0; r < 8; ++r) {
4509               newp = cStartNew + (p - cStart)*8 + r;
4510               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4511             }
4512             for (r = 0; r < 8; ++r) {
4513               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*8 + r;
4514               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4515             }
4516             for (r = 0; r < 1; ++r) {
4517               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*1 + r;
4518               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4519             }
4520           }
4521           break;
4522         case 7:
4523           /* Hybrid Simplicial 3D */
4524           if ((p >= vStart) && (p < vEnd)) {
4525             /* Interior vertices stay the same */
4526             newp = vStartNew + (p - vStart);
4527             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4528           } else if ((p >= eStart) && (p < eMax)) {
4529             /* Interior edges add new edges and vertex */
4530             for (r = 0; r < 2; ++r) {
4531               newp = eStartNew + (p - eStart)*2 + r;
4532               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4533             }
4534             newp = vStartNew + (vEnd - vStart) + (p - eStart);
4535             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4536           } else if ((p >= eMax) && (p < eEnd)) {
4537             /* Hybrid edges stay the same */
4538             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - eMax);
4539             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4540           } else if ((p >= fStart) && (p < fMax)) {
4541             /* Interior faces add new faces and edges */
4542             for (r = 0; r < 4; ++r) {
4543               newp = fStartNew + (p - fStart)*4 + r;
4544               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4545             }
4546             for (r = 0; r < 3; ++r) {
4547               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
4548               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4549             }
4550           } else if ((p >= fMax) && (p < fEnd)) {
4551             /* Hybrid faces add new faces and edges */
4552             for (r = 0; r < 2; ++r) {
4553               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (p - fMax)*2 + r;
4554               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4555             }
4556             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - fMax);
4557             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4558           } else if ((p >= cStart) && (p < cMax)) {
4559             /* Interior cells add new cells, faces, and edges */
4560             for (r = 0; r < 8; ++r) {
4561               newp = cStartNew + (p - cStart)*8 + r;
4562               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4563             }
4564             for (r = 0; r < 8; ++r) {
4565               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*8 + r;
4566               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4567             }
4568             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart);
4569             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4570           } else if ((p >= cMax) && (p < cEnd)) {
4571             /* Hybrid cells add new cells and faces */
4572             for (r = 0; r < 4; ++r) {
4573               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
4574               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4575             }
4576             for (r = 0; r < 3; ++r) {
4577               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
4578               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4579             }
4580           }
4581           break;
4582         case 6:
4583           /* Hex 3D */
4584           if ((p >= vStart) && (p < vEnd)) {
4585             /* Old vertices stay the same */
4586             newp = vStartNew + (p - vStart);
4587             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4588           } else if ((p >= eStart) && (p < eEnd)) {
4589             /* Old edges add new edges and vertex */
4590             for (r = 0; r < 2; ++r) {
4591               newp = eStartNew + (p - eStart)*2 + r;
4592               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4593             }
4594             newp = vStartNew + (vEnd - vStart) + (p - eStart);
4595             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4596           } else if ((p >= fStart) && (p < fEnd)) {
4597             /* Old faces add new faces, edges, and vertex */
4598             for (r = 0; r < 4; ++r) {
4599               newp = fStartNew + (p - fStart)*4 + r;
4600               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4601             }
4602             for (r = 0; r < 4; ++r) {
4603               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*4 + r;
4604               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4605             }
4606             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (p - fStart);
4607             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4608           } else if ((p >= cStart) && (p < cEnd)) {
4609             /* Old cells add new cells, faces, edges, and vertex */
4610             for (r = 0; r < 8; ++r) {
4611               newp = cStartNew + (p - cStart)*8 + r;
4612               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4613             }
4614             for (r = 0; r < 12; ++r) {
4615               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*12 + r;
4616               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4617             }
4618             for (r = 0; r < 6; ++r) {
4619               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (p - cStart)*6 + r;
4620               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4621             }
4622             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (p - cStart);
4623             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4624           }
4625           break;
4626         default:
4627           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
4628         }
4629       }
4630       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
4631       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
4632     }
4633     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
4634     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
4635     if (0) {
4636       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
4637       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4638       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4639     }
4640   }
4641   PetscFunctionReturn(0);
4642 }
4643 
4644 #undef __FUNCT__
4645 #define __FUNCT__ "DMPlexRefineUniform_Internal"
4646 /* This will only work for interpolated meshes */
4647 PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
4648 {
4649   DM             rdm;
4650   PetscInt      *depthSize;
4651   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
4652   PetscErrorCode ierr;
4653 
4654   PetscFunctionBegin;
4655   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
4656   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
4657   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4658   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
4659   /* Calculate number of new points of each depth */
4660   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4661   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
4662   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
4663   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
4664   /* Step 1: Set chart */
4665   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
4666   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
4667   /* Step 2: Set cone/support sizes */
4668   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
4669   /* Step 3: Setup refined DM */
4670   ierr = DMSetUp(rdm);CHKERRQ(ierr);
4671   /* Step 4: Set cones and supports */
4672   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
4673   /* Step 5: Stratify */
4674   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
4675   /* Step 6: Set coordinates for vertices */
4676   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
4677   /* Step 7: Create pointSF */
4678   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
4679   /* Step 8: Create labels */
4680   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
4681   ierr = PetscFree(depthSize);CHKERRQ(ierr);
4682 
4683   *dmRefined = rdm;
4684   PetscFunctionReturn(0);
4685 }
4686 
4687 #undef __FUNCT__
4688 #define __FUNCT__ "DMPlexSetRefinementUniform"
4689 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
4690 {
4691   DM_Plex *mesh = (DM_Plex*) dm->data;
4692 
4693   PetscFunctionBegin;
4694   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4695   mesh->refinementUniform = refinementUniform;
4696   PetscFunctionReturn(0);
4697 }
4698 
4699 #undef __FUNCT__
4700 #define __FUNCT__ "DMPlexGetRefinementUniform"
4701 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
4702 {
4703   DM_Plex *mesh = (DM_Plex*) dm->data;
4704 
4705   PetscFunctionBegin;
4706   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4707   PetscValidPointer(refinementUniform,  2);
4708   *refinementUniform = mesh->refinementUniform;
4709   PetscFunctionReturn(0);
4710 }
4711 
4712 #undef __FUNCT__
4713 #define __FUNCT__ "DMPlexSetRefinementLimit"
4714 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
4715 {
4716   DM_Plex *mesh = (DM_Plex*) dm->data;
4717 
4718   PetscFunctionBegin;
4719   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4720   mesh->refinementLimit = refinementLimit;
4721   PetscFunctionReturn(0);
4722 }
4723 
4724 #undef __FUNCT__
4725 #define __FUNCT__ "DMPlexGetRefinementLimit"
4726 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
4727 {
4728   DM_Plex *mesh = (DM_Plex*) dm->data;
4729 
4730   PetscFunctionBegin;
4731   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4732   PetscValidPointer(refinementLimit,  2);
4733   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
4734   *refinementLimit = mesh->refinementLimit;
4735   PetscFunctionReturn(0);
4736 }
4737 
4738 #undef __FUNCT__
4739 #define __FUNCT__ "DMPlexGetCellRefiner_Internal"
4740 PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
4741 {
4742   PetscInt       dim, cStart, cEnd, coneSize, cMax;
4743   PetscErrorCode ierr;
4744 
4745   PetscFunctionBegin;
4746   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4747   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4748   if (cEnd <= cStart) {*cellRefiner = 0; PetscFunctionReturn(0);}
4749   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
4750   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
4751   switch (dim) {
4752   case 2:
4753     switch (coneSize) {
4754     case 3:
4755       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
4756       else *cellRefiner = 1; /* Triangular */
4757       break;
4758     case 4:
4759       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
4760       else *cellRefiner = 2; /* Quadrilateral */
4761       break;
4762     default:
4763       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
4764     }
4765     break;
4766   case 3:
4767     switch (coneSize) {
4768     case 4:
4769       if (cMax >= 0) *cellRefiner = 7; /* Hybrid */
4770       else *cellRefiner = 5; /* Tetrahedral */
4771       break;
4772     case 6:
4773       if (cMax >= 0) *cellRefiner = 8; /* Hybrid */
4774       else *cellRefiner = 6; /* hexahedral */
4775       break;
4776     default:
4777       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
4778     }
4779     break;
4780   default:
4781     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
4782   }
4783   PetscFunctionReturn(0);
4784 }
4785