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