xref: /petsc/src/dm/impls/plex/plexrefine.c (revision 623f434855bb2ee033dbf9f04c49d2116bc3c3f7)
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 + (GetTriSubfaceInverse_Static(ornt[c], 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, *cornt;
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         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
2912         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
2913         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]);
2914         supportRef[2+s*2+0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + GetTriSubfaceInverse_Static(cornt[0], c-2);
2915         supportRef[2+s*2+1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (GetTriSubfaceInverse_Static(cornt[0], c-2) + 1)%3;
2916       }
2917       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2918 #if 1
2919       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
2920       for (p = 0; p < 2+size*2; ++p) {
2921         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);
2922       }
2923 #endif
2924     }
2925     /* Interior vertices have identical supports */
2926     for (v = vStart; v < vEnd; ++v) {
2927       const PetscInt  newp = vStartNew + (v - vStart);
2928       const PetscInt *support, *cone;
2929       PetscInt        size, s;
2930 
2931       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2932       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2933       for (s = 0; s < size; ++s) {
2934         PetscInt r = 0;
2935 
2936         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2937         if (cone[1] == v) r = 1;
2938         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
2939         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (support[s] - eMax);
2940       }
2941       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2942 #if 1
2943       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2944       for (p = 0; p < size; ++p) {
2945         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);
2946       }
2947 #endif
2948     }
2949     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
2950     for (e = eStart; e < eMax; ++e) {
2951       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
2952       const PetscInt *cone, *support;
2953       PetscInt       *star = NULL, starSize, faceSize = 0, cellSize = 0, coneSize, size, s;
2954 
2955       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
2956       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
2957       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
2958       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
2959       for (s = 0; s < size; ++s) {
2960         PetscInt r = 0;
2961 
2962         if (support[s] < fMax) {
2963           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2964           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2965           for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
2966           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
2967           supportRef[2+faceSize+1] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
2968           faceSize += 2;
2969         } else {
2970           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (support[s] - fMax);
2971           ++faceSize;
2972         }
2973       }
2974       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
2975       for (s = 0; s < starSize*2; s += 2) {
2976         const PetscInt *cone, *ornt;
2977         PetscInt        e01, e23;
2978 
2979         if ((star[s] >= cStart) && (star[s] < cMax)) {
2980           /* Check edge 0-1 */
2981           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
2982           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
2983           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
2984           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
2985           /* Check edge 2-3 */
2986           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
2987           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
2988           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
2989           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
2990           if ((e01 == e) || (e23 == e)) {supportRef[2+faceSize+cellSize++] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (star[s] - cStart);}
2991         }
2992       }
2993       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
2994       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2995 #if 1
2996       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2997       for (p = 0; p < 2+faceSize+cellSize; ++p) {
2998         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);
2999       }
3000 #endif
3001     }
3002     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3003     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
3004     break;
3005   case 6:
3006     /* Hex 3D */
3007     /*
3008      Bottom (viewed from top)    Top
3009      1---------2---------2       7---------2---------6
3010      |         |         |       |         |         |
3011      |    B    2    C    |       |    H    2    G    |
3012      |         |         |       |         |         |
3013      3----3----0----1----1       3----3----0----1----1
3014      |         |         |       |         |         |
3015      |    A    0    D    |       |    E    0    F    |
3016      |         |         |       |         |         |
3017      0---------0---------3       4---------0---------5
3018      */
3019     /* All cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
3020     for (c = cStart; c < cEnd; ++c) {
3021       const PetscInt  newp = (c - cStart)*8;
3022       const PetscInt *cone, *ornt;
3023       PetscInt        coneNew[6], orntNew[6];
3024 
3025       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3026       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3027       /* A hex */
3028       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
3029       orntNew[0] = ornt[0];
3030       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
3031       orntNew[1] = 0;
3032       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
3033       orntNew[2] = ornt[2];
3034       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
3035       orntNew[3] = 0;
3036       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
3037       orntNew[4] = 0;
3038       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
3039       orntNew[5] = ornt[5];
3040       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3041       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3042 #if 1
3043       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);
3044       for (p = 0; p < 6; ++p) {
3045         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);
3046       }
3047 #endif
3048       /* B hex */
3049       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
3050       orntNew[0] = ornt[0];
3051       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
3052       orntNew[1] = 0;
3053       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
3054       orntNew[2] = -3;
3055       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
3056       orntNew[3] = ornt[3];
3057       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
3058       orntNew[4] = 0;
3059       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
3060       orntNew[5] = ornt[5];
3061       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3062       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3063 #if 1
3064       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);
3065       for (p = 0; p < 6; ++p) {
3066         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);
3067       }
3068 #endif
3069       /* C hex */
3070       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
3071       orntNew[0] = ornt[0];
3072       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
3073       orntNew[1] = 0;
3074       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
3075       orntNew[2] = 0;
3076       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
3077       orntNew[3] = ornt[3];
3078       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
3079       orntNew[4] = ornt[4];
3080       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
3081       orntNew[5] = -3;
3082       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3083       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3084 #if 1
3085       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);
3086       for (p = 0; p < 6; ++p) {
3087         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);
3088       }
3089 #endif
3090       /* D hex */
3091       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
3092       orntNew[0] = ornt[0];
3093       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
3094       orntNew[1] = 0;
3095       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
3096       orntNew[2] = ornt[2];
3097       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
3098       orntNew[3] = -3;
3099       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
3100       orntNew[4] = ornt[4];
3101       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
3102       orntNew[5] = -3;
3103       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3104       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3105 #if 1
3106       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);
3107       for (p = 0; p < 6; ++p) {
3108         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);
3109       }
3110 #endif
3111       /* E hex */
3112       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
3113       orntNew[0] = -3;
3114       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
3115       orntNew[1] = ornt[1];
3116       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
3117       orntNew[2] = ornt[2];
3118       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
3119       orntNew[3] = 0;
3120       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
3121       orntNew[4] = 0;
3122       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
3123       orntNew[5] = ornt[5];
3124       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
3125       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
3126 #if 1
3127       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);
3128       for (p = 0; p < 6; ++p) {
3129         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);
3130       }
3131 #endif
3132       /* F hex */
3133       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
3134       orntNew[0] = -3;
3135       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
3136       orntNew[1] = ornt[1];
3137       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
3138       orntNew[2] = ornt[2];
3139       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
3140       orntNew[3] = 0;
3141       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
3142       orntNew[4] = ornt[4];
3143       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
3144       orntNew[5] = -3;
3145       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
3146       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
3147 #if 1
3148       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);
3149       for (p = 0; p < 6; ++p) {
3150         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);
3151       }
3152 #endif
3153       /* G hex */
3154       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
3155       orntNew[0] = -3;
3156       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
3157       orntNew[1] = ornt[1];
3158       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
3159       orntNew[2] = -3;
3160       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
3161       orntNew[3] = ornt[3];
3162       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
3163       orntNew[4] = ornt[4];
3164       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
3165       orntNew[5] = 0;
3166       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
3167       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
3168 #if 1
3169       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);
3170       for (p = 0; p < 6; ++p) {
3171         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);
3172       }
3173 #endif
3174       /* H hex */
3175       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
3176       orntNew[0] = -3;
3177       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
3178       orntNew[1] = ornt[1];
3179       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
3180       orntNew[2] = -3;
3181       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
3182       orntNew[3] = ornt[3];
3183       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
3184       orntNew[4] = -3;
3185       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
3186       orntNew[5] = ornt[5];
3187       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
3188       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
3189 #if 1
3190       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);
3191       for (p = 0; p < 6; ++p) {
3192         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);
3193       }
3194 #endif
3195     }
3196     /* Split faces have 4 edges and the same cells as the parent */
3197     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3198     ierr = PetscMalloc((4 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
3199     for (f = fStart; f < fEnd; ++f) {
3200       for (r = 0; r < 4; ++r) {
3201         /* TODO: This can come from GetFaces_Internal() */
3202         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};
3203         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
3204         const PetscInt *cone, *ornt, *support;
3205         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
3206 
3207         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3208         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3209         coneNew[0] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
3210         orntNew[0] = ornt[(r+3)%4];
3211         coneNew[1] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
3212         orntNew[1] = ornt[r];
3213         coneNew[2] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
3214         orntNew[2] = 0;
3215         coneNew[3] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + (r+3)%4;
3216         orntNew[3] = -2;
3217         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3218         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3219 #if 1
3220         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3221         for (p = 0; p < 4; ++p) {
3222           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);
3223         }
3224 #endif
3225         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3226         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3227         for (s = 0; s < supportSize; ++s) {
3228           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3229           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3230           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3231           for (c = 0; c < coneSize; ++c) {
3232             if (cone[c] == f) break;
3233           }
3234           supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+GetQuadSubface_Static(ornt[c], r)];
3235         }
3236         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3237 #if 1
3238         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3239         for (p = 0; p < supportSize; ++p) {
3240           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);
3241         }
3242 #endif
3243       }
3244     }
3245     /* Interior faces have 4 edges and 2 cells */
3246     for (c = cStart; c < cEnd; ++c) {
3247       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};
3248       const PetscInt *cone, *ornt;
3249       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
3250 
3251       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3252       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3253       /* A-D face */
3254       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 0;
3255       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
3256       orntNew[0] = -2;
3257       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
3258       orntNew[1] = 0;
3259       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
3260       orntNew[2] = 0;
3261       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
3262       orntNew[3] = -2;
3263       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3264       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3265 #if 1
3266       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3267       for (p = 0; p < 4; ++p) {
3268         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);
3269       }
3270 #endif
3271       /* C-D face */
3272       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 1;
3273       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
3274       orntNew[0] = -2;
3275       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
3276       orntNew[1] = 0;
3277       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
3278       orntNew[2] = 0;
3279       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
3280       orntNew[3] = -2;
3281       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3282       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3283 #if 1
3284       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3285       for (p = 0; p < 4; ++p) {
3286         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);
3287       }
3288 #endif
3289       /* B-C face */
3290       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 2;
3291       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
3292       orntNew[0] = -2;
3293       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
3294       orntNew[1] = 0;
3295       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
3296       orntNew[2] = 0;
3297       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
3298       orntNew[3] = -2;
3299       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3300       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3301 #if 1
3302       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3303       for (p = 0; p < 4; ++p) {
3304         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);
3305       }
3306 #endif
3307       /* A-B face */
3308       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 3;
3309       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
3310       orntNew[0] = -2;
3311       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
3312       orntNew[1] = 0;
3313       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
3314       orntNew[2] = 0;
3315       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
3316       orntNew[3] = -2;
3317       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3318       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3319 #if 1
3320       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3321       for (p = 0; p < 4; ++p) {
3322         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);
3323       }
3324 #endif
3325       /* E-F face */
3326       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 4;
3327       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
3328       orntNew[0] = -2;
3329       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
3330       orntNew[1] = 0;
3331       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
3332       orntNew[2] = 0;
3333       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
3334       orntNew[3] = -2;
3335       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3336       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3337 #if 1
3338       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3339       for (p = 0; p < 4; ++p) {
3340         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);
3341       }
3342 #endif
3343       /* F-G face */
3344       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 5;
3345       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
3346       orntNew[0] = -2;
3347       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
3348       orntNew[1] = 0;
3349       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
3350       orntNew[2] = 0;
3351       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
3352       orntNew[3] = -2;
3353       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3354       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3355 #if 1
3356       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3357       for (p = 0; p < 4; ++p) {
3358         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);
3359       }
3360 #endif
3361       /* G-H face */
3362       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 6;
3363       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
3364       orntNew[0] = -2;
3365       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
3366       orntNew[1] = 0;
3367       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
3368       orntNew[2] = 0;
3369       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
3370       orntNew[3] = -2;
3371       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3372       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3373 #if 1
3374       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3375       for (p = 0; p < 4; ++p) {
3376         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);
3377       }
3378 #endif
3379       /* E-H face */
3380       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 7;
3381       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
3382       orntNew[0] = -2;
3383       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
3384       orntNew[1] = 0;
3385       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
3386       orntNew[2] = 0;
3387       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
3388       orntNew[3] = -2;
3389       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3390       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3391 #if 1
3392       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3393       for (p = 0; p < 4; ++p) {
3394         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);
3395       }
3396 #endif
3397       /* A-E face */
3398       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 8;
3399       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
3400       orntNew[0] = -2;
3401       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
3402       orntNew[1] = 0;
3403       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
3404       orntNew[2] = 0;
3405       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
3406       orntNew[3] = -2;
3407       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3408       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3409 #if 1
3410       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3411       for (p = 0; p < 4; ++p) {
3412         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);
3413       }
3414 #endif
3415       /* D-F face */
3416       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 9;
3417       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
3418       orntNew[0] = -2;
3419       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
3420       orntNew[1] = 0;
3421       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
3422       orntNew[2] = 0;
3423       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
3424       orntNew[3] = -2;
3425       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3426       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3427 #if 1
3428       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3429       for (p = 0; p < 4; ++p) {
3430         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);
3431       }
3432 #endif
3433       /* C-G face */
3434       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 10;
3435       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
3436       orntNew[0] = -2;
3437       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
3438       orntNew[1] = 0;
3439       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
3440       orntNew[2] = 0;
3441       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
3442       orntNew[3] = -2;
3443       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3444       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3445 #if 1
3446       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3447       for (p = 0; p < 4; ++p) {
3448         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);
3449       }
3450 #endif
3451       /* B-H face */
3452       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 11;
3453       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
3454       orntNew[0] = -2;
3455       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
3456       orntNew[1] = 0;
3457       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
3458       orntNew[2] = 0;
3459       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
3460       orntNew[3] = -2;
3461       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3462       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3463 #if 1
3464       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3465       for (p = 0; p < 4; ++p) {
3466         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);
3467       }
3468 #endif
3469       for (r = 0; r < 12; ++r) {
3470         newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
3471         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
3472         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
3473         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3474 #if 1
3475         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3476         for (p = 0; p < 2; ++p) {
3477           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);
3478         }
3479 #endif
3480       }
3481     }
3482     /* Split edges have 2 vertices and the same faces as the parent */
3483     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3484     for (e = eStart; e < eEnd; ++e) {
3485       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
3486 
3487       for (r = 0; r < 2; ++r) {
3488         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
3489         const PetscInt *cone, *ornt, *support;
3490         PetscInt        coneNew[2], coneSize, c, supportSize, s;
3491 
3492         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3493         coneNew[0]       = vStartNew + (cone[0] - vStart);
3494         coneNew[1]       = vStartNew + (cone[1] - vStart);
3495         coneNew[(r+1)%2] = newv;
3496         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3497 #if 1
3498         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3499         for (p = 0; p < 2; ++p) {
3500           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);
3501         }
3502 #endif
3503         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
3504         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3505         for (s = 0; s < supportSize; ++s) {
3506           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3507           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3508           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3509           for (c = 0; c < coneSize; ++c) {
3510             if (cone[c] == e) break;
3511           }
3512           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
3513         }
3514         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3515 #if 1
3516         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3517         for (p = 0; p < supportSize; ++p) {
3518           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);
3519         }
3520 #endif
3521       }
3522     }
3523     /* Face edges have 2 vertices and 2+cells faces */
3524     for (f = fStart; f < fEnd; ++f) {
3525       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};
3526       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
3527       const PetscInt *cone, *coneCell, *orntCell, *support;
3528       PetscInt        coneNew[2], coneSize, c, supportSize, s;
3529 
3530       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3531       for (r = 0; r < 4; ++r) {
3532         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
3533 
3534         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
3535         coneNew[1] = newv;
3536         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3537 #if 1
3538         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3539         for (p = 0; p < 2; ++p) {
3540           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);
3541         }
3542 #endif
3543         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3544         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3545         supportRef[0] = fStartNew + (f - fStart)*4 + r;
3546         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
3547         for (s = 0; s < supportSize; ++s) {
3548           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3549           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
3550           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
3551           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
3552           supportRef[2+s] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdge_Static(orntCell[c], r)];
3553         }
3554         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3555 #if 1
3556         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3557         for (p = 0; p < 2+supportSize; ++p) {
3558           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);
3559         }
3560 #endif
3561       }
3562     }
3563     /* Cell edges have 2 vertices and 4 faces */
3564     for (c = cStart; c < cEnd; ++c) {
3565       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};
3566       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
3567       const PetscInt *cone;
3568       PetscInt        coneNew[2], supportNew[4];
3569 
3570       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3571       for (r = 0; r < 6; ++r) {
3572         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
3573 
3574         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
3575         coneNew[1] = newv;
3576         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3577 #if 1
3578         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3579         for (p = 0; p < 2; ++p) {
3580           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);
3581         }
3582 #endif
3583         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
3584         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3585 #if 1
3586         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3587         for (p = 0; p < 4; ++p) {
3588           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);
3589         }
3590 #endif
3591       }
3592     }
3593     /* Old vertices have identical supports */
3594     for (v = vStart; v < vEnd; ++v) {
3595       const PetscInt  newp = vStartNew + (v - vStart);
3596       const PetscInt *support, *cone;
3597       PetscInt        size, s;
3598 
3599       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
3600       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
3601       for (s = 0; s < size; ++s) {
3602         PetscInt r = 0;
3603 
3604         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3605         if (cone[1] == v) r = 1;
3606         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
3607       }
3608       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3609 #if 1
3610       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3611       for (p = 0; p < size; ++p) {
3612         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);
3613       }
3614 #endif
3615     }
3616     /* Edge vertices have 2 + faces supports */
3617     for (e = eStart; e < eEnd; ++e) {
3618       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
3619       const PetscInt *cone, *support;
3620       PetscInt        size, s;
3621 
3622       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
3623       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3624       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
3625       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
3626       for (s = 0; s < size; ++s) {
3627         PetscInt r;
3628 
3629         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3630         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
3631         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*4 + r;
3632       }
3633       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3634 #if 1
3635       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3636       for (p = 0; p < 2+size; ++p) {
3637         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);
3638       }
3639 #endif
3640     }
3641     /* Face vertices have 4 + cells supports */
3642     for (f = fStart; f < fEnd; ++f) {
3643       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
3644       const PetscInt *cone, *support;
3645       PetscInt        size, s;
3646 
3647       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3648       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3649       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (e - eStart)*2 +  (f - fStart)*4 + r;
3650       for (s = 0; s < size; ++s) {
3651         PetscInt r;
3652 
3653         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3654         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
3655         supportRef[4+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (support[s] - cStart)*6 + r;
3656       }
3657       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3658 #if 1
3659       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3660       for (p = 0; p < 4+size; ++p) {
3661         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);
3662       }
3663 #endif
3664     }
3665     /* Cell vertices have 6 supports */
3666     for (c = cStart; c < cEnd; ++c) {
3667       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
3668       PetscInt       supportNew[6];
3669 
3670       for (r = 0; r < 6; ++r) {
3671         supportNew[r] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
3672       }
3673       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3674     }
3675     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3676     break;
3677   default:
3678     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
3679   }
3680   PetscFunctionReturn(0);
3681 }
3682 
3683 #undef __FUNCT__
3684 #define __FUNCT__ "CellRefinerSetCoordinates"
3685 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
3686 {
3687   PetscSection   coordSection, coordSectionNew;
3688   Vec            coordinates, coordinatesNew;
3689   PetscScalar   *coords, *coordsNew;
3690   const PetscInt numVertices = depthSize ? depthSize[0] : 0;
3691   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, eStart, eEnd, eMax, e, fStart, fEnd, fMax, f;
3692   PetscErrorCode ierr;
3693 
3694   PetscFunctionBegin;
3695   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3696   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3697   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3698   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
3699   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3700   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
3701   ierr = DMPlexGetHybridBounds(dm, NULL, &fMax, &eMax, NULL);CHKERRQ(ierr);
3702   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);}
3703   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
3704   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3705   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
3706   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
3707   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
3708   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+numVertices);CHKERRQ(ierr);
3709   if (fMax < 0) fMax = fEnd;
3710   if (eMax < 0) eMax = eEnd;
3711   /* All vertices have the dim coordinates */
3712   for (v = vStartNew; v < vStartNew+numVertices; ++v) {
3713     ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
3714     ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
3715   }
3716   ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
3717   ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
3718   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3719   ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
3720   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);CHKERRQ(ierr);
3721   ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
3722   ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
3723   ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
3724   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
3725   ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
3726   switch (refiner) {
3727   case 0: break;
3728   case 6: /* Hex 3D */
3729     /* Face vertices have the average of corner coordinates */
3730     for (f = fStart; f < fEnd; ++f) {
3731       const PetscInt newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
3732       PetscInt      *cone = NULL;
3733       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
3734 
3735       ierr = DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
3736       for (p = 0; p < closureSize*2; p += 2) {
3737         const PetscInt point = cone[p];
3738         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
3739       }
3740       for (v = 0; v < coneSize; ++v) {
3741         ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
3742       }
3743       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
3744       for (d = 0; d < dim; ++d) {
3745         coordsNew[offnew+d] = 0.0;
3746         for (v = 0; v < coneSize; ++v) coordsNew[offnew+d] += coords[off[v]+d];
3747         coordsNew[offnew+d] /= coneSize;
3748       }
3749       ierr = DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
3750     }
3751   case 2: /* Hex 2D */
3752     /* Cell vertices have the average of corner coordinates */
3753     for (c = cStart; c < cEnd; ++c) {
3754       const PetscInt newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (c - cStart) + (dim > 2 ? (fEnd - fStart) : 0);
3755       PetscInt      *cone = NULL;
3756       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
3757 
3758       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
3759       for (p = 0; p < closureSize*2; p += 2) {
3760         const PetscInt point = cone[p];
3761         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
3762       }
3763       for (v = 0; v < coneSize; ++v) {
3764         ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
3765       }
3766       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
3767       for (d = 0; d < dim; ++d) {
3768         coordsNew[offnew+d] = 0.0;
3769         for (v = 0; v < coneSize; ++v) coordsNew[offnew+d] += coords[off[v]+d];
3770         coordsNew[offnew+d] /= coneSize;
3771       }
3772       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
3773     }
3774   case 1: /* Simplicial 2D */
3775   case 3: /* Hybrid Simplicial 2D */
3776   case 5: /* Simplicial 3D */
3777   case 7: /* Hybrid Simplicial 3D */
3778     /* Edge vertices have the average of endpoint coordinates */
3779     for (e = eStart; e < eMax; ++e) {
3780       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
3781       const PetscInt *cone;
3782       PetscInt        coneSize, offA, offB, offnew, d;
3783 
3784       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
3785       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
3786       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3787       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
3788       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
3789       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
3790       for (d = 0; d < dim; ++d) {
3791         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
3792       }
3793     }
3794     /* Old vertices have the same coordinates */
3795     for (v = vStart; v < vEnd; ++v) {
3796       const PetscInt newv = vStartNew + (v - vStart);
3797       PetscInt       off, offnew, d;
3798 
3799       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3800       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
3801       for (d = 0; d < dim; ++d) {
3802         coordsNew[offnew+d] = coords[off+d];
3803       }
3804     }
3805     break;
3806   default:
3807     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
3808   }
3809   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
3810   ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
3811   ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
3812   ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
3813   ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
3814   PetscFunctionReturn(0);
3815 }
3816 
3817 #undef __FUNCT__
3818 #define __FUNCT__ "DMPlexCreateProcessSF"
3819 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
3820 {
3821   PetscInt           numRoots, numLeaves, l;
3822   const PetscInt    *localPoints;
3823   const PetscSFNode *remotePoints;
3824   PetscInt          *localPointsNew;
3825   PetscSFNode       *remotePointsNew;
3826   PetscInt          *ranks, *ranksNew;
3827   PetscErrorCode     ierr;
3828 
3829   PetscFunctionBegin;
3830   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3831   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
3832   for (l = 0; l < numLeaves; ++l) {
3833     ranks[l] = remotePoints[l].rank;
3834   }
3835   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
3836   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
3837   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
3838   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
3839   for (l = 0; l < numLeaves; ++l) {
3840     ranksNew[l]              = ranks[l];
3841     localPointsNew[l]        = l;
3842     remotePointsNew[l].index = 0;
3843     remotePointsNew[l].rank  = ranksNew[l];
3844   }
3845   ierr = PetscFree(ranks);CHKERRQ(ierr);
3846   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
3847   ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
3848   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
3849   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
3850   PetscFunctionReturn(0);
3851 }
3852 
3853 #undef __FUNCT__
3854 #define __FUNCT__ "CellRefinerCreateSF"
3855 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
3856 {
3857   PetscSF            sf, sfNew, sfProcess;
3858   IS                 processRanks;
3859   MPI_Datatype       depthType;
3860   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
3861   const PetscInt    *localPoints, *neighbors;
3862   const PetscSFNode *remotePoints;
3863   PetscInt          *localPointsNew;
3864   PetscSFNode       *remotePointsNew;
3865   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
3866   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
3867   PetscErrorCode     ierr;
3868 
3869   PetscFunctionBegin;
3870   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
3871   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3872   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3873   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
3874   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3875   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
3876   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
3877   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
3878   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
3879   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
3880   /* Caculate size of new SF */
3881   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3882   if (numRoots < 0) PetscFunctionReturn(0);
3883   for (l = 0; l < numLeaves; ++l) {
3884     const PetscInt p = localPoints[l];
3885 
3886     switch (refiner) {
3887     case 1:
3888       /* Simplicial 2D */
3889       if ((p >= vStart) && (p < vEnd)) {
3890         /* Old vertices stay the same */
3891         ++numLeavesNew;
3892       } else if ((p >= fStart) && (p < fEnd)) {
3893         /* Old faces add new faces and vertex */
3894         numLeavesNew += 2 + 1;
3895       } else if ((p >= cStart) && (p < cEnd)) {
3896         /* Old cells add new cells and interior faces */
3897         numLeavesNew += 4 + 3;
3898       }
3899       break;
3900     case 2:
3901       /* Hex 2D */
3902       if ((p >= vStart) && (p < vEnd)) {
3903         /* Old vertices stay the same */
3904         ++numLeavesNew;
3905       } else if ((p >= fStart) && (p < fEnd)) {
3906         /* Old faces add new faces and vertex */
3907         numLeavesNew += 2 + 1;
3908       } else if ((p >= cStart) && (p < cEnd)) {
3909         /* Old cells add new cells, interior faces, and vertex */
3910         numLeavesNew += 4 + 4 + 1;
3911       }
3912       break;
3913     case 5:
3914       /* Simplicial 3D */
3915       if ((p >= vStart) && (p < vEnd)) {
3916         /* Old vertices stay the same */
3917         ++numLeavesNew;
3918       } else if ((p >= eStart) && (p < eEnd)) {
3919         /* Old edges add new edges and vertex */
3920         numLeavesNew += 2 + 1;
3921       } else if ((p >= fStart) && (p < fEnd)) {
3922         /* Old faces add new faces and face edges */
3923         numLeavesNew += 4 + 3;
3924       } else if ((p >= cStart) && (p < cEnd)) {
3925         /* Old cells add new cells and interior faces and edges */
3926         numLeavesNew += 8 + 8 + 1;
3927       }
3928       break;
3929     case 7:
3930       /* Hybrid Simplicial 3D */
3931       if ((p >= vStart) && (p < vEnd)) {
3932         /* Interior vertices stay the same */
3933         ++numLeavesNew;
3934       } else if ((p >= eStart) && (p < eMax)) {
3935         /* Interior edges add new edges and vertex */
3936         numLeavesNew += 2 + 1;
3937       } else if ((p >= eMax) && (p < eEnd)) {
3938         /* Hybrid edges stay the same */
3939         ++numLeavesNew;
3940       } else if ((p >= fStart) && (p < fMax)) {
3941         /* Interior faces add new faces and edges */
3942         numLeavesNew += 4 + 3;
3943       } else if ((p >= fMax) && (p < fEnd)) {
3944         /* Hybrid faces add new faces and edges */
3945         numLeavesNew += 2 + 1;
3946       } else if ((p >= cStart) && (p < cMax)) {
3947         /* Interior cells add new cells, faces, and edges */
3948         numLeavesNew += 8 + 8 + 1;
3949       } else if ((p >= cMax) && (p < cEnd)) {
3950         /* Hybrid cells add new cells and faces */
3951         numLeavesNew += 4 + 3;
3952       }
3953       break;
3954     case 6:
3955       /* Hex 3D */
3956       if ((p >= vStart) && (p < vEnd)) {
3957         /* Old vertices stay the same */
3958         ++numLeavesNew;
3959       } else if ((p >= eStart) && (p < eEnd)) {
3960         /* Old edges add new edges, and vertex */
3961         numLeavesNew += 2 + 1;
3962       } else if ((p >= fStart) && (p < fEnd)) {
3963         /* Old faces add new faces, edges, and vertex */
3964         numLeavesNew += 4 + 4 + 1;
3965       } else if ((p >= cStart) && (p < cEnd)) {
3966         /* Old cells add new cells, faces, edges, and vertex */
3967         numLeavesNew += 8 + 12 + 6 + 1;
3968       }
3969       break;
3970     default:
3971       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
3972     }
3973   }
3974   /* Communicate depthSizes for each remote rank */
3975   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
3976   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
3977   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
3978   ierr = PetscMalloc7(depth+1,PetscInt,&depthSizeOld,(depth+1)*numNeighbors,PetscInt,&rdepthSizeOld,(depth+1)*numNeighbors,PetscInt,&rdepthMaxOld,numNeighbors,PetscInt,&rvStart,numNeighbors,PetscInt,&reStart,numNeighbors,PetscInt,&rfStart,numNeighbors,PetscInt,&rcStart);CHKERRQ(ierr);
3979   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
3980   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
3981   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
3982   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
3983   for (n = 0; n < numNeighbors; ++n) {
3984     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
3985   }
3986   depthSizeOld[depth]   = cMax;
3987   depthSizeOld[0]       = vMax;
3988   depthSizeOld[depth-1] = fMax;
3989   depthSizeOld[1]       = eMax;
3990 
3991   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
3992   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
3993 
3994   depthSizeOld[depth]   = cEnd - cStart;
3995   depthSizeOld[0]       = vEnd - vStart;
3996   depthSizeOld[depth-1] = fEnd - fStart;
3997   depthSizeOld[1]       = eEnd - eStart;
3998 
3999   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
4000   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
4001   for (n = 0; n < numNeighbors; ++n) {
4002     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
4003   }
4004   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
4005   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
4006   /* Calculate new point SF */
4007   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
4008   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
4009   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
4010   for (l = 0, m = 0; l < numLeaves; ++l) {
4011     PetscInt    p     = localPoints[l];
4012     PetscInt    rp    = remotePoints[l].index, n;
4013     PetscMPIInt rrank = remotePoints[l].rank;
4014 
4015     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
4016     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
4017     switch (refiner) {
4018     case 1:
4019       /* Simplicial 2D */
4020       if ((p >= vStart) && (p < vEnd)) {
4021         /* Old vertices stay the same */
4022         localPointsNew[m]        = vStartNew     + (p  - vStart);
4023         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
4024         remotePointsNew[m].rank  = rrank;
4025         ++m;
4026       } else if ((p >= fStart) && (p < fEnd)) {
4027         /* Old faces add new faces and vertex */
4028         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
4029         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
4030         remotePointsNew[m].rank  = rrank;
4031         ++m;
4032         for (r = 0; r < 2; ++r, ++m) {
4033           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
4034           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
4035           remotePointsNew[m].rank  = rrank;
4036         }
4037       } else if ((p >= cStart) && (p < cEnd)) {
4038         /* Old cells add new cells and interior faces */
4039         for (r = 0; r < 4; ++r, ++m) {
4040           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
4041           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
4042           remotePointsNew[m].rank  = rrank;
4043         }
4044         for (r = 0; r < 3; ++r, ++m) {
4045           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
4046           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
4047           remotePointsNew[m].rank  = rrank;
4048         }
4049       }
4050       break;
4051     case 2:
4052       /* Hex 2D */
4053       if ((p >= vStart) && (p < vEnd)) {
4054         /* Old vertices stay the same */
4055         localPointsNew[m]        = vStartNew     + (p  - vStart);
4056         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
4057         remotePointsNew[m].rank  = rrank;
4058         ++m;
4059       } else if ((p >= fStart) && (p < fEnd)) {
4060         /* Old faces add new faces and vertex */
4061         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
4062         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
4063         remotePointsNew[m].rank  = rrank;
4064         ++m;
4065         for (r = 0; r < 2; ++r, ++m) {
4066           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
4067           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
4068           remotePointsNew[m].rank  = rrank;
4069         }
4070       } else if ((p >= cStart) && (p < cEnd)) {
4071         /* Old cells add new cells, interior faces, and vertex */
4072         for (r = 0; r < 4; ++r, ++m) {
4073           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
4074           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
4075           remotePointsNew[m].rank  = rrank;
4076         }
4077         for (r = 0; r < 4; ++r, ++m) {
4078           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
4079           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
4080           remotePointsNew[m].rank  = rrank;
4081         }
4082         for (r = 0; r < 1; ++r, ++m) {
4083           localPointsNew[m]        = vStartNew     + (fEnd - fStart)                    + (p  - cStart)     + r;
4084           remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]) + r;
4085           remotePointsNew[m].rank  = rrank;
4086         }
4087       }
4088       break;
4089     case 3:
4090       /* Hybrid simplicial 2D */
4091       if ((p >= vStart) && (p < vEnd)) {
4092         /* Old vertices stay the same */
4093         localPointsNew[m]        = vStartNew     + (p  - vStart);
4094         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
4095         remotePointsNew[m].rank  = rrank;
4096         ++m;
4097       } else if ((p >= fStart) && (p < fMax)) {
4098         /* Old interior faces add new faces and vertex */
4099         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
4100         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
4101         remotePointsNew[m].rank  = rrank;
4102         ++m;
4103         for (r = 0; r < 2; ++r, ++m) {
4104           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
4105           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
4106           remotePointsNew[m].rank  = rrank;
4107         }
4108       } else if ((p >= fMax) && (p < fEnd)) {
4109         /* Old hybrid faces stay the same */
4110         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
4111         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
4112         remotePointsNew[m].rank  = rrank;
4113         ++m;
4114       } else if ((p >= cStart) && (p < cMax)) {
4115         /* Old interior cells add new cells and interior faces */
4116         for (r = 0; r < 4; ++r, ++m) {
4117           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
4118           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
4119           remotePointsNew[m].rank  = rrank;
4120         }
4121         for (r = 0; r < 3; ++r, ++m) {
4122           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
4123           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
4124           remotePointsNew[m].rank  = rrank;
4125         }
4126       } else if ((p >= cStart) && (p < cMax)) {
4127         /* Old hybrid cells add new cells and hybrid face */
4128         for (r = 0; r < 2; ++r, ++m) {
4129           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
4130           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
4131           remotePointsNew[m].rank  = rrank;
4132         }
4133         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
4134         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]);
4135         remotePointsNew[m].rank  = rrank;
4136         ++m;
4137       }
4138       break;
4139     case 5:
4140       /* Simplicial 3D */
4141       if ((p >= vStart) && (p < vEnd)) {
4142         /* Old vertices stay the same */
4143         localPointsNew[m]        = vStartNew     + (p  - vStart);
4144         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
4145         remotePointsNew[m].rank  = rrank;
4146         ++m;
4147       } else if ((p >= eStart) && (p < eEnd)) {
4148         /* Old edges add new edges and vertex */
4149         for (r = 0; r < 2; ++r, ++m) {
4150           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
4151           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
4152           remotePointsNew[m].rank  = rrank;
4153         }
4154         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
4155         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
4156         remotePointsNew[m].rank  = rrank;
4157         ++m;
4158       } else if ((p >= fStart) && (p < fEnd)) {
4159         /* Old faces add new faces and face edges */
4160         for (r = 0; r < 4; ++r, ++m) {
4161           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
4162           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
4163           remotePointsNew[m].rank  = rrank;
4164         }
4165         for (r = 0; r < 3; ++r, ++m) {
4166           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (p  - fStart)*3     + r;
4167           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + (rp - rfStart[n])*3 + r;
4168           remotePointsNew[m].rank  = rrank;
4169         }
4170       } else if ((p >= cStart) && (p < cEnd)) {
4171         /* Old cells add new cells and interior faces and edges */
4172         for (r = 0; r < 8; ++r, ++m) {
4173           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
4174           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
4175           remotePointsNew[m].rank  = rrank;
4176         }
4177         for (r = 0; r < 8; ++r, ++m) {
4178           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*4                    + (p  - cStart)*8     + r;
4179           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*4 + (rp - rcStart[n])*8 + r;
4180           remotePointsNew[m].rank  = rrank;
4181         }
4182         for (r = 0; r < 1; ++r, ++m) {
4183           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (fEnd - fStart)*3                    + (p  - cStart)*1     + r;
4184           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + rdepthSizeOld[n*(depth+1)+depth-1]*3 + (rp - rcStart[n])*1 + r;
4185           remotePointsNew[m].rank  = rrank;
4186         }
4187       }
4188       break;
4189     case 7:
4190       /* Hybrid Simplicial 3D */
4191       if ((p >= vStart) && (p < vEnd)) {
4192         /* Interior vertices stay the same */
4193         localPointsNew[m]        = vStartNew     + (p  - vStart);
4194         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
4195         remotePointsNew[m].rank  = rrank;
4196         ++m;
4197       } else if ((p >= eStart) && (p < eMax)) {
4198         /* Interior edges add new edges and vertex */
4199         for (r = 0; r < 2; ++r, ++m) {
4200           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
4201           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
4202           remotePointsNew[m].rank  = rrank;
4203         }
4204         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
4205         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
4206         remotePointsNew[m].rank  = rrank;
4207         ++m;
4208       } else if ((p >= eMax) && (p < eEnd)) {
4209         /* Hybrid edges stay the same */
4210         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - eMax);
4211         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]);
4212         remotePointsNew[m].rank  = rrank;
4213         ++m;
4214       } else if ((p >= fStart) && (p < fMax)) {
4215         /* Interior faces add new faces and edges */
4216         for (r = 0; r < 4; ++r, ++m) {
4217           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
4218           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
4219           remotePointsNew[m].rank  = rrank;
4220         }
4221         for (r = 0; r < 3; ++r, ++m) {
4222           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*3     + r;
4223           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
4224           remotePointsNew[m].rank  = rrank;
4225         }
4226       } else if ((p >= fMax) && (p < fEnd)) {
4227         /* Hybrid faces add new faces and edges */
4228         for (r = 0; r < 2; ++r, ++m) {
4229           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fStart)*2     + r;
4230           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;
4231           remotePointsNew[m].rank  = rrank;
4232         }
4233         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)     + (cMax                            - cStart)     + (fEnd                                          - fMax);
4234         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]);
4235         remotePointsNew[m].rank  = rrank;
4236       } else if ((p >= cStart) && (p < cMax)) {
4237         /* Interior cells add new cells, faces, and edges */
4238         for (r = 0; r < 8; ++r, ++m) {
4239           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
4240           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
4241           remotePointsNew[m].rank  = rrank;
4242         }
4243         for (r = 0; r < 8; ++r, ++m) {
4244           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*8     + r;
4245           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*8 + r;
4246           remotePointsNew[m].rank  = rrank;
4247         }
4248         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (p  - cStart)*1     + r;
4249         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;
4250         remotePointsNew[m].rank  = rrank;
4251       } else if ((p >= cMax) && (p < cEnd)) {
4252         /* Hybrid cells add new cells and faces */
4253         for (r = 0; r < 4; ++r, ++m) {
4254           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
4255           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
4256           remotePointsNew[m].rank  = rrank;
4257         }
4258         for (r = 0; r < 3; ++r, ++m) {
4259           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*4                              + (p  - cMax)*3                            + r;
4260           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;
4261           remotePointsNew[m].rank  = rrank;
4262         }
4263       }
4264       break;
4265     case 6:
4266       /* Hex 3D */
4267       if ((p >= vStart) && (p < vEnd)) {
4268         /* Old vertices stay the same */
4269         localPointsNew[m]        = vStartNew     + (p  - vStart);
4270         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
4271         remotePointsNew[m].rank  = rrank;
4272         ++m;
4273       } else if ((p >= eStart) && (p < eEnd)) {
4274         /* Old edges add new edges and vertex */
4275         for (r = 0; r < 2; ++r, ++m) {
4276           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
4277           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
4278           remotePointsNew[m].rank  = rrank;
4279         }
4280         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
4281         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
4282         remotePointsNew[m].rank  = rrank;
4283         ++m;
4284       } else if ((p >= fStart) && (p < fEnd)) {
4285         /* Old faces add new faces, edges, and vertex */
4286         for (r = 0; r < 4; ++r, ++m) {
4287           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
4288           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
4289           remotePointsNew[m].rank  = rrank;
4290         }
4291         for (r = 0; r < 4; ++r, ++m) {
4292           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (p  - fStart)*4     + r;
4293           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + (rp - rfStart[n])*4 + r;
4294           remotePointsNew[m].rank  = rrank;
4295         }
4296         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eEnd - eStart)              + (p  - fStart);
4297         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+1] + (rp - rfStart[n]);
4298         remotePointsNew[m].rank  = rrank;
4299         ++m;
4300       } else if ((p >= cStart) && (p < cEnd)) {
4301         /* Old cells add new cells, faces, edges, and vertex */
4302         for (r = 0; r < 8; ++r, ++m) {
4303           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
4304           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
4305           remotePointsNew[m].rank  = rrank;
4306         }
4307         for (r = 0; r < 12; ++r, ++m) {
4308           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*4                    + (p  - cStart)*12     + r;
4309           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*4 + (rp - rcStart[n])*12 + r;
4310           remotePointsNew[m].rank  = rrank;
4311         }
4312         for (r = 0; r < 6; ++r, ++m) {
4313           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (fEnd - fStart)*4                    + (p  - cStart)*6     + r;
4314           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + rdepthSizeOld[n*(depth+1)+depth-1]*4 + (rp - rcStart[n])*6 + r;
4315           remotePointsNew[m].rank  = rrank;
4316         }
4317         for (r = 0; r < 1; ++r, ++m) {
4318           localPointsNew[m]        = vStartNew     + (eEnd - eStart)              + (fEnd - fStart)                    + (p  - cStart)     + r;
4319           remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+1] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]) + r;
4320           remotePointsNew[m].rank  = rrank;
4321         }
4322       }
4323       break;
4324     default:
4325       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
4326     }
4327   }
4328   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
4329   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
4330   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
4331   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
4332   ierr = PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
4333   PetscFunctionReturn(0);
4334 }
4335 
4336 #undef __FUNCT__
4337 #define __FUNCT__ "CellRefinerCreateLabels"
4338 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
4339 {
4340   PetscInt       numLabels, l;
4341   PetscInt       depth, newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r;
4342   PetscErrorCode ierr;
4343 
4344   PetscFunctionBegin;
4345   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4346   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
4347   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4348   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
4349   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4350   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
4351   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
4352   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
4353   switch (refiner) {
4354   case 0: break;
4355   case 7:
4356   case 8:
4357     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
4358   case 3:
4359   case 4:
4360     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
4361     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
4362   }
4363   for (l = 0; l < numLabels; ++l) {
4364     DMLabel         label, labelNew;
4365     const char     *lname;
4366     PetscBool       isDepth;
4367     IS              valueIS;
4368     const PetscInt *values;
4369     PetscInt        numValues, val;
4370 
4371     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
4372     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
4373     if (isDepth) continue;
4374     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
4375     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
4376     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
4377     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
4378     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
4379     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
4380     for (val = 0; val < numValues; ++val) {
4381       IS              pointIS;
4382       const PetscInt *points;
4383       PetscInt        numPoints, n;
4384 
4385       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
4386       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
4387       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
4388       for (n = 0; n < numPoints; ++n) {
4389         const PetscInt p = points[n];
4390         switch (refiner) {
4391         case 1:
4392           /* Simplicial 2D */
4393           if ((p >= vStart) && (p < vEnd)) {
4394             /* Old vertices stay the same */
4395             newp = vStartNew + (p - vStart);
4396             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4397           } else if ((p >= fStart) && (p < fEnd)) {
4398             /* Old faces add new faces and vertex */
4399             newp = vStartNew + (vEnd - vStart) + (p - fStart);
4400             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4401             for (r = 0; r < 2; ++r) {
4402               newp = fStartNew + (p - fStart)*2 + r;
4403               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4404             }
4405           } else if ((p >= cStart) && (p < cEnd)) {
4406             /* Old cells add new cells and interior faces */
4407             for (r = 0; r < 4; ++r) {
4408               newp = cStartNew + (p - cStart)*4 + r;
4409               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4410             }
4411             for (r = 0; r < 3; ++r) {
4412               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
4413               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4414             }
4415           }
4416           break;
4417         case 2:
4418           /* Hex 2D */
4419           if ((p >= vStart) && (p < vEnd)) {
4420             /* Old vertices stay the same */
4421             newp = vStartNew + (p - vStart);
4422             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4423           } else if ((p >= fStart) && (p < fEnd)) {
4424             /* Old faces add new faces and vertex */
4425             newp = vStartNew + (vEnd - vStart) + (p - fStart);
4426             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4427             for (r = 0; r < 2; ++r) {
4428               newp = fStartNew + (p - fStart)*2 + r;
4429               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4430             }
4431           } else if ((p >= cStart) && (p < cEnd)) {
4432             /* Old cells add new cells and interior faces and vertex */
4433             for (r = 0; r < 4; ++r) {
4434               newp = cStartNew + (p - cStart)*4 + r;
4435               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4436             }
4437             for (r = 0; r < 4; ++r) {
4438               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
4439               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4440             }
4441             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
4442             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4443           }
4444           break;
4445         case 3:
4446           /* Hybrid simplicial 2D */
4447           if ((p >= vStart) && (p < vEnd)) {
4448             /* Old vertices stay the same */
4449             newp = vStartNew + (p - vStart);
4450             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4451           } else if ((p >= fStart) && (p < fMax)) {
4452             /* Old interior faces add new faces and vertex */
4453             newp = vStartNew + (vEnd - vStart) + (p - fStart);
4454             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4455             for (r = 0; r < 2; ++r) {
4456               newp = fStartNew + (p - fStart)*2 + r;
4457               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4458             }
4459           } else if ((p >= fMax) && (p < fEnd)) {
4460             /* Old hybrid faces stay the same */
4461             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
4462             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4463           } else if ((p >= cStart) && (p < cMax)) {
4464             /* Old interior cells add new cells and interior faces */
4465             for (r = 0; r < 4; ++r) {
4466               newp = cStartNew + (p - cStart)*4 + r;
4467               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4468             }
4469             for (r = 0; r < 3; ++r) {
4470               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
4471               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4472             }
4473           } else if ((p >= cMax) && (p < cEnd)) {
4474             /* Old hybrid cells add new cells and hybrid face */
4475             for (r = 0; r < 2; ++r) {
4476               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
4477               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4478             }
4479             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
4480             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4481           }
4482           break;
4483         case 5:
4484           /* Simplicial 3D */
4485           if ((p >= vStart) && (p < vEnd)) {
4486             /* Old vertices stay the same */
4487             newp = vStartNew + (p - vStart);
4488             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4489           } else if ((p >= eStart) && (p < eEnd)) {
4490             /* Old edges add new edges and vertex */
4491             for (r = 0; r < 2; ++r) {
4492               newp = eStartNew + (p - eStart)*2 + r;
4493               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4494             }
4495             newp = vStartNew + (vEnd - vStart) + (p - eStart);
4496             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4497           } else if ((p >= fStart) && (p < fEnd)) {
4498             /* Old faces add new faces and edges */
4499             for (r = 0; r < 4; ++r) {
4500               newp = fStartNew + (p - fStart)*4 + r;
4501               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4502             }
4503             for (r = 0; r < 3; ++r) {
4504               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
4505               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4506             }
4507           } else if ((p >= cStart) && (p < cEnd)) {
4508             /* Old cells add new cells and interior faces and edges */
4509             for (r = 0; r < 8; ++r) {
4510               newp = cStartNew + (p - cStart)*8 + r;
4511               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4512             }
4513             for (r = 0; r < 8; ++r) {
4514               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*8 + r;
4515               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4516             }
4517             for (r = 0; r < 1; ++r) {
4518               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*1 + r;
4519               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4520             }
4521           }
4522           break;
4523         case 7:
4524           /* Hybrid Simplicial 3D */
4525           if ((p >= vStart) && (p < vEnd)) {
4526             /* Interior vertices stay the same */
4527             newp = vStartNew + (p - vStart);
4528             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4529           } else if ((p >= eStart) && (p < eMax)) {
4530             /* Interior edges add new edges and vertex */
4531             for (r = 0; r < 2; ++r) {
4532               newp = eStartNew + (p - eStart)*2 + r;
4533               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4534             }
4535             newp = vStartNew + (vEnd - vStart) + (p - eStart);
4536             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4537           } else if ((p >= eMax) && (p < eEnd)) {
4538             /* Hybrid edges stay the same */
4539             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - eMax);
4540             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4541           } else if ((p >= fStart) && (p < fMax)) {
4542             /* Interior faces add new faces and edges */
4543             for (r = 0; r < 4; ++r) {
4544               newp = fStartNew + (p - fStart)*4 + r;
4545               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4546             }
4547             for (r = 0; r < 3; ++r) {
4548               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
4549               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4550             }
4551           } else if ((p >= fMax) && (p < fEnd)) {
4552             /* Hybrid faces add new faces and edges */
4553             for (r = 0; r < 2; ++r) {
4554               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (p - fMax)*2 + r;
4555               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4556             }
4557             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - fMax);
4558             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4559           } else if ((p >= cStart) && (p < cMax)) {
4560             /* Interior cells add new cells, faces, and edges */
4561             for (r = 0; r < 8; ++r) {
4562               newp = cStartNew + (p - cStart)*8 + r;
4563               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4564             }
4565             for (r = 0; r < 8; ++r) {
4566               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*8 + r;
4567               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4568             }
4569             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart);
4570             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4571           } else if ((p >= cMax) && (p < cEnd)) {
4572             /* Hybrid cells add new cells and faces */
4573             for (r = 0; r < 4; ++r) {
4574               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
4575               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4576             }
4577             for (r = 0; r < 3; ++r) {
4578               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
4579               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4580             }
4581           }
4582           break;
4583         case 6:
4584           /* Hex 3D */
4585           if ((p >= vStart) && (p < vEnd)) {
4586             /* Old vertices stay the same */
4587             newp = vStartNew + (p - vStart);
4588             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4589           } else if ((p >= eStart) && (p < eEnd)) {
4590             /* Old edges add new edges and vertex */
4591             for (r = 0; r < 2; ++r) {
4592               newp = eStartNew + (p - eStart)*2 + r;
4593               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4594             }
4595             newp = vStartNew + (vEnd - vStart) + (p - eStart);
4596             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4597           } else if ((p >= fStart) && (p < fEnd)) {
4598             /* Old faces add new faces, edges, and vertex */
4599             for (r = 0; r < 4; ++r) {
4600               newp = fStartNew + (p - fStart)*4 + r;
4601               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4602             }
4603             for (r = 0; r < 4; ++r) {
4604               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*4 + r;
4605               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4606             }
4607             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (p - fStart);
4608             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4609           } else if ((p >= cStart) && (p < cEnd)) {
4610             /* Old cells add new cells, faces, edges, and vertex */
4611             for (r = 0; r < 8; ++r) {
4612               newp = cStartNew + (p - cStart)*8 + r;
4613               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4614             }
4615             for (r = 0; r < 12; ++r) {
4616               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*12 + r;
4617               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4618             }
4619             for (r = 0; r < 6; ++r) {
4620               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (p - cStart)*6 + r;
4621               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4622             }
4623             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (p - cStart);
4624             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
4625           }
4626           break;
4627         default:
4628           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
4629         }
4630       }
4631       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
4632       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
4633     }
4634     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
4635     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
4636     if (0) {
4637       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
4638       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4639       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4640     }
4641   }
4642   PetscFunctionReturn(0);
4643 }
4644 
4645 #undef __FUNCT__
4646 #define __FUNCT__ "DMPlexRefineUniform_Internal"
4647 /* This will only work for interpolated meshes */
4648 PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
4649 {
4650   DM             rdm;
4651   PetscInt      *depthSize;
4652   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
4653   PetscErrorCode ierr;
4654 
4655   PetscFunctionBegin;
4656   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
4657   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
4658   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4659   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
4660   /* Calculate number of new points of each depth */
4661   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4662   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
4663   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
4664   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
4665   /* Step 1: Set chart */
4666   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
4667   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
4668   /* Step 2: Set cone/support sizes */
4669   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
4670   /* Step 3: Setup refined DM */
4671   ierr = DMSetUp(rdm);CHKERRQ(ierr);
4672   /* Step 4: Set cones and supports */
4673   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
4674   /* Step 5: Stratify */
4675   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
4676   /* Step 6: Set coordinates for vertices */
4677   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
4678   /* Step 7: Create pointSF */
4679   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
4680   /* Step 8: Create labels */
4681   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
4682   ierr = PetscFree(depthSize);CHKERRQ(ierr);
4683 
4684   *dmRefined = rdm;
4685   PetscFunctionReturn(0);
4686 }
4687 
4688 #undef __FUNCT__
4689 #define __FUNCT__ "DMPlexSetRefinementUniform"
4690 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
4691 {
4692   DM_Plex *mesh = (DM_Plex*) dm->data;
4693 
4694   PetscFunctionBegin;
4695   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4696   mesh->refinementUniform = refinementUniform;
4697   PetscFunctionReturn(0);
4698 }
4699 
4700 #undef __FUNCT__
4701 #define __FUNCT__ "DMPlexGetRefinementUniform"
4702 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
4703 {
4704   DM_Plex *mesh = (DM_Plex*) dm->data;
4705 
4706   PetscFunctionBegin;
4707   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4708   PetscValidPointer(refinementUniform,  2);
4709   *refinementUniform = mesh->refinementUniform;
4710   PetscFunctionReturn(0);
4711 }
4712 
4713 #undef __FUNCT__
4714 #define __FUNCT__ "DMPlexSetRefinementLimit"
4715 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
4716 {
4717   DM_Plex *mesh = (DM_Plex*) dm->data;
4718 
4719   PetscFunctionBegin;
4720   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4721   mesh->refinementLimit = refinementLimit;
4722   PetscFunctionReturn(0);
4723 }
4724 
4725 #undef __FUNCT__
4726 #define __FUNCT__ "DMPlexGetRefinementLimit"
4727 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
4728 {
4729   DM_Plex *mesh = (DM_Plex*) dm->data;
4730 
4731   PetscFunctionBegin;
4732   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4733   PetscValidPointer(refinementLimit,  2);
4734   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
4735   *refinementLimit = mesh->refinementLimit;
4736   PetscFunctionReturn(0);
4737 }
4738 
4739 #undef __FUNCT__
4740 #define __FUNCT__ "DMPlexGetCellRefiner_Internal"
4741 PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
4742 {
4743   PetscInt       dim, cStart, cEnd, coneSize, cMax;
4744   PetscErrorCode ierr;
4745 
4746   PetscFunctionBegin;
4747   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4748   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4749   if (cEnd <= cStart) {*cellRefiner = 0; PetscFunctionReturn(0);}
4750   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
4751   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
4752   switch (dim) {
4753   case 2:
4754     switch (coneSize) {
4755     case 3:
4756       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
4757       else *cellRefiner = 1; /* Triangular */
4758       break;
4759     case 4:
4760       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
4761       else *cellRefiner = 2; /* Quadrilateral */
4762       break;
4763     default:
4764       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
4765     }
4766     break;
4767   case 3:
4768     switch (coneSize) {
4769     case 4:
4770       if (cMax >= 0) *cellRefiner = 7; /* Hybrid */
4771       else *cellRefiner = 5; /* Tetrahedral */
4772       break;
4773     case 6:
4774       if (cMax >= 0) *cellRefiner = 8; /* Hybrid */
4775       else *cellRefiner = 6; /* hexahedral */
4776       break;
4777     default:
4778       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
4779     }
4780     break;
4781   default:
4782     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
4783   }
4784   PetscFunctionReturn(0);
4785 }
4786