xref: /petsc/src/dm/impls/plex/plexrefine.c (revision 7fdeb8b9be692273ce99bf256278a44482a052ca)
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__ "CellRefinerGetAffineTransforms_Internal"
30 /* Gets the affine map from the original cell to each subcell */
31 PetscErrorCode CellRefinerGetAffineTransforms_Internal(CellRefiner refiner, PetscInt *numSubcells, PetscReal *v0[], PetscReal *jac[], PetscReal *invjac[])
32 {
33   PetscReal     *v = NULL, *j = NULL, *invj = NULL, detJ;
34   PetscInt       dim, s;
35   PetscErrorCode ierr;
36 
37   PetscFunctionBegin;
38   switch (refiner) {
39   case 0: break;
40   case 1:
41     dim  = 2;
42     if (numSubcells) *numSubcells = 4;
43     if (v0) {
44       ierr = PetscMalloc3(4*dim,&v,4*dim*dim,&j,4*dim*dim,&invj);CHKERRQ(ierr);
45       /* A */
46       v[0+0] = -1.0; v[0+1] = -1.0;
47       j[0+0] =  0.5; j[0+1] =  0.0;
48       j[0+2] =  0.0; j[0+3] =  0.5;
49       /* B */
50       v[2+0] =  0.0; v[2+1] = -1.0;
51       j[4+0] =  0.5; j[4+1] =  0.0;
52       j[4+2] =  0.0; j[4+3] =  0.5;
53       /* C */
54       v[4+0] = -1.0; v[4+1] =  0.0;
55       j[8+0] =  0.5; j[8+1] =  0.0;
56       j[8+2] =  0.0; j[8+3] =  0.5;
57       /* D */
58       v[6+0]  =  0.0; v[6+1]  = -1.0;
59       j[12+0] =  0.0; j[12+1] = -0.5;
60       j[12+2] =  0.5; j[12+3] =  0.5;
61       for (s = 0; s < 4; ++s) {
62         DMPlex_Det2D_Internal(&detJ, &j[s*dim*dim]);
63         DMPlex_Invert2D_Internal(&invj[s*dim*dim], &j[s*dim*dim], detJ);
64       }
65     }
66     break;
67   default:
68     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
69   }
70   if (v0) {*v0 = v; *jac = j; *invjac = invj;}
71   PetscFunctionReturn(0);
72 }
73 
74 #undef __FUNCT__
75 #define __FUNCT__ "CellRefinerRestoreAffineTransforms_Internal"
76 PetscErrorCode CellRefinerRestoreAffineTransforms_Internal(CellRefiner refiner, PetscInt *numSubcells, PetscReal *v0[], PetscReal *jac[], PetscReal *invjac[])
77 {
78   PetscErrorCode ierr;
79 
80   PetscFunctionBegin;
81   ierr = PetscFree3(*v0,*jac,*invjac);CHKERRQ(ierr);
82   PetscFunctionReturn(0);
83 }
84 
85 #undef __FUNCT__
86 #define __FUNCT__ "CellRefinerGetSizes"
87 static PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
88 {
89   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
90   PetscErrorCode ierr;
91 
92   PetscFunctionBegin;
93   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
94   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
95   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
96   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
97   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
98   switch (refiner) {
99   case 0:
100     break;
101   case 1:
102     /* Simplicial 2D */
103     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
104     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
105     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
106     break;
107   case 3:
108     /* Hybrid Simplicial 2D */
109     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
110     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
111     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
112     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 */
113     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
114     break;
115   case 2:
116     /* Hex 2D */
117     depthSize[0] = vEnd - vStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every face and cell */
118     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
119     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
120     break;
121   case 4:
122     /* Hybrid Hex 2D */
123     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
124     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
125     /* Quadrilateral */
126     depthSize[0] = vEnd - vStart + fMax - fStart + cMax - cStart;                 /* Add a vertex on every face and cell */
127     depthSize[1] = 2*(fMax - fStart) + 4*(cMax - cStart);                         /* Every face is split into 2 faces, and 4 faces are added for each cell */
128     depthSize[2] = 4*(cMax - cStart);                                             /* Every cell split into 4 cells */
129     /* Segment Prisms */
130     depthSize[0] += 0;                                                            /* No hybrid vertices */
131     depthSize[1] +=   (fEnd - fMax)  +   (cEnd - cMax);                           /* Every hybrid face remains and 1 faces is added for each hybrid cell */
132     depthSize[2] += 2*(cEnd - cMax);                                              /* Every hybrid cell split into 2 cells */
133     break;
134   case 5:
135     /* Simplicial 3D */
136     depthSize[0] =    vEnd - vStart  +    eEnd - eStart;                    /* Add a vertex on every edge */
137     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 */
138     depthSize[2] = 4*(fEnd - fStart) + 8*(cEnd - cStart);                   /* Every face split into 4 faces and 8 faces are added for each cell */
139     depthSize[3] = 8*(cEnd - cStart);                                       /* Every cell split into 8 cells */
140     break;
141   case 7:
142     /* Hybrid Simplicial 3D */
143     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
144     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
145     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
146     /* Tetrahedra */
147     depthSize[0]  =    vEnd - vStart  +    eMax - eStart;                    /* Add a vertex on every interior edge */
148     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 */
149     depthSize[2]  = 4*(fMax - fStart) + 8*(cMax - cStart);                   /* Every interior face split into 4 faces, 8 faces added for each interior cell */
150     depthSize[3]  = 8*(cMax - cStart);                                       /* Every interior cell split into 8 cells */
151     /* Triangular Prisms */
152     depthSize[0] += 0;                                                       /* No hybrid vertices */
153     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax);                     /* Every hybrid edge remains, 1 edge for every hybrid face */
154     depthSize[2] += 2*(fEnd - fMax)   + 3*(cEnd - cMax);                     /* Every hybrid face split into 2 faces and 3 faces are added for each hybrid cell */
155     depthSize[3] += 4*(cEnd - cMax);                                         /* Every hybrid cell split into 4 cells */
156     break;
157   case 6:
158     /* Hex 3D */
159     depthSize[0] = vEnd - vStart + eEnd - eStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every edge, face and cell */
160     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 */
161     depthSize[2] = 4*(fEnd - fStart) + 12*(cEnd - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
162     depthSize[3] = 8*(cEnd - cStart);                                             /* Every cell split into 8 cells */
163     break;
164   case 8:
165     /* Hybrid Hex 3D */
166     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
167     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
168     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
169     /* Hexahedra */
170     depthSize[0] = vEnd - vStart + eMax - eStart + fMax - fStart + cMax - cStart; /* Add a vertex on every edge, face and cell */
171     depthSize[1] = 2*(eMax - eStart) +  4*(fMax - fStart) + 6*(cMax - cStart);    /* Every edge is split into 2 edge, 4 edges are added for each face, and 6 edges for each cell */
172     depthSize[2] = 4*(fMax - fStart) + 12*(cMax - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
173     depthSize[3] = 8*(cMax - cStart);                                             /* Every cell split into 8 cells */
174     /* Quadrilateral Prisms */
175     depthSize[0] += 0;                                                            /* No hybrid vertices */
176     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax)   +   (cEnd - cMax);      /* Every hybrid edge remains, 1 edge for every hybrid face and hybrid cell */
177     depthSize[2] += 2*(fEnd - fMax)   + 4*(cEnd - cMax);                          /* Every hybrid face split into 2 faces and 4 faces are added for each hybrid cell */
178     depthSize[3] += 4*(cEnd - cMax);                                              /* Every hybrid cell split into 4 cells */
179     break;
180   default:
181     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
182   }
183   PetscFunctionReturn(0);
184 }
185 
186 /* Return triangle edge for orientation o, if it is r for o == 0 */
187 PETSC_STATIC_INLINE PetscInt GetTriEdge_Static(PetscInt o, PetscInt r) {
188   return (o < 0 ? 2-(o+r) : o+r)%3;
189 }
190 PETSC_STATIC_INLINE PetscInt GetTriEdgeInverse_Static(PetscInt o, PetscInt s) {
191   return (o < 0 ? 2-(o+s) : 3+s-o)%3;
192 }
193 
194 /* Return triangle subface for orientation o, if it is r for o == 0 */
195 PETSC_STATIC_INLINE PetscInt GetTriSubface_Static(PetscInt o, PetscInt r) {
196   return (o < 0 ? 3-(o+r) : o+r)%3;
197 }
198 PETSC_STATIC_INLINE PetscInt GetTriSubfaceInverse_Static(PetscInt o, PetscInt s) {
199   return (o < 0 ? 3-(o+s) : 3+s-o)%3;
200 }
201 
202 /* I HAVE NO IDEA: Return ??? for orientation o, if it is r for o == 0 */
203 PETSC_STATIC_INLINE PetscInt GetTetSomething_Static(PetscInt o, PetscInt r) {
204   return (o < 0 ? 1-(o+r) : o+r)%3;
205 }
206 PETSC_STATIC_INLINE PetscInt GetTetSomethingInverse_Static(PetscInt o, PetscInt s) {
207   return (o < 0 ? 1-(o+s) : 3+s-o)%3;
208 }
209 
210 
211 /* Return quad edge for orientation o, if it is r for o == 0 */
212 PETSC_STATIC_INLINE PetscInt GetQuadEdge_Static(PetscInt o, PetscInt r) {
213   return (o < 0 ? 3-(o+r) : o+r)%4;
214 }
215 PETSC_STATIC_INLINE PetscInt GetQuadEdgeInverse_Static(PetscInt o, PetscInt s) {
216   return (o < 0 ? 3-(o+s) : 4+s-o)%4;
217 }
218 
219 /* Return quad subface for orientation o, if it is r for o == 0 */
220 PETSC_STATIC_INLINE PetscInt GetQuadSubface_Static(PetscInt o, PetscInt r) {
221   return (o < 0 ? 4-(o+r) : o+r)%4;
222 }
223 PETSC_STATIC_INLINE PetscInt GetQuadSubfaceInverse_Static(PetscInt o, PetscInt s) {
224   return (o < 0 ? 4-(o+s) : 4+s-o)%4;
225 }
226 
227 #undef __FUNCT__
228 #define __FUNCT__ "CellRefinerSetConeSizes"
229 static PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
230 {
231   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, e, r;
232   PetscErrorCode ierr;
233 
234   PetscFunctionBegin;
235   if (!refiner) PetscFunctionReturn(0);
236   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
237   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
238   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
239   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
240   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
241   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
242   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
243   switch (refiner) {
244   case 1:
245     /* Simplicial 2D */
246     /* All cells have 3 faces */
247     for (c = cStart; c < cEnd; ++c) {
248       for (r = 0; r < 4; ++r) {
249         const PetscInt newp = (c - cStart)*4 + r;
250 
251         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
252       }
253     }
254     /* Split faces have 2 vertices and the same cells as the parent */
255     for (f = fStart; f < fEnd; ++f) {
256       for (r = 0; r < 2; ++r) {
257         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
258         PetscInt       size;
259 
260         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
261         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
262         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
263       }
264     }
265     /* Interior faces have 2 vertices and 2 cells */
266     for (c = cStart; c < cEnd; ++c) {
267       for (r = 0; r < 3; ++r) {
268         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
269 
270         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
271         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
272       }
273     }
274     /* Old vertices have identical supports */
275     for (v = vStart; v < vEnd; ++v) {
276       const PetscInt newp = vStartNew + (v - vStart);
277       PetscInt       size;
278 
279       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
280       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
281     }
282     /* Face vertices have 2 + cells*2 supports */
283     for (f = fStart; f < fEnd; ++f) {
284       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
285       PetscInt       size;
286 
287       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
288       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
289     }
290     break;
291   case 2:
292     /* Hex 2D */
293     /* All cells have 4 faces */
294     for (c = cStart; c < cEnd; ++c) {
295       for (r = 0; r < 4; ++r) {
296         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
297 
298         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
299       }
300     }
301     /* Split faces have 2 vertices and the same cells as the parent */
302     for (f = fStart; f < fEnd; ++f) {
303       for (r = 0; r < 2; ++r) {
304         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
305         PetscInt       size;
306 
307         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
308         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
309         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
310       }
311     }
312     /* Interior faces have 2 vertices and 2 cells */
313     for (c = cStart; c < cEnd; ++c) {
314       for (r = 0; r < 4; ++r) {
315         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
316 
317         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
318         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
319       }
320     }
321     /* Old vertices have identical supports */
322     for (v = vStart; v < vEnd; ++v) {
323       const PetscInt newp = vStartNew + (v - vStart);
324       PetscInt       size;
325 
326       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
327       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
328     }
329     /* Face vertices have 2 + cells supports */
330     for (f = fStart; f < fEnd; ++f) {
331       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
332       PetscInt       size;
333 
334       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
335       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
336     }
337     /* Cell vertices have 4 supports */
338     for (c = cStart; c < cEnd; ++c) {
339       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
340 
341       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
342     }
343     break;
344   case 3:
345     /* Hybrid Simplicial 2D */
346     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
347     cMax = PetscMin(cEnd, cMax);
348     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
349     fMax = PetscMin(fEnd, fMax);
350     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
351     /* Interior cells have 3 faces */
352     for (c = cStart; c < cMax; ++c) {
353       for (r = 0; r < 4; ++r) {
354         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
355 
356         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
357       }
358     }
359     /* Hybrid cells have 4 faces */
360     for (c = cMax; c < cEnd; ++c) {
361       for (r = 0; r < 2; ++r) {
362         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
363 
364         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
365       }
366     }
367     /* Interior split faces have 2 vertices and the same cells as the parent */
368     for (f = fStart; f < fMax; ++f) {
369       for (r = 0; r < 2; ++r) {
370         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
371         PetscInt       size;
372 
373         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
374         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
375         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
376       }
377     }
378     /* Interior cell faces have 2 vertices and 2 cells */
379     for (c = cStart; c < cMax; ++c) {
380       for (r = 0; r < 3; ++r) {
381         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
382 
383         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
384         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
385       }
386     }
387     /* Hybrid faces have 2 vertices and the same cells */
388     for (f = fMax; f < fEnd; ++f) {
389       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
390       PetscInt       size;
391 
392       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
393       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
394       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
395     }
396     /* Hybrid cell faces have 2 vertices and 2 cells */
397     for (c = cMax; c < cEnd; ++c) {
398       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
399 
400       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
401       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
402     }
403     /* Old vertices have identical supports */
404     for (v = vStart; v < vEnd; ++v) {
405       const PetscInt newp = vStartNew + (v - vStart);
406       PetscInt       size;
407 
408       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
409       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
410     }
411     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
412     for (f = fStart; f < fMax; ++f) {
413       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
414       const PetscInt *support;
415       PetscInt       size, newSize = 2, s;
416 
417       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
418       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
419       for (s = 0; s < size; ++s) {
420         if (support[s] >= cMax) newSize += 1;
421         else newSize += 2;
422       }
423       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
424     }
425     break;
426   case 4:
427     /* Hybrid Hex 2D */
428     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
429     cMax = PetscMin(cEnd, cMax);
430     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
431     fMax = PetscMin(fEnd, fMax);
432     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
433     /* Interior cells have 4 faces */
434     for (c = cStart; c < cMax; ++c) {
435       for (r = 0; r < 4; ++r) {
436         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
437 
438         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
439       }
440     }
441     /* Hybrid cells have 4 faces */
442     for (c = cMax; c < cEnd; ++c) {
443       for (r = 0; r < 2; ++r) {
444         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
445 
446         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
447       }
448     }
449     /* Interior split faces have 2 vertices and the same cells as the parent */
450     for (f = fStart; f < fMax; ++f) {
451       for (r = 0; r < 2; ++r) {
452         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
453         PetscInt       size;
454 
455         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
456         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
457         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
458       }
459     }
460     /* Interior cell faces have 2 vertices and 2 cells */
461     for (c = cStart; c < cMax; ++c) {
462       for (r = 0; r < 4; ++r) {
463         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
464 
465         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
466         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
467       }
468     }
469     /* Hybrid faces have 2 vertices and the same cells */
470     for (f = fMax; f < fEnd; ++f) {
471       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
472       PetscInt       size;
473 
474       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
475       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
476       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
477     }
478     /* Hybrid cell faces have 2 vertices and 2 cells */
479     for (c = cMax; c < cEnd; ++c) {
480       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
481 
482       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
483       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
484     }
485     /* Old vertices have identical supports */
486     for (v = vStart; v < vEnd; ++v) {
487       const PetscInt newp = vStartNew + (v - vStart);
488       PetscInt       size;
489 
490       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
491       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
492     }
493     /* Face vertices have 2 + cells supports */
494     for (f = fStart; f < fMax; ++f) {
495       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
496       PetscInt       size;
497 
498       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
499       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
500     }
501     /* Cell vertices have 4 supports */
502     for (c = cStart; c < cMax; ++c) {
503       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
504 
505       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
506     }
507     break;
508   case 5:
509     /* Simplicial 3D */
510     /* All cells have 4 faces */
511     for (c = cStart; c < cEnd; ++c) {
512       for (r = 0; r < 8; ++r) {
513         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
514 
515         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
516       }
517     }
518     /* Split faces have 3 edges and the same cells as the parent */
519     for (f = fStart; f < fEnd; ++f) {
520       for (r = 0; r < 4; ++r) {
521         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
522         PetscInt       size;
523 
524         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
525         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
526         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
527       }
528     }
529     /* Interior cell faces have 3 edges and 2 cells */
530     for (c = cStart; c < cEnd; ++c) {
531       for (r = 0; r < 8; ++r) {
532         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + r;
533 
534         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
535         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
536       }
537     }
538     /* Split edges have 2 vertices and the same faces */
539     for (e = eStart; e < eEnd; ++e) {
540       for (r = 0; r < 2; ++r) {
541         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
542         PetscInt       size;
543 
544         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
545         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
546         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
547       }
548     }
549     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
550     for (f = fStart; f < fEnd; ++f) {
551       for (r = 0; r < 3; ++r) {
552         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
553         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
554         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;
555 
556         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
557         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
558         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
559         for (s = 0; s < supportSize; ++s) {
560           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
561           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
562           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
563           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
564           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
565           er = GetTetSomethingInverse_Static(ornt[c], r);
566           if (er == eint[c]) {
567             intFaces += 1;
568           } else {
569             intFaces += 2;
570           }
571         }
572         ierr = DMPlexSetSupportSize(rdm, newp, 2+intFaces);CHKERRQ(ierr);
573       }
574     }
575     /* Interior cell edges have 2 vertices and 4 faces */
576     for (c = cStart; c < cEnd; ++c) {
577       const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
578 
579       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
580       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
581     }
582     /* Old vertices have identical supports */
583     for (v = vStart; v < vEnd; ++v) {
584       const PetscInt newp = vStartNew + (v - vStart);
585       PetscInt       size;
586 
587       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
588       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
589     }
590     /* Edge vertices have 2 + faces*2 + cells*0/1 supports */
591     for (e = eStart; e < eEnd; ++e) {
592       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
593       PetscInt       size, *star = NULL, starSize, s, cellSize = 0;
594 
595       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
596       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
597       for (s = 0; s < starSize*2; s += 2) {
598         const PetscInt *cone, *ornt;
599         PetscInt        e01, e23;
600 
601         if ((star[s] >= cStart) && (star[s] < cEnd)) {
602           /* Check edge 0-1 */
603           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
604           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
605           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
606           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
607           /* Check edge 2-3 */
608           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
609           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
610           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
611           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
612           if ((e01 == e) || (e23 == e)) ++cellSize;
613         }
614       }
615       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
616       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2 + cellSize);CHKERRQ(ierr);
617     }
618     break;
619   case 7:
620     /* Hybrid Simplicial 3D */
621     ierr = DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 8*(cMax - cStart),
622                                  eStartNew + 2*(eMax - eStart) + 3*(fMax - fStart) + (cMax - cStart), PETSC_DETERMINE);CHKERRQ(ierr);
623     /* Interior cells have 4 faces */
624     for (c = cStart; c < cMax; ++c) {
625       for (r = 0; r < 8; ++r) {
626         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
627 
628         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
629       }
630     }
631     /* Hybrid cells have 5 faces */
632     for (c = cMax; c < cEnd; ++c) {
633       for (r = 0; r < 4; ++r) {
634         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;
635 
636         ierr = DMPlexSetConeSize(rdm, newp, 5);CHKERRQ(ierr);
637       }
638     }
639     /* Interior split faces have 3 edges and the same cells as the parent */
640     for (f = fStart; f < fMax; ++f) {
641       for (r = 0; r < 4; ++r) {
642         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
643         PetscInt       size;
644 
645         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
646         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
647         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
648       }
649     }
650     /* Interior cell faces have 3 edges and 2 cells */
651     for (c = cStart; c < cMax; ++c) {
652       for (r = 0; r < 8; ++r) {
653         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + r;
654 
655         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
656         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
657       }
658     }
659     /* Hybrid split faces have 4 edges and the same cells as the parent */
660     for (f = fMax; f < fEnd; ++f) {
661       for (r = 0; r < 2; ++r) {
662         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
663         PetscInt       size;
664 
665         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
666         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
667         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
668       }
669     }
670     /* Hybrid cells faces have 4 edges and 2 cells */
671     for (c = cMax; c < cEnd; ++c) {
672       for (r = 0; r < 3; ++r) {
673         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + r;
674 
675         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
676         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
677       }
678     }
679     /* Interior split edges have 2 vertices and the same faces */
680     for (e = eStart; e < eMax; ++e) {
681       for (r = 0; r < 2; ++r) {
682         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
683         PetscInt       size;
684 
685         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
686         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
687         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
688       }
689     }
690     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
691     for (f = fStart; f < fMax; ++f) {
692       for (r = 0; r < 3; ++r) {
693         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
694         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
695         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;
696 
697         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
698         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
699         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
700         for (s = 0; s < supportSize; ++s) {
701           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
702           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
703           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
704           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
705           if (support[s] < cMax) {
706             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
707             er = GetTetSomethingInverse_Static(ornt[c], r);
708             if (er == eint[c]) {
709               intFaces += 1;
710             } else {
711               intFaces += 2;
712             }
713           } else {
714             intFaces += 1;
715           }
716         }
717         ierr = DMPlexSetSupportSize(rdm, newp, 2+intFaces);CHKERRQ(ierr);
718       }
719     }
720     /* Interior cell edges have 2 vertices and 4 faces */
721     for (c = cStart; c < cMax; ++c) {
722       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
723 
724       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
725       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
726     }
727     /* Hybrid edges have 2 vertices and the same faces */
728     for (e = eMax; e < eEnd; ++e) {
729       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
730       PetscInt       size;
731 
732       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
733       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
734       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
735     }
736     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
737     for (f = fMax; f < fEnd; ++f) {
738       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
739       PetscInt       size;
740 
741       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
742       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
743       ierr = DMPlexSetSupportSize(rdm, newp, 2+2*size);CHKERRQ(ierr);
744     }
745     /* Interior vertices have identical supports */
746     for (v = vStart; v < vEnd; ++v) {
747       const PetscInt newp = vStartNew + (v - vStart);
748       PetscInt       size;
749 
750       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
751       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
752     }
753     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
754     for (e = eStart; e < eMax; ++e) {
755       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
756       const PetscInt *support;
757       PetscInt        size, *star = NULL, starSize, s, faceSize = 0, cellSize = 0;
758 
759       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
760       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
761       for (s = 0; s < size; ++s) {
762         if (support[s] < fMax) faceSize += 2;
763         else                   faceSize += 1;
764       }
765       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
766       for (s = 0; s < starSize*2; s += 2) {
767         const PetscInt *cone, *ornt;
768         PetscInt        e01, e23;
769 
770         if ((star[s] >= cStart) && (star[s] < cMax)) {
771           /* Check edge 0-1 */
772           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
773           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
774           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
775           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
776           /* Check edge 2-3 */
777           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
778           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
779           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
780           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
781           if ((e01 == e) || (e23 == e)) ++cellSize;
782         }
783       }
784       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
785       ierr = DMPlexSetSupportSize(rdm, newp, 2 + faceSize + cellSize);CHKERRQ(ierr);
786     }
787     break;
788   case 6:
789     /* Hex 3D */
790     /* All cells have 6 faces */
791     for (c = cStart; c < cEnd; ++c) {
792       for (r = 0; r < 8; ++r) {
793         const PetscInt newp = (c - cStart)*8 + r;
794 
795         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
796       }
797     }
798     /* Split faces have 4 edges and the same cells as the parent */
799     for (f = fStart; f < fEnd; ++f) {
800       for (r = 0; r < 4; ++r) {
801         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
802         PetscInt       size;
803 
804         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
805         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
806         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
807       }
808     }
809     /* Interior faces have 4 edges and 2 cells */
810     for (c = cStart; c < cEnd; ++c) {
811       for (r = 0; r < 12; ++r) {
812         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
813 
814         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
815         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
816       }
817     }
818     /* Split edges have 2 vertices and the same faces as the parent */
819     for (e = eStart; e < eEnd; ++e) {
820       for (r = 0; r < 2; ++r) {
821         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
822         PetscInt       size;
823 
824         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
825         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
826         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
827       }
828     }
829     /* Face edges have 2 vertices and 2+cells faces */
830     for (f = fStart; f < fEnd; ++f) {
831       for (r = 0; r < 4; ++r) {
832         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
833         PetscInt       size;
834 
835         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
836         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
837         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
838       }
839     }
840     /* Cell edges have 2 vertices and 4 faces */
841     for (c = cStart; c < cEnd; ++c) {
842       for (r = 0; r < 6; ++r) {
843         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
844 
845         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
846         ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
847       }
848     }
849     /* Old vertices have identical supports */
850     for (v = vStart; v < vEnd; ++v) {
851       const PetscInt newp = vStartNew + (v - vStart);
852       PetscInt       size;
853 
854       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
855       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
856     }
857     /* Edge vertices have 2 + faces supports */
858     for (e = eStart; e < eEnd; ++e) {
859       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
860       PetscInt       size;
861 
862       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
863       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
864     }
865     /* Face vertices have 4 + cells supports */
866     for (f = fStart; f < fEnd; ++f) {
867       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
868       PetscInt       size;
869 
870       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
871       ierr = DMPlexSetSupportSize(rdm, newp, 4 + size);CHKERRQ(ierr);
872     }
873     /* Cell vertices have 6 supports */
874     for (c = cStart; c < cEnd; ++c) {
875       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
876 
877       ierr = DMPlexSetSupportSize(rdm, newp, 6);CHKERRQ(ierr);
878     }
879     break;
880   case 8:
881     /* Hybrid Hex 3D */
882     ierr = DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 12*(cMax - cStart),
883                                  eStartNew + 2*(eMax - eStart) + 4*(fMax - fStart) + 6*(cMax - cStart), PETSC_DETERMINE);CHKERRQ(ierr);
884     /* Interior cells have 6 faces */
885     for (c = cStart; c < cMax; ++c) {
886       for (r = 0; r < 8; ++r) {
887         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
888 
889         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
890       }
891     }
892     /* Hybrid cells have 6 faces */
893     for (c = cMax; c < cEnd; ++c) {
894       for (r = 0; r < 4; ++r) {
895         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;
896 
897         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
898       }
899     }
900     /* Interior split faces have 4 edges and the same cells as the parent */
901     for (f = fStart; f < fMax; ++f) {
902       for (r = 0; r < 4; ++r) {
903         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
904         PetscInt       size;
905 
906         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
907         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
908         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
909       }
910     }
911     /* Interior cell faces have 4 edges and 2 cells */
912     for (c = cStart; c < cMax; ++c) {
913       for (r = 0; r < 12; ++r) {
914         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
915 
916         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
917         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
918       }
919     }
920     /* Hybrid split faces have 4 edges and the same cells as the parent */
921     for (f = fMax; f < fEnd; ++f) {
922       for (r = 0; r < 2; ++r) {
923         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
924         PetscInt       size;
925 
926         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
927         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
928         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
929       }
930     }
931     /* Hybrid cells faces have 4 edges and 2 cells */
932     for (c = cMax; c < cEnd; ++c) {
933       for (r = 0; r < 4; ++r) {
934         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + r;
935 
936         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
937         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
938       }
939     }
940     /* Interior split edges have 2 vertices and the same faces as the parent */
941     for (e = eStart; e < eMax; ++e) {
942       for (r = 0; r < 2; ++r) {
943         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
944         PetscInt       size;
945 
946         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
947         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
948         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
949       }
950     }
951     /* Interior face edges have 2 vertices and 2+cells faces */
952     for (f = fStart; f < fMax; ++f) {
953       for (r = 0; r < 4; ++r) {
954         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
955         PetscInt       size;
956 
957         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
958         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
959         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
960       }
961     }
962     /* Interior cell edges have 2 vertices and 4 faces */
963     for (c = cStart; c < cMax; ++c) {
964       for (r = 0; r < 6; ++r) {
965         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
966 
967         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
968         ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
969       }
970     }
971     /* Hybrid edges have 2 vertices and the same faces */
972     for (e = eMax; e < eEnd; ++e) {
973       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
974       PetscInt       size;
975 
976       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
977       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
978       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
979     }
980     /* Hybrid face edges have 2 vertices and 2+cells faces */
981     for (f = fMax; f < fEnd; ++f) {
982       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
983       PetscInt       size;
984 
985       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
986       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
987       ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
988     }
989     /* Hybrid cell edges have 2 vertices and 4 faces */
990     for (c = cMax; c < cEnd; ++c) {
991       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
992 
993       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
994       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
995     }
996     /* Interior vertices have identical supports */
997     for (v = vStart; v < vEnd; ++v) {
998       const PetscInt newp = vStartNew + (v - vStart);
999       PetscInt       size;
1000 
1001       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1002       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1003     }
1004     /* Interior edge vertices have 2 + faces supports */
1005     for (e = eStart; e < eMax; ++e) {
1006       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1007       PetscInt       size;
1008 
1009       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1010       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1011     }
1012     /* Interior face vertices have 4 + cells supports */
1013     for (f = fStart; f < fMax; ++f) {
1014       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
1015       PetscInt       size;
1016 
1017       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1018       ierr = DMPlexSetSupportSize(rdm, newp, 4 + size);CHKERRQ(ierr);
1019     }
1020     /* Interior cell vertices have 6 supports */
1021     for (c = cStart; c < cMax; ++c) {
1022       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
1023 
1024       ierr = DMPlexSetSupportSize(rdm, newp, 6);CHKERRQ(ierr);
1025     }
1026     break;
1027   default:
1028     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
1029   }
1030   PetscFunctionReturn(0);
1031 }
1032 
1033 #undef __FUNCT__
1034 #define __FUNCT__ "CellRefinerSetCones"
1035 static PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
1036 {
1037   const PetscInt *faces, cellInd[4] = {0, 1, 2, 3};
1038   PetscInt        cStart,    cEnd,    cMax,    vStart,    vEnd, vMax, fStart,    fEnd,    fMax,    eStart,    eEnd,    eMax;
1039   PetscInt        cStartNew, cEndNew, cMaxNew, vStartNew, vEndNew,    fStartNew, fEndNew, fMaxNew, eStartNew, eEndNew, eMaxNew;
1040   PetscInt        depth, maxSupportSize, *supportRef, c, f, e, v, r, p;
1041   PetscErrorCode  ierr;
1042 
1043   PetscFunctionBegin;
1044   if (!refiner) PetscFunctionReturn(0);
1045   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1046   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
1047   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
1048   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1049   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
1050   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
1051   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
1052   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
1053   switch (refiner) {
1054   case 1:
1055     /* Simplicial 2D */
1056     /*
1057      2
1058      |\
1059      | \
1060      |  \
1061      |   \
1062      | C  \
1063      |     \
1064      |      \
1065      2---1---1
1066      |\  D  / \
1067      | 2   0   \
1068      |A \ /  B  \
1069      0---0-------1
1070      */
1071     /* All cells have 3 faces */
1072     for (c = cStart; c < cEnd; ++c) {
1073       const PetscInt  newp = cStartNew + (c - cStart)*4;
1074       const PetscInt *cone, *ornt;
1075       PetscInt        coneNew[3], orntNew[3];
1076 
1077       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1078       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1079       /* A triangle */
1080       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1081       orntNew[0] = ornt[0];
1082       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1083       orntNew[1] = -2;
1084       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1085       orntNew[2] = ornt[2];
1086       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1087       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1088 #if 1
1089       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);
1090       for (p = 0; p < 3; ++p) {
1091         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);
1092       }
1093 #endif
1094       /* B triangle */
1095       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1096       orntNew[0] = ornt[0];
1097       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1098       orntNew[1] = ornt[1];
1099       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1100       orntNew[2] = -2;
1101       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1102       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1103 #if 1
1104       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);
1105       for (p = 0; p < 3; ++p) {
1106         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);
1107       }
1108 #endif
1109       /* C triangle */
1110       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1111       orntNew[0] = -2;
1112       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1113       orntNew[1] = ornt[1];
1114       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1115       orntNew[2] = ornt[2];
1116       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1117       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1118 #if 1
1119       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);
1120       for (p = 0; p < 3; ++p) {
1121         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);
1122       }
1123 #endif
1124       /* D triangle */
1125       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1126       orntNew[0] = 0;
1127       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1128       orntNew[1] = 0;
1129       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1130       orntNew[2] = 0;
1131       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1132       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1133 #if 1
1134       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);
1135       for (p = 0; p < 3; ++p) {
1136         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);
1137       }
1138 #endif
1139     }
1140     /* Split faces have 2 vertices and the same cells as the parent */
1141     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1142     ierr = PetscMalloc1((2 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
1143     for (f = fStart; f < fEnd; ++f) {
1144       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1145 
1146       for (r = 0; r < 2; ++r) {
1147         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1148         const PetscInt *cone, *ornt, *support;
1149         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1150 
1151         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1152         coneNew[0]       = vStartNew + (cone[0] - vStart);
1153         coneNew[1]       = vStartNew + (cone[1] - vStart);
1154         coneNew[(r+1)%2] = newv;
1155         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1156 #if 1
1157         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1158         for (p = 0; p < 2; ++p) {
1159           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);
1160         }
1161 #endif
1162         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1163         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1164         for (s = 0; s < supportSize; ++s) {
1165           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1166           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1167           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1168           for (c = 0; c < coneSize; ++c) {
1169             if (cone[c] == f) break;
1170           }
1171           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1172         }
1173         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1174 #if 1
1175         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1176         for (p = 0; p < supportSize; ++p) {
1177           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);
1178         }
1179 #endif
1180       }
1181     }
1182     /* Interior faces have 2 vertices and 2 cells */
1183     for (c = cStart; c < cEnd; ++c) {
1184       const PetscInt *cone;
1185 
1186       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1187       for (r = 0; r < 3; ++r) {
1188         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
1189         PetscInt       coneNew[2];
1190         PetscInt       supportNew[2];
1191 
1192         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
1193         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
1194         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1195 #if 1
1196         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1197         for (p = 0; p < 2; ++p) {
1198           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);
1199         }
1200 #endif
1201         supportNew[0] = (c - cStart)*4 + (r+1)%3;
1202         supportNew[1] = (c - cStart)*4 + 3;
1203         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1204 #if 1
1205         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1206         for (p = 0; p < 2; ++p) {
1207           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);
1208         }
1209 #endif
1210       }
1211     }
1212     /* Old vertices have identical supports */
1213     for (v = vStart; v < vEnd; ++v) {
1214       const PetscInt  newp = vStartNew + (v - vStart);
1215       const PetscInt *support, *cone;
1216       PetscInt        size, s;
1217 
1218       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1219       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1220       for (s = 0; s < size; ++s) {
1221         PetscInt r = 0;
1222 
1223         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1224         if (cone[1] == v) r = 1;
1225         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1226       }
1227       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1228 #if 1
1229       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1230       for (p = 0; p < size; ++p) {
1231         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);
1232       }
1233 #endif
1234     }
1235     /* Face vertices have 2 + cells*2 supports */
1236     for (f = fStart; f < fEnd; ++f) {
1237       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1238       const PetscInt *cone, *support;
1239       PetscInt        size, s;
1240 
1241       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1242       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1243       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1244       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1245       for (s = 0; s < size; ++s) {
1246         PetscInt r = 0;
1247 
1248         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1249         if      (cone[1] == f) r = 1;
1250         else if (cone[2] == f) r = 2;
1251         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
1252         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
1253       }
1254       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1255 #if 1
1256       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1257       for (p = 0; p < 2+size*2; ++p) {
1258         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);
1259       }
1260 #endif
1261     }
1262     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1263     break;
1264   case 2:
1265     /* Hex 2D */
1266     /*
1267      3---------2---------2
1268      |         |         |
1269      |    D    2    C    |
1270      |         |         |
1271      3----3----0----1----1
1272      |         |         |
1273      |    A    0    B    |
1274      |         |         |
1275      0---------0---------1
1276      */
1277     /* All cells have 4 faces */
1278     for (c = cStart; c < cEnd; ++c) {
1279       const PetscInt  newp = (c - cStart)*4;
1280       const PetscInt *cone, *ornt;
1281       PetscInt        coneNew[4], orntNew[4];
1282 
1283       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1284       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1285       /* A quad */
1286       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1287       orntNew[0] = ornt[0];
1288       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
1289       orntNew[1] = 0;
1290       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
1291       orntNew[2] = -2;
1292       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
1293       orntNew[3] = ornt[3];
1294       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1295       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1296 #if 1
1297       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);
1298       for (p = 0; p < 4; ++p) {
1299         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);
1300       }
1301 #endif
1302       /* B quad */
1303       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1304       orntNew[0] = ornt[0];
1305       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1306       orntNew[1] = ornt[1];
1307       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
1308       orntNew[2] = 0;
1309       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
1310       orntNew[3] = -2;
1311       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1312       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1313 #if 1
1314       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);
1315       for (p = 0; p < 4; ++p) {
1316         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);
1317       }
1318 #endif
1319       /* C quad */
1320       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
1321       orntNew[0] = -2;
1322       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1323       orntNew[1] = ornt[1];
1324       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1325       orntNew[2] = ornt[2];
1326       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
1327       orntNew[3] = 0;
1328       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1329       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1330 #if 1
1331       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);
1332       for (p = 0; p < 4; ++p) {
1333         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);
1334       }
1335 #endif
1336       /* D quad */
1337       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
1338       orntNew[0] = 0;
1339       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
1340       orntNew[1] = -2;
1341       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1342       orntNew[2] = ornt[2];
1343       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
1344       orntNew[3] = ornt[3];
1345       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1346       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1347 #if 1
1348       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);
1349       for (p = 0; p < 4; ++p) {
1350         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);
1351       }
1352 #endif
1353     }
1354     /* Split faces have 2 vertices and the same cells as the parent */
1355     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1356     ierr = PetscMalloc1((2 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
1357     for (f = fStart; f < fEnd; ++f) {
1358       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1359 
1360       for (r = 0; r < 2; ++r) {
1361         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1362         const PetscInt *cone, *ornt, *support;
1363         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1364 
1365         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1366         coneNew[0]       = vStartNew + (cone[0] - vStart);
1367         coneNew[1]       = vStartNew + (cone[1] - vStart);
1368         coneNew[(r+1)%2] = newv;
1369         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1370 #if 1
1371         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1372         for (p = 0; p < 2; ++p) {
1373           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
1374         }
1375 #endif
1376         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1377         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1378         for (s = 0; s < supportSize; ++s) {
1379           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1380           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1381           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1382           for (c = 0; c < coneSize; ++c) {
1383             if (cone[c] == f) break;
1384           }
1385           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
1386         }
1387         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1388 #if 1
1389         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1390         for (p = 0; p < supportSize; ++p) {
1391           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);
1392         }
1393 #endif
1394       }
1395     }
1396     /* Interior faces have 2 vertices and 2 cells */
1397     for (c = cStart; c < cEnd; ++c) {
1398       const PetscInt *cone;
1399       PetscInt        coneNew[2], supportNew[2];
1400 
1401       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1402       for (r = 0; r < 4; ++r) {
1403         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
1404 
1405         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
1406         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
1407         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1408 #if 1
1409         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1410         for (p = 0; p < 2; ++p) {
1411           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);
1412         }
1413 #endif
1414         supportNew[0] = (c - cStart)*4 + r;
1415         supportNew[1] = (c - cStart)*4 + (r+1)%4;
1416         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1417 #if 1
1418         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1419         for (p = 0; p < 2; ++p) {
1420           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);
1421         }
1422 #endif
1423       }
1424     }
1425     /* Old vertices have identical supports */
1426     for (v = vStart; v < vEnd; ++v) {
1427       const PetscInt  newp = vStartNew + (v - vStart);
1428       const PetscInt *support, *cone;
1429       PetscInt        size, s;
1430 
1431       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1432       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1433       for (s = 0; s < size; ++s) {
1434         PetscInt r = 0;
1435 
1436         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1437         if (cone[1] == v) r = 1;
1438         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1439       }
1440       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1441 #if 1
1442       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1443       for (p = 0; p < size; ++p) {
1444         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);
1445       }
1446 #endif
1447     }
1448     /* Face vertices have 2 + cells supports */
1449     for (f = fStart; f < fEnd; ++f) {
1450       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1451       const PetscInt *cone, *support;
1452       PetscInt        size, s;
1453 
1454       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1455       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1456       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1457       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1458       for (s = 0; s < size; ++s) {
1459         PetscInt r = 0;
1460 
1461         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1462         if      (cone[1] == f) r = 1;
1463         else if (cone[2] == f) r = 2;
1464         else if (cone[3] == f) r = 3;
1465         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
1466       }
1467       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1468 #if 1
1469       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1470       for (p = 0; p < 2+size; ++p) {
1471         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);
1472       }
1473 #endif
1474     }
1475     /* Cell vertices have 4 supports */
1476     for (c = cStart; c < cEnd; ++c) {
1477       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
1478       PetscInt       supportNew[4];
1479 
1480       for (r = 0; r < 4; ++r) {
1481         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
1482       }
1483       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1484     }
1485     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1486     break;
1487   case 3:
1488     /* Hybrid Simplicial 2D */
1489     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
1490     cMax = PetscMin(cEnd, cMax);
1491     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
1492     fMax = PetscMin(fEnd, fMax);
1493     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);CHKERRQ(ierr);
1494     /* Interior cells have 3 faces */
1495     for (c = cStart; c < cMax; ++c) {
1496       const PetscInt  newp = cStartNew + (c - cStart)*4;
1497       const PetscInt *cone, *ornt;
1498       PetscInt        coneNew[3], orntNew[3];
1499 
1500       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1501       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1502       /* A triangle */
1503       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1504       orntNew[0] = ornt[0];
1505       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
1506       orntNew[1] = -2;
1507       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1508       orntNew[2] = ornt[2];
1509       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1510       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1511 #if 1
1512       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+0, cStartNew, cMaxNew);
1513       for (p = 0; p < 3; ++p) {
1514         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
1515       }
1516 #endif
1517       /* B triangle */
1518       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1519       orntNew[0] = ornt[0];
1520       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1521       orntNew[1] = ornt[1];
1522       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
1523       orntNew[2] = -2;
1524       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1525       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1526 #if 1
1527       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+1, cStartNew, cMaxNew);
1528       for (p = 0; p < 3; ++p) {
1529         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
1530       }
1531 #endif
1532       /* C triangle */
1533       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
1534       orntNew[0] = -2;
1535       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1536       orntNew[1] = ornt[1];
1537       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1538       orntNew[2] = ornt[2];
1539       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1540       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1541 #if 1
1542       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+2, cStartNew, cMaxNew);
1543       for (p = 0; p < 3; ++p) {
1544         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
1545       }
1546 #endif
1547       /* D triangle */
1548       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
1549       orntNew[0] = 0;
1550       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
1551       orntNew[1] = 0;
1552       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
1553       orntNew[2] = 0;
1554       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1555       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1556 #if 1
1557       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+3, cStartNew, cMaxNew);
1558       for (p = 0; p < 3; ++p) {
1559         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
1560       }
1561 #endif
1562     }
1563     /*
1564      2----3----3
1565      |         |
1566      |    B    |
1567      |         |
1568      0----4--- 1
1569      |         |
1570      |    A    |
1571      |         |
1572      0----2----1
1573      */
1574     /* Hybrid cells have 4 faces */
1575     for (c = cMax; c < cEnd; ++c) {
1576       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
1577       const PetscInt *cone, *ornt;
1578       PetscInt        coneNew[4], orntNew[4], r;
1579 
1580       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1581       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1582       r    = (ornt[0] < 0 ? 1 : 0);
1583       /* A quad */
1584       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + r;
1585       orntNew[0]   = ornt[0];
1586       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + r;
1587       orntNew[1]   = ornt[1];
1588       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2+r] - fMax);
1589       orntNew[2+r] = 0;
1590       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
1591       orntNew[3-r] = 0;
1592       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1593       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1594 #if 1
1595       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);
1596       for (p = 0; p < 4; ++p) {
1597         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);
1598       }
1599 #endif
1600       /* B quad */
1601       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + 1-r;
1602       orntNew[0]   = ornt[0];
1603       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + 1-r;
1604       orntNew[1]   = ornt[1];
1605       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
1606       orntNew[2+r] = 0;
1607       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3-r] - fMax);
1608       orntNew[3-r] = 0;
1609       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1610       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1611 #if 1
1612       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);
1613       for (p = 0; p < 4; ++p) {
1614         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);
1615       }
1616 #endif
1617     }
1618     /* Interior split faces have 2 vertices and the same cells as the parent */
1619     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1620     ierr = PetscMalloc1((2 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
1621     for (f = fStart; f < fMax; ++f) {
1622       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1623 
1624       for (r = 0; r < 2; ++r) {
1625         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1626         const PetscInt *cone, *ornt, *support;
1627         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1628 
1629         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1630         coneNew[0]       = vStartNew + (cone[0] - vStart);
1631         coneNew[1]       = vStartNew + (cone[1] - vStart);
1632         coneNew[(r+1)%2] = newv;
1633         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1634 #if 1
1635         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1636         for (p = 0; p < 2; ++p) {
1637           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);
1638         }
1639 #endif
1640         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1641         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1642         for (s = 0; s < supportSize; ++s) {
1643           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1644           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1645           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1646           for (c = 0; c < coneSize; ++c) if (cone[c] == f) break;
1647           if (support[s] >= cMax) {
1648             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[c] < 0 ? 1-r : r);
1649           } else {
1650             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1651           }
1652         }
1653         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1654 #if 1
1655         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1656         for (p = 0; p < supportSize; ++p) {
1657           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);
1658         }
1659 #endif
1660       }
1661     }
1662     /* Interior cell faces have 2 vertices and 2 cells */
1663     for (c = cStart; c < cMax; ++c) {
1664       const PetscInt *cone;
1665 
1666       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1667       for (r = 0; r < 3; ++r) {
1668         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
1669         PetscInt       coneNew[2];
1670         PetscInt       supportNew[2];
1671 
1672         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
1673         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
1674         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1675 #if 1
1676         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1677         for (p = 0; p < 2; ++p) {
1678           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);
1679         }
1680 #endif
1681         supportNew[0] = (c - cStart)*4 + (r+1)%3;
1682         supportNew[1] = (c - cStart)*4 + 3;
1683         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1684 #if 1
1685         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1686         for (p = 0; p < 2; ++p) {
1687           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);
1688         }
1689 #endif
1690       }
1691     }
1692     /* Interior hybrid faces have 2 vertices and the same cells */
1693     for (f = fMax; f < fEnd; ++f) {
1694       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
1695       const PetscInt *cone, *ornt;
1696       const PetscInt *support;
1697       PetscInt        coneNew[2];
1698       PetscInt        supportNew[2];
1699       PetscInt        size, s, r;
1700 
1701       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1702       coneNew[0] = vStartNew + (cone[0] - vStart);
1703       coneNew[1] = vStartNew + (cone[1] - vStart);
1704       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1705 #if 1
1706       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1707       for (p = 0; p < 2; ++p) {
1708         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);
1709       }
1710 #endif
1711       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1712       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1713       for (s = 0; s < size; ++s) {
1714         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1715         ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1716         for (r = 0; r < 2; ++r) {
1717           if (cone[r+2] == f) break;
1718         }
1719         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[0] < 0 ? 1-r : r);
1720       }
1721       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1722 #if 1
1723       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1724       for (p = 0; p < size; ++p) {
1725         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);
1726       }
1727 #endif
1728     }
1729     /* Cell hybrid faces have 2 vertices and 2 cells */
1730     for (c = cMax; c < cEnd; ++c) {
1731       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
1732       const PetscInt *cone;
1733       PetscInt        coneNew[2];
1734       PetscInt        supportNew[2];
1735 
1736       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1737       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
1738       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
1739       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1740 #if 1
1741       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1742       for (p = 0; p < 2; ++p) {
1743         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);
1744       }
1745 #endif
1746       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
1747       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
1748       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1749 #if 1
1750       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1751       for (p = 0; p < 2; ++p) {
1752         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);
1753       }
1754 #endif
1755     }
1756     /* Old vertices have identical supports */
1757     for (v = vStart; v < vEnd; ++v) {
1758       const PetscInt  newp = vStartNew + (v - vStart);
1759       const PetscInt *support, *cone;
1760       PetscInt        size, s;
1761 
1762       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1763       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1764       for (s = 0; s < size; ++s) {
1765         if (support[s] >= fMax) {
1766           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
1767         } else {
1768           PetscInt r = 0;
1769 
1770           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1771           if (cone[1] == v) r = 1;
1772           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1773         }
1774       }
1775       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1776 #if 1
1777       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1778       for (p = 0; p < size; ++p) {
1779         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);
1780       }
1781 #endif
1782     }
1783     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
1784     for (f = fStart; f < fMax; ++f) {
1785       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1786       const PetscInt *cone, *support;
1787       PetscInt        size, newSize = 2, s;
1788 
1789       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1790       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1791       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1792       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1793       for (s = 0; s < size; ++s) {
1794         PetscInt r = 0;
1795 
1796         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1797         if (support[s] >= cMax) {
1798           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
1799 
1800           newSize += 1;
1801         } else {
1802           if      (cone[1] == f) r = 1;
1803           else if (cone[2] == f) r = 2;
1804           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
1805           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
1806 
1807           newSize += 2;
1808         }
1809       }
1810       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1811 #if 1
1812       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1813       for (p = 0; p < newSize; ++p) {
1814         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);
1815       }
1816 #endif
1817     }
1818     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1819     break;
1820   case 4:
1821     /* Hybrid Hex 2D */
1822     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
1823     cMax = PetscMin(cEnd, cMax);
1824     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
1825     fMax = PetscMin(fEnd, fMax);
1826     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);CHKERRQ(ierr);
1827     /* Interior cells have 4 faces */
1828     for (c = cStart; c < cMax; ++c) {
1829       const PetscInt  newp = cStartNew + (c - cStart)*4;
1830       const PetscInt *cone, *ornt;
1831       PetscInt        coneNew[4], orntNew[4];
1832 
1833       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1834       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1835       /* A quad */
1836       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1837       orntNew[0] = ornt[0];
1838       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
1839       orntNew[1] = 0;
1840       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
1841       orntNew[2] = -2;
1842       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
1843       orntNew[3] = ornt[3];
1844       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1845       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1846 #if 1
1847       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+0, cStartNew, cMaxNew);
1848       for (p = 0; p < 4; ++p) {
1849         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
1850       }
1851 #endif
1852       /* B quad */
1853       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1854       orntNew[0] = ornt[0];
1855       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1856       orntNew[1] = ornt[1];
1857       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
1858       orntNew[2] = 0;
1859       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
1860       orntNew[3] = -2;
1861       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1862       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1863 #if 1
1864       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+1, cStartNew, cMaxNew);
1865       for (p = 0; p < 4; ++p) {
1866         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
1867       }
1868 #endif
1869       /* C quad */
1870       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
1871       orntNew[0] = -2;
1872       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1873       orntNew[1] = ornt[1];
1874       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1875       orntNew[2] = ornt[2];
1876       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
1877       orntNew[3] = 0;
1878       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1879       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1880 #if 1
1881       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+2, cStartNew, cMaxNew);
1882       for (p = 0; p < 4; ++p) {
1883         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
1884       }
1885 #endif
1886       /* D quad */
1887       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
1888       orntNew[0] = 0;
1889       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
1890       orntNew[1] = -2;
1891       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1892       orntNew[2] = ornt[2];
1893       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
1894       orntNew[3] = ornt[3];
1895       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1896       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1897 #if 1
1898       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+3, cStartNew, cMaxNew);
1899       for (p = 0; p < 4; ++p) {
1900         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
1901       }
1902 #endif
1903     }
1904     /*
1905      2----3----3
1906      |         |
1907      |    B    |
1908      |         |
1909      0----4--- 1
1910      |         |
1911      |    A    |
1912      |         |
1913      0----2----1
1914      */
1915     /* Hybrid cells have 4 faces */
1916     for (c = cMax; c < cEnd; ++c) {
1917       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
1918       const PetscInt *cone, *ornt;
1919       PetscInt        coneNew[4], orntNew[4];
1920 
1921       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1922       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1923       /* A quad */
1924       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1925       orntNew[0] = ornt[0];
1926       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1927       orntNew[1] = ornt[1];
1928       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[2] - fMax);
1929       orntNew[2] = 0;
1930       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
1931       orntNew[3] = 0;
1932       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1933       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1934 #if 1
1935       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);
1936       for (p = 0; p < 4; ++p) {
1937         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);
1938       }
1939 #endif
1940       /* B quad */
1941       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1942       orntNew[0] = ornt[0];
1943       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1944       orntNew[1] = ornt[1];
1945       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
1946       orntNew[2] = 0;
1947       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[3] - fMax);
1948       orntNew[3] = 0;
1949       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1950       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1951 #if 1
1952       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);
1953       for (p = 0; p < 4; ++p) {
1954         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);
1955       }
1956 #endif
1957     }
1958     /* Interior split faces have 2 vertices and the same cells as the parent */
1959     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1960     ierr = PetscMalloc1((2 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
1961     for (f = fStart; f < fMax; ++f) {
1962       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1963 
1964       for (r = 0; r < 2; ++r) {
1965         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1966         const PetscInt *cone, *ornt, *support;
1967         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1968 
1969         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1970         coneNew[0]       = vStartNew + (cone[0] - vStart);
1971         coneNew[1]       = vStartNew + (cone[1] - vStart);
1972         coneNew[(r+1)%2] = newv;
1973         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1974 #if 1
1975         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1976         for (p = 0; p < 2; ++p) {
1977           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);
1978         }
1979 #endif
1980         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1981         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1982         for (s = 0; s < supportSize; ++s) {
1983           if (support[s] >= cMax) {
1984             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
1985           } else {
1986             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1987             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1988             ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1989             for (c = 0; c < coneSize; ++c) {
1990               if (cone[c] == f) break;
1991             }
1992             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
1993           }
1994         }
1995         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1996 #if 1
1997         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1998         for (p = 0; p < supportSize; ++p) {
1999           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);
2000         }
2001 #endif
2002       }
2003     }
2004     /* Interior cell faces have 2 vertices and 2 cells */
2005     for (c = cStart; c < cMax; ++c) {
2006       const PetscInt *cone;
2007 
2008       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2009       for (r = 0; r < 4; ++r) {
2010         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
2011         PetscInt       coneNew[2], supportNew[2];
2012 
2013         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2014         coneNew[1] = vStartNew + (vEnd - vStart) + (fMax    - fStart) + (c - cStart);
2015         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2016 #if 1
2017         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2018         for (p = 0; p < 2; ++p) {
2019           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);
2020         }
2021 #endif
2022         supportNew[0] = (c - cStart)*4 + r;
2023         supportNew[1] = (c - cStart)*4 + (r+1)%4;
2024         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2025 #if 1
2026         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2027         for (p = 0; p < 2; ++p) {
2028           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);
2029         }
2030 #endif
2031       }
2032     }
2033     /* Hybrid faces have 2 vertices and the same cells */
2034     for (f = fMax; f < fEnd; ++f) {
2035       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
2036       const PetscInt *cone, *support;
2037       PetscInt        coneNew[2], supportNew[2];
2038       PetscInt        size, s, r;
2039 
2040       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2041       coneNew[0] = vStartNew + (cone[0] - vStart);
2042       coneNew[1] = vStartNew + (cone[1] - vStart);
2043       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2044 #if 1
2045       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2046       for (p = 0; p < 2; ++p) {
2047         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);
2048       }
2049 #endif
2050       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2051       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2052       for (s = 0; s < size; ++s) {
2053         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2054         for (r = 0; r < 2; ++r) {
2055           if (cone[r+2] == f) break;
2056         }
2057         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
2058       }
2059       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2060 #if 1
2061       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2062       for (p = 0; p < size; ++p) {
2063         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);
2064       }
2065 #endif
2066     }
2067     /* Cell hybrid faces have 2 vertices and 2 cells */
2068     for (c = cMax; c < cEnd; ++c) {
2069       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
2070       const PetscInt *cone;
2071       PetscInt        coneNew[2], supportNew[2];
2072 
2073       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2074       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
2075       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
2076       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2077 #if 1
2078       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2079       for (p = 0; p < 2; ++p) {
2080         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);
2081       }
2082 #endif
2083       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
2084       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
2085       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2086 #if 1
2087       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2088       for (p = 0; p < 2; ++p) {
2089         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);
2090       }
2091 #endif
2092     }
2093     /* Old vertices have identical supports */
2094     for (v = vStart; v < vEnd; ++v) {
2095       const PetscInt  newp = vStartNew + (v - vStart);
2096       const PetscInt *support, *cone;
2097       PetscInt        size, s;
2098 
2099       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2100       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2101       for (s = 0; s < size; ++s) {
2102         if (support[s] >= fMax) {
2103           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (support[s] - fMax);
2104         } else {
2105           PetscInt r = 0;
2106 
2107           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2108           if (cone[1] == v) r = 1;
2109           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2110         }
2111       }
2112       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2113 #if 1
2114       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2115       for (p = 0; p < size; ++p) {
2116         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);
2117       }
2118 #endif
2119     }
2120     /* Face vertices have 2 + cells supports */
2121     for (f = fStart; f < fMax; ++f) {
2122       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2123       const PetscInt *cone, *support;
2124       PetscInt        size, s;
2125 
2126       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2127       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2128       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2129       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2130       for (s = 0; s < size; ++s) {
2131         PetscInt r = 0;
2132 
2133         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2134         if (support[s] >= cMax) {
2135           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (support[s] - cMax);
2136         } else {
2137           if      (cone[1] == f) r = 1;
2138           else if (cone[2] == f) r = 2;
2139           else if (cone[3] == f) r = 3;
2140           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*4 + r;
2141         }
2142       }
2143       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2144 #if 1
2145       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2146       for (p = 0; p < 2+size; ++p) {
2147         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);
2148       }
2149 #endif
2150     }
2151     /* Cell vertices have 4 supports */
2152     for (c = cStart; c < cMax; ++c) {
2153       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
2154       PetscInt       supportNew[4];
2155 
2156       for (r = 0; r < 4; ++r) {
2157         supportNew[r] = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
2158       }
2159       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2160     }
2161     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2162     break;
2163   case 5:
2164     /* Simplicial 3D */
2165     /* All cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
2166     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
2167     for (c = cStart; c < cEnd; ++c) {
2168       const PetscInt  newp = cStartNew + (c - cStart)*8;
2169       const PetscInt *cone, *ornt;
2170       PetscInt        coneNew[4], orntNew[4];
2171 
2172       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2173       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2174       /* A tetrahedron: {0, a, c, d} */
2175       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
2176       orntNew[0] = ornt[0];
2177       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
2178       orntNew[1] = ornt[1];
2179       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
2180       orntNew[2] = ornt[2];
2181       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
2182       orntNew[3] = 0;
2183       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2184       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2185 #if 1
2186       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);
2187       for (p = 0; p < 4; ++p) {
2188         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);
2189       }
2190 #endif
2191       /* B tetrahedron: {a, 1, b, e} */
2192       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
2193       orntNew[0] = ornt[0];
2194       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
2195       orntNew[1] = ornt[1];
2196       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
2197       orntNew[2] = 0;
2198       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
2199       orntNew[3] = ornt[3];
2200       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2201       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2202 #if 1
2203       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);
2204       for (p = 0; p < 4; ++p) {
2205         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);
2206       }
2207 #endif
2208       /* C tetrahedron: {c, b, 2, f} */
2209       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
2210       orntNew[0] = ornt[0];
2211       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
2212       orntNew[1] = 0;
2213       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
2214       orntNew[2] = ornt[2];
2215       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
2216       orntNew[3] = ornt[3];
2217       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2218       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2219 #if 1
2220       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);
2221       for (p = 0; p < 4; ++p) {
2222         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);
2223       }
2224 #endif
2225       /* D tetrahedron: {d, e, f, 3} */
2226       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
2227       orntNew[0] = 0;
2228       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
2229       orntNew[1] = ornt[1];
2230       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
2231       orntNew[2] = ornt[2];
2232       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
2233       orntNew[3] = ornt[3];
2234       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2235       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2236 #if 1
2237       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);
2238       for (p = 0; p < 4; ++p) {
2239         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);
2240       }
2241 #endif
2242       /* A' tetrahedron: {d, a, c, f} */
2243       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
2244       orntNew[0] = -3;
2245       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
2246       orntNew[1] = ornt[2] < 0 ? -(GetTetSomething_Static(ornt[2], 0)+1) : GetTetSomething_Static(ornt[2], 0);
2247       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
2248       orntNew[2] = 0;
2249       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
2250       orntNew[3] = 2;
2251       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
2252       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
2253 #if 1
2254       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);
2255       for (p = 0; p < 4; ++p) {
2256         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);
2257       }
2258 #endif
2259       /* B' tetrahedron: {e, b, a, f} */
2260       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
2261       orntNew[0] = -3;
2262       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
2263       orntNew[1] = 1;
2264       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
2265       orntNew[2] = 0;
2266       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + 3;
2267       orntNew[3] = ornt[3] < 0 ? -(GetTetSomething_Static(ornt[3], 0)+1) : GetTetSomething_Static(ornt[3], 0);
2268       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
2269       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
2270 #if 1
2271       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);
2272       for (p = 0; p < 4; ++p) {
2273         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);
2274       }
2275 #endif
2276       /* C' tetrahedron: {b, f, c, a} */
2277       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
2278       orntNew[0] = -3;
2279       coneNew[1] = fStartNew + (cone[0] - fStart)*4 + 3;
2280       orntNew[1] = ornt[0] < 0 ? -(GetTetSomething_Static(ornt[0], 2)+1) : GetTetSomething_Static(ornt[0], 2);
2281       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
2282       orntNew[2] = -3;
2283       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
2284       orntNew[3] = -2;
2285       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
2286       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
2287 #if 1
2288       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);
2289       for (p = 0; p < 4; ++p) {
2290         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);
2291       }
2292 #endif
2293       /* D' tetrahedron: {f, e, d, a} */
2294       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
2295       orntNew[0] = -3;
2296       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
2297       orntNew[1] = -3;
2298       coneNew[2] = fStartNew + (cone[1] - fStart)*4 + 3;
2299       orntNew[2] = ornt[1] < 0 ? -(GetTetSomething_Static(ornt[1], 0)+1) : GetTetSomething_Static(ornt[1], 0);
2300       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
2301       orntNew[3] = -3;
2302       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
2303       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
2304 #if 1
2305       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);
2306       for (p = 0; p < 4; ++p) {
2307         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);
2308       }
2309 #endif
2310     }
2311     /* Split faces have 3 edges and the same cells as the parent */
2312     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2313     ierr = PetscMalloc1((2 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
2314     for (f = fStart; f < fEnd; ++f) {
2315       const PetscInt  newp = fStartNew + (f - fStart)*4;
2316       const PetscInt *cone, *ornt, *support;
2317       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
2318 
2319       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2320       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
2321       /* A triangle */
2322       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
2323       orntNew[0] = ornt[0];
2324       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
2325       orntNew[1] = -2;
2326       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
2327       orntNew[2] = ornt[2];
2328       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2329       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2330 #if 1
2331       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);
2332       for (p = 0; p < 3; ++p) {
2333         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);
2334       }
2335 #endif
2336       /* B triangle */
2337       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
2338       orntNew[0] = ornt[0];
2339       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
2340       orntNew[1] = ornt[1];
2341       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
2342       orntNew[2] = -2;
2343       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2344       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2345 #if 1
2346       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);
2347       for (p = 0; p < 3; ++p) {
2348         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);
2349       }
2350 #endif
2351       /* C triangle */
2352       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
2353       orntNew[0] = -2;
2354       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
2355       orntNew[1] = ornt[1];
2356       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
2357       orntNew[2] = ornt[2];
2358       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2359       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2360 #if 1
2361       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);
2362       for (p = 0; p < 3; ++p) {
2363         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);
2364       }
2365 #endif
2366       /* D triangle */
2367       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
2368       orntNew[0] = 0;
2369       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
2370       orntNew[1] = 0;
2371       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
2372       orntNew[2] = 0;
2373       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2374       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2375 #if 1
2376       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);
2377       for (p = 0; p < 3; ++p) {
2378         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);
2379       }
2380 #endif
2381       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2382       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2383       for (r = 0; r < 4; ++r) {
2384         for (s = 0; s < supportSize; ++s) {
2385           PetscInt subf;
2386           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2387           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2388           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2389           for (c = 0; c < coneSize; ++c) {
2390             if (cone[c] == f) break;
2391           }
2392           subf = GetTriSubfaceInverse_Static(ornt[c], r);
2393           supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
2394         }
2395         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
2396 #if 1
2397         if ((newp+r < fStartNew) || (newp+r >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+r, fStartNew, fEndNew);
2398         for (p = 0; p < supportSize; ++p) {
2399           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);
2400         }
2401 #endif
2402       }
2403     }
2404     /* Interior faces have 3 edges and 2 cells */
2405     for (c = cStart; c < cEnd; ++c) {
2406       PetscInt        newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8;
2407       const PetscInt *cone, *ornt;
2408       PetscInt        coneNew[3], orntNew[3];
2409       PetscInt        supportNew[2];
2410 
2411       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2412       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2413       /* Face A: {c, a, d} */
2414       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
2415       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2416       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
2417       orntNew[1] = ornt[1] < 0 ? -2 : 0;
2418       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 2);
2419       orntNew[2] = ornt[2] < 0 ? -2 : 0;
2420       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2421       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2422 #if 1
2423       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2424       for (p = 0; p < 3; ++p) {
2425         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);
2426       }
2427 #endif
2428       supportNew[0] = (c - cStart)*8 + 0;
2429       supportNew[1] = (c - cStart)*8 + 0+4;
2430       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2431 #if 1
2432       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2433       for (p = 0; p < 2; ++p) {
2434         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);
2435       }
2436 #endif
2437       ++newp;
2438       /* Face B: {a, b, e} */
2439       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
2440       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2441       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 0);
2442       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2443       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
2444       orntNew[2] = ornt[1] < 0 ? -2 : 0;
2445       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2446       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2447 #if 1
2448       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2449       for (p = 0; p < 3; ++p) {
2450         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);
2451       }
2452 #endif
2453       supportNew[0] = (c - cStart)*8 + 1;
2454       supportNew[1] = (c - cStart)*8 + 1+4;
2455       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2456 #if 1
2457       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2458       for (p = 0; p < 2; ++p) {
2459         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);
2460       }
2461 #endif
2462       ++newp;
2463       /* Face C: {c, f, b} */
2464       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
2465       orntNew[0] = ornt[2] < 0 ? -2 : 0;
2466       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
2467       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2468       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 1);
2469       orntNew[2] = ornt[0] < 0 ? -2 : 0;
2470       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2471       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2472 #if 1
2473       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2474       for (p = 0; p < 3; ++p) {
2475         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);
2476       }
2477 #endif
2478       supportNew[0] = (c - cStart)*8 + 2;
2479       supportNew[1] = (c - cStart)*8 + 2+4;
2480       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2481 #if 1
2482       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2483       for (p = 0; p < 2; ++p) {
2484         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);
2485       }
2486 #endif
2487       ++newp;
2488       /* Face D: {d, e, f} */
2489       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 0);
2490       orntNew[0] = ornt[1] < 0 ? -2 : 0;
2491       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
2492       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2493       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
2494       orntNew[2] = ornt[2] < 0 ? -2 : 0;
2495       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2496       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2497 #if 1
2498       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2499       for (p = 0; p < 3; ++p) {
2500         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);
2501       }
2502 #endif
2503       supportNew[0] = (c - cStart)*8 + 3;
2504       supportNew[1] = (c - cStart)*8 + 3+4;
2505       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2506 #if 1
2507       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2508       for (p = 0; p < 2; ++p) {
2509         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);
2510       }
2511 #endif
2512       ++newp;
2513       /* Face E: {d, f, a} */
2514       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
2515       orntNew[0] = ornt[2] < 0 ? 0 : -2;
2516       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2517       orntNew[1] = -2;
2518       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
2519       orntNew[2] = ornt[1] < 0 ? -2 : 0;
2520       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2521       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2522 #if 1
2523       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2524       for (p = 0; p < 3; ++p) {
2525         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);
2526       }
2527 #endif
2528       supportNew[0] = (c - cStart)*8 + 0+4;
2529       supportNew[1] = (c - cStart)*8 + 3+4;
2530       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2531 #if 1
2532       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2533       for (p = 0; p < 2; ++p) {
2534         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);
2535       }
2536 #endif
2537       ++newp;
2538       /* Face F: {c, a, f} */
2539       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
2540       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2541       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2542       orntNew[1] = 0;
2543       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
2544       orntNew[2] = ornt[2] < 0 ? 0 : -2;
2545       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2546       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2547 #if 1
2548       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2549       for (p = 0; p < 3; ++p) {
2550         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);
2551       }
2552 #endif
2553       supportNew[0] = (c - cStart)*8 + 0+4;
2554       supportNew[1] = (c - cStart)*8 + 2+4;
2555       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2556 #if 1
2557       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2558       for (p = 0; p < 2; ++p) {
2559         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);
2560       }
2561 #endif
2562       ++newp;
2563       /* Face G: {e, a, f} */
2564       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
2565       orntNew[0] = ornt[1] < 0 ? -2 : 0;
2566       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2567       orntNew[1] = 0;
2568       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
2569       orntNew[2] = ornt[3] < 0 ? 0 : -2;
2570       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2571       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2572 #if 1
2573       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2574       for (p = 0; p < 3; ++p) {
2575         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);
2576       }
2577 #endif
2578       supportNew[0] = (c - cStart)*8 + 1+4;
2579       supportNew[1] = (c - cStart)*8 + 3+4;
2580       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2581 #if 1
2582       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2583       for (p = 0; p < 2; ++p) {
2584         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);
2585       }
2586 #endif
2587       ++newp;
2588       /* Face H: {a, b, f} */
2589       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
2590       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2591       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
2592       orntNew[1] = ornt[3] < 0 ? 0 : -2;
2593       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2594       orntNew[2] = -2;
2595       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2596       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2597 #if 1
2598       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2599       for (p = 0; p < 3; ++p) {
2600         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);
2601       }
2602 #endif
2603       supportNew[0] = (c - cStart)*8 + 1+4;
2604       supportNew[1] = (c - cStart)*8 + 2+4;
2605       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2606 #if 1
2607       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2608       for (p = 0; p < 2; ++p) {
2609         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);
2610       }
2611 #endif
2612       ++newp;
2613     }
2614     /* Split Edges have 2 vertices and the same faces as the parent */
2615     for (e = eStart; e < eEnd; ++e) {
2616       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
2617 
2618       for (r = 0; r < 2; ++r) {
2619         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
2620         const PetscInt *cone, *ornt, *support;
2621         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2622 
2623         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
2624         coneNew[0]       = vStartNew + (cone[0] - vStart);
2625         coneNew[1]       = vStartNew + (cone[1] - vStart);
2626         coneNew[(r+1)%2] = newv;
2627         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2628 #if 1
2629         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2630         for (p = 0; p < 2; ++p) {
2631           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);
2632         }
2633 #endif
2634         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
2635         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
2636         for (s = 0; s < supportSize; ++s) {
2637           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2638           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2639           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2640           for (c = 0; c < coneSize; ++c) {
2641             if (cone[c] == e) break;
2642           }
2643           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
2644         }
2645         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2646 #if 1
2647         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2648         for (p = 0; p < supportSize; ++p) {
2649           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);
2650         }
2651 #endif
2652       }
2653     }
2654     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
2655     for (f = fStart; f < fEnd; ++f) {
2656       const PetscInt *cone, *ornt, *support;
2657       PetscInt        coneSize, supportSize, s;
2658 
2659       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2660       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2661       for (r = 0; r < 3; ++r) {
2662         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
2663         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
2664         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
2665                                     -1, -1,  1,  6,  0,  4,
2666                                      2,  5,  3,  4, -1, -1,
2667                                     -1, -1,  3,  6,  2,  7};
2668 
2669         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2670         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
2671         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
2672         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2673 #if 1
2674         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2675         for (p = 0; p < 2; ++p) {
2676           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);
2677         }
2678 #endif
2679         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
2680         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
2681         for (s = 0; s < supportSize; ++s) {
2682           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2683           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2684           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2685           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
2686           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
2687           er = GetTetSomethingInverse_Static(ornt[c], r);
2688           if (er == eint[c]) {
2689             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
2690           } else {
2691             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
2692             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
2693           }
2694         }
2695         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2696 #if 1
2697         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2698         for (p = 0; p < intFaces; ++p) {
2699           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);
2700         }
2701 #endif
2702       }
2703     }
2704     /* Interior edges have 2 vertices and 4 faces */
2705     for (c = cStart; c < cEnd; ++c) {
2706       const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2707       const PetscInt *cone, *ornt, *fcone;
2708       PetscInt        coneNew[2], supportNew[4], find;
2709 
2710       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2711       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2712       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
2713       find = GetTriEdge_Static(ornt[0], 0);
2714       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
2715       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
2716       find = GetTriEdge_Static(ornt[2], 1);
2717       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
2718       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2719 #if 1
2720       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2721       for (p = 0; p < 2; ++p) {
2722         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);
2723       }
2724 #endif
2725       supportNew[0] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 4;
2726       supportNew[1] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 5;
2727       supportNew[2] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 6;
2728       supportNew[3] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 7;
2729       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2730 #if 1
2731       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2732       for (p = 0; p < 4; ++p) {
2733         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);
2734       }
2735 #endif
2736     }
2737     /* Old vertices have identical supports */
2738     for (v = vStart; v < vEnd; ++v) {
2739       const PetscInt  newp = vStartNew + (v - vStart);
2740       const PetscInt *support, *cone;
2741       PetscInt        size, s;
2742 
2743       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2744       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2745       for (s = 0; s < size; ++s) {
2746         PetscInt r = 0;
2747 
2748         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2749         if (cone[1] == v) r = 1;
2750         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
2751       }
2752       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2753 #if 1
2754       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2755       for (p = 0; p < size; ++p) {
2756         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);
2757       }
2758 #endif
2759     }
2760     /* Edge vertices have 2 + face*2 + 0/1 supports */
2761     for (e = eStart; e < eEnd; ++e) {
2762       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
2763       const PetscInt *cone, *support;
2764       PetscInt       *star = NULL, starSize, cellSize = 0, coneSize, size, s;
2765 
2766       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
2767       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
2768       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
2769       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
2770       for (s = 0; s < size; ++s) {
2771         PetscInt r = 0;
2772 
2773         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2774         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2775         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
2776         supportRef[2+s*2+0] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
2777         supportRef[2+s*2+1] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
2778       }
2779       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
2780       for (s = 0; s < starSize*2; s += 2) {
2781         const PetscInt *cone, *ornt;
2782         PetscInt        e01, e23;
2783 
2784         if ((star[s] >= cStart) && (star[s] < cEnd)) {
2785           /* Check edge 0-1 */
2786           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
2787           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
2788           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
2789           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
2790           /* Check edge 2-3 */
2791           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
2792           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
2793           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
2794           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
2795           if ((e01 == e) || (e23 == e)) {supportRef[2+size*2+cellSize++] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (star[s] - cStart);}
2796         }
2797       }
2798       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
2799       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2800 #if 1
2801       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2802       for (p = 0; p < 2+size*2+cellSize; ++p) {
2803         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);
2804       }
2805 #endif
2806     }
2807     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2808     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
2809     break;
2810   case 7:
2811     /* Hybrid Simplicial 3D */
2812     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
2813     /* Interior cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
2814     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
2815     for (c = cStart; c < cMax; ++c) {
2816       const PetscInt  newp = cStartNew + (c - cStart)*8;
2817       const PetscInt *cone, *ornt;
2818       PetscInt        coneNew[4], orntNew[4];
2819 
2820       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2821       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2822       /* A tetrahedron: {0, a, c, d} */
2823       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
2824       orntNew[0] = ornt[0];
2825       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
2826       orntNew[1] = ornt[1];
2827       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
2828       orntNew[2] = ornt[2];
2829       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
2830       orntNew[3] = 0;
2831       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2832       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2833 #if 1
2834       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);
2835       for (p = 0; p < 4; ++p) {
2836         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);
2837       }
2838 #endif
2839       /* B tetrahedron: {a, 1, b, e} */
2840       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
2841       orntNew[0] = ornt[0];
2842       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
2843       orntNew[1] = ornt[1];
2844       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
2845       orntNew[2] = 0;
2846       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
2847       orntNew[3] = ornt[3];
2848       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2849       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2850 #if 1
2851       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);
2852       for (p = 0; p < 4; ++p) {
2853         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);
2854       }
2855 #endif
2856       /* C tetrahedron: {c, b, 2, f} */
2857       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
2858       orntNew[0] = ornt[0];
2859       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
2860       orntNew[1] = 0;
2861       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
2862       orntNew[2] = ornt[2];
2863       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
2864       orntNew[3] = ornt[3];
2865       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2866       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2867 #if 1
2868       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);
2869       for (p = 0; p < 4; ++p) {
2870         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);
2871       }
2872 #endif
2873       /* D tetrahedron: {d, e, f, 3} */
2874       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
2875       orntNew[0] = 0;
2876       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
2877       orntNew[1] = ornt[1];
2878       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
2879       orntNew[2] = ornt[2];
2880       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
2881       orntNew[3] = ornt[3];
2882       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2883       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2884 #if 1
2885       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);
2886       for (p = 0; p < 4; ++p) {
2887         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);
2888       }
2889 #endif
2890       /* A' tetrahedron: {d, a, c, f} */
2891       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
2892       orntNew[0] = -3;
2893       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
2894       orntNew[1] = ornt[2] < 0 ? -(GetTetSomething_Static(ornt[2], 0)+1) : GetTetSomething_Static(ornt[2], 0);
2895       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
2896       orntNew[2] = 0;
2897       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
2898       orntNew[3] = 2;
2899       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
2900       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
2901 #if 1
2902       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);
2903       for (p = 0; p < 4; ++p) {
2904         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);
2905       }
2906 #endif
2907       /* B' tetrahedron: {e, b, a, f} */
2908       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
2909       orntNew[0] = -3;
2910       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
2911       orntNew[1] = 1;
2912       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
2913       orntNew[2] = 0;
2914       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + 3;
2915       orntNew[3] = ornt[3] < 0 ? -(GetTetSomething_Static(ornt[3], 0)+1) : GetTetSomething_Static(ornt[3], 0);
2916       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
2917       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
2918 #if 1
2919       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);
2920       for (p = 0; p < 4; ++p) {
2921         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);
2922       }
2923 #endif
2924       /* C' tetrahedron: {b, f, c, a} */
2925       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
2926       orntNew[0] = -3;
2927       coneNew[1] = fStartNew + (cone[0] - fStart)*4 + 3;
2928       orntNew[1] = ornt[0] < 0 ? -(GetTetSomething_Static(ornt[0], 2)+1) : GetTetSomething_Static(ornt[0], 2);
2929       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
2930       orntNew[2] = -3;
2931       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
2932       orntNew[3] = -2;
2933       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
2934       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
2935 #if 1
2936       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);
2937       for (p = 0; p < 4; ++p) {
2938         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);
2939       }
2940 #endif
2941       /* D' tetrahedron: {f, e, d, a} */
2942       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
2943       orntNew[0] = -3;
2944       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
2945       orntNew[1] = -3;
2946       coneNew[2] = fStartNew + (cone[1] - fStart)*4 + 3;
2947       orntNew[2] = ornt[1] < 0 ? -(GetTetSomething_Static(ornt[1], 0)+1) : GetTetSomething_Static(ornt[1], 0);
2948       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
2949       orntNew[3] = -3;
2950       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
2951       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
2952 #if 1
2953       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);
2954       for (p = 0; p < 4; ++p) {
2955         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);
2956       }
2957 #endif
2958     }
2959     /* Hybrid cells have 5 faces */
2960     for (c = cMax; c < cEnd; ++c) {
2961       const PetscInt  newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4;
2962       const PetscInt *cone, *ornt, *fornt;
2963       PetscInt        coneNew[5], orntNew[5], o, of, i;
2964 
2965       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2966       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2967       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
2968       o = ornt[0] < 0 ? -1 : 1;
2969       for (r = 0; r < 3; ++r) {
2970         coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], r);
2971         orntNew[0] = ornt[0];
2972         coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], r);
2973         orntNew[1] = ornt[1];
2974         of = fornt[GetTriEdge_Static(ornt[0], r)]       < 0 ? -1 : 1;
2975         i  = GetTriEdgeInverse_Static(ornt[0], r)       + 2;
2976         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], r)]       - fMax)*2 + (o*of < 0 ? 1 : 0);
2977         orntNew[i] = 0;
2978         i  = GetTriEdgeInverse_Static(ornt[0], (r+1)%3) + 2;
2979         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + GetTriSubface_Static(ornt[0], r);
2980         orntNew[i] = 0;
2981         of = fornt[GetTriEdge_Static(ornt[0], (r+2)%3)] < 0 ? -1 : 1;
2982         i  = GetTriEdgeInverse_Static(ornt[0], (r+2)%3) + 2;
2983         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], (r+2)%3)] - fMax)*2 + (o*of < 0 ? 0 : 1);
2984         orntNew[i] = 0;
2985         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
2986         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
2987 #if 1
2988         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);
2989         for (p = 0; p < 2; ++p) {
2990           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);
2991         }
2992         for (p = 2; p < 5; ++p) {
2993           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);
2994         }
2995 #endif
2996       }
2997       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + 3;
2998       orntNew[0] = 0;
2999       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + 3;
3000       orntNew[1] = 0;
3001       coneNew[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
3002       orntNew[2] = 0;
3003       coneNew[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
3004       orntNew[3] = 0;
3005       coneNew[4] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
3006       orntNew[4] = 0;
3007       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3008       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3009 #if 1
3010       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);
3011       for (p = 0; p < 2; ++p) {
3012         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);
3013       }
3014       for (p = 2; p < 5; ++p) {
3015         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);
3016       }
3017 #endif
3018     }
3019     /* Split faces have 3 edges and the same cells as the parent */
3020     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3021     ierr = PetscMalloc1((2 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
3022     for (f = fStart; f < fMax; ++f) {
3023       const PetscInt  newp = fStartNew + (f - fStart)*4;
3024       const PetscInt *cone, *ornt, *support;
3025       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
3026 
3027       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3028       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3029       /* A triangle */
3030       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
3031       orntNew[0] = ornt[0];
3032       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
3033       orntNew[1] = -2;
3034       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
3035       orntNew[2] = ornt[2];
3036       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3037       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3038 #if 1
3039       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);
3040       for (p = 0; p < 3; ++p) {
3041         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);
3042       }
3043 #endif
3044       /* B triangle */
3045       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
3046       orntNew[0] = ornt[0];
3047       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
3048       orntNew[1] = ornt[1];
3049       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
3050       orntNew[2] = -2;
3051       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3052       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3053 #if 1
3054       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);
3055       for (p = 0; p < 3; ++p) {
3056         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);
3057       }
3058 #endif
3059       /* C triangle */
3060       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
3061       orntNew[0] = -2;
3062       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
3063       orntNew[1] = ornt[1];
3064       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
3065       orntNew[2] = ornt[2];
3066       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3067       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3068 #if 1
3069       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);
3070       for (p = 0; p < 3; ++p) {
3071         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);
3072       }
3073 #endif
3074       /* D triangle */
3075       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
3076       orntNew[0] = 0;
3077       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
3078       orntNew[1] = 0;
3079       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
3080       orntNew[2] = 0;
3081       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3082       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3083 #if 1
3084       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);
3085       for (p = 0; p < 3; ++p) {
3086         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);
3087       }
3088 #endif
3089       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3090       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3091       for (r = 0; r < 4; ++r) {
3092         for (s = 0; s < supportSize; ++s) {
3093           PetscInt subf;
3094           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3095           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3096           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3097           for (c = 0; c < coneSize; ++c) {
3098             if (cone[c] == f) break;
3099           }
3100           subf = GetTriSubfaceInverse_Static(ornt[c], r);
3101           if (support[s] < cMax) {
3102             supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
3103           } else {
3104             supportRef[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (r==3 ? r : subf);
3105           }
3106         }
3107         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
3108 #if 1
3109         if ((newp+r < fStartNew) || (newp+r >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+r, fStartNew, fMaxNew);
3110         for (p = 0; p < supportSize; ++p) {
3111           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);
3112         }
3113 #endif
3114       }
3115     }
3116     /* Interior cell faces have 3 edges and 2 cells */
3117     for (c = cStart; c < cMax; ++c) {
3118       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8;
3119       const PetscInt *cone, *ornt;
3120       PetscInt        coneNew[3], orntNew[3];
3121       PetscInt        supportNew[2];
3122 
3123       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3124       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3125       /* Face A: {c, a, d} */
3126       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
3127       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3128       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
3129       orntNew[1] = ornt[1] < 0 ? -2 : 0;
3130       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 2);
3131       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3132       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3133       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3134 #if 1
3135       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3136       for (p = 0; p < 3; ++p) {
3137         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);
3138       }
3139 #endif
3140       supportNew[0] = (c - cStart)*8 + 0;
3141       supportNew[1] = (c - cStart)*8 + 0+4;
3142       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3143 #if 1
3144       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3145       for (p = 0; p < 2; ++p) {
3146         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);
3147       }
3148 #endif
3149       ++newp;
3150       /* Face B: {a, b, e} */
3151       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
3152       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3153       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 0);
3154       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3155       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
3156       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3157       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3158       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3159 #if 1
3160       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);
3161       for (p = 0; p < 3; ++p) {
3162         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);
3163       }
3164 #endif
3165       supportNew[0] = (c - cStart)*8 + 1;
3166       supportNew[1] = (c - cStart)*8 + 1+4;
3167       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3168 #if 1
3169       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3170       for (p = 0; p < 2; ++p) {
3171         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);
3172       }
3173 #endif
3174       ++newp;
3175       /* Face C: {c, f, b} */
3176       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
3177       orntNew[0] = ornt[2] < 0 ? -2 : 0;
3178       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
3179       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3180       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 1);
3181       orntNew[2] = ornt[0] < 0 ? -2 : 0;
3182       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3183       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3184 #if 1
3185       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3186       for (p = 0; p < 3; ++p) {
3187         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);
3188       }
3189 #endif
3190       supportNew[0] = (c - cStart)*8 + 2;
3191       supportNew[1] = (c - cStart)*8 + 2+4;
3192       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3193 #if 1
3194       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3195       for (p = 0; p < 2; ++p) {
3196         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);
3197       }
3198 #endif
3199       ++newp;
3200       /* Face D: {d, e, f} */
3201       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 0);
3202       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3203       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
3204       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3205       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
3206       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3207       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3208       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3209 #if 1
3210       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3211       for (p = 0; p < 3; ++p) {
3212         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);
3213       }
3214 #endif
3215       supportNew[0] = (c - cStart)*8 + 3;
3216       supportNew[1] = (c - cStart)*8 + 3+4;
3217       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3218 #if 1
3219       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3220       for (p = 0; p < 2; ++p) {
3221         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);
3222       }
3223 #endif
3224       ++newp;
3225       /* Face E: {d, f, a} */
3226       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
3227       orntNew[0] = ornt[2] < 0 ? 0 : -2;
3228       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3229       orntNew[1] = -2;
3230       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
3231       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3232       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3233       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3234 #if 1
3235       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3236       for (p = 0; p < 3; ++p) {
3237         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);
3238       }
3239 #endif
3240       supportNew[0] = (c - cStart)*8 + 0+4;
3241       supportNew[1] = (c - cStart)*8 + 3+4;
3242       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3243 #if 1
3244       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3245       for (p = 0; p < 2; ++p) {
3246         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);
3247       }
3248 #endif
3249       ++newp;
3250       /* Face F: {c, a, f} */
3251       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
3252       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3253       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3254       orntNew[1] = 0;
3255       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
3256       orntNew[2] = ornt[2] < 0 ? 0 : -2;
3257       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3258       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3259 #if 1
3260       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3261       for (p = 0; p < 3; ++p) {
3262         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);
3263       }
3264 #endif
3265       supportNew[0] = (c - cStart)*8 + 0+4;
3266       supportNew[1] = (c - cStart)*8 + 2+4;
3267       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3268 #if 1
3269       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3270       for (p = 0; p < 2; ++p) {
3271         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);
3272       }
3273 #endif
3274       ++newp;
3275       /* Face G: {e, a, f} */
3276       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
3277       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3278       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3279       orntNew[1] = 0;
3280       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
3281       orntNew[2] = ornt[3] < 0 ? 0 : -2;
3282       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3283       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3284 #if 1
3285       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3286       for (p = 0; p < 3; ++p) {
3287         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);
3288       }
3289 #endif
3290       supportNew[0] = (c - cStart)*8 + 1+4;
3291       supportNew[1] = (c - cStart)*8 + 3+4;
3292       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3293 #if 1
3294       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3295       for (p = 0; p < 2; ++p) {
3296         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);
3297       }
3298 #endif
3299       ++newp;
3300       /* Face H: {a, b, f} */
3301       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
3302       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3303       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
3304       orntNew[1] = ornt[3] < 0 ? 0 : -2;
3305       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3306       orntNew[2] = -2;
3307       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3308       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3309 #if 1
3310       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3311       for (p = 0; p < 3; ++p) {
3312         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);
3313       }
3314 #endif
3315       supportNew[0] = (c - cStart)*8 + 1+4;
3316       supportNew[1] = (c - cStart)*8 + 2+4;
3317       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3318 #if 1
3319       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3320       for (p = 0; p < 2; ++p) {
3321         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);
3322       }
3323 #endif
3324       ++newp;
3325     }
3326     /* Hybrid split faces have 4 edges and same cells */
3327     for (f = fMax; f < fEnd; ++f) {
3328       const PetscInt *cone, *ornt, *support;
3329       PetscInt        coneNew[4], orntNew[4];
3330       PetscInt        supportNew[2], size, s, c;
3331 
3332       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3333       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3334       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3335       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3336       for (r = 0; r < 2; ++r) {
3337         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
3338 
3339         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
3340         orntNew[0]   = ornt[0];
3341         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
3342         orntNew[1]   = ornt[1];
3343         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (cone[2+r] - eMax);
3344         orntNew[2+r] = 0;
3345         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd      - eMax) + (f - fMax);
3346         orntNew[3-r] = 0;
3347         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3348         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3349 #if 1
3350         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
3351         for (p = 0; p < 2; ++p) {
3352           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);
3353         }
3354         for (p = 2; p < 4; ++p) {
3355           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);
3356         }
3357 #endif
3358         for (s = 0; s < size; ++s) {
3359           const PetscInt *coneCell, *orntCell, *fornt;
3360           PetscInt        o, of;
3361 
3362           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
3363           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
3364           o = orntCell[0] < 0 ? -1 : 1;
3365           for (c = 2; c < 5; ++c) if (coneCell[c] == f) break;
3366           if (c >= 5) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
3367           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
3368           of = fornt[c-2] < 0 ? -1 : 1;
3369           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetTriEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%3;
3370         }
3371         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3372 #if 1
3373         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
3374         for (p = 0; p < size; ++p) {
3375           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);
3376         }
3377 #endif
3378       }
3379     }
3380     /* Hybrid cell faces have 4 edges and 2 cells */
3381     for (c = cMax; c < cEnd; ++c) {
3382       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3;
3383       const PetscInt *cone, *ornt;
3384       PetscInt        coneNew[4], orntNew[4];
3385       PetscInt        supportNew[2];
3386 
3387       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3388       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3389       for (r = 0; r < 3; ++r) {
3390         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + (r+2)%3;
3391         orntNew[0] = 0;
3392         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + (r+2)%3;
3393         orntNew[1] = 0;
3394         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+(r+2)%3] - fMax);
3395         orntNew[2] = 0;
3396         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+r]       - fMax);
3397         orntNew[3] = 0;
3398         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
3399         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
3400 #if 1
3401         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);
3402         for (p = 0; p < 2; ++p) {
3403           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);
3404         }
3405         for (p = 2; p < 4; ++p) {
3406           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);
3407         }
3408 #endif
3409         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetTriSubface_Static(ornt[0], r);
3410         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + 3;
3411         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
3412 #if 1
3413         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);
3414         for (p = 0; p < 2; ++p) {
3415           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);
3416         }
3417 #endif
3418       }
3419     }
3420     /* Interior split edges have 2 vertices and the same faces as the parent */
3421     for (e = eStart; e < eMax; ++e) {
3422       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
3423 
3424       for (r = 0; r < 2; ++r) {
3425         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
3426         const PetscInt *cone, *ornt, *support;
3427         PetscInt        coneNew[2], coneSize, c, supportSize, s;
3428 
3429         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3430         coneNew[0]       = vStartNew + (cone[0] - vStart);
3431         coneNew[1]       = vStartNew + (cone[1] - vStart);
3432         coneNew[(r+1)%2] = newv;
3433         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3434 #if 1
3435         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3436         for (p = 0; p < 2; ++p) {
3437           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);
3438         }
3439 #endif
3440         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
3441         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3442         for (s = 0; s < supportSize; ++s) {
3443           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3444           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3445           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3446           for (c = 0; c < coneSize; ++c) if (cone[c] == e) break;
3447           if (support[s] < fMax) {
3448             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
3449           } else {
3450             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
3451           }
3452         }
3453         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3454 #if 1
3455         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3456         for (p = 0; p < supportSize; ++p) {
3457           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);
3458         }
3459 #endif
3460       }
3461     }
3462     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
3463     for (f = fStart; f < fMax; ++f) {
3464       const PetscInt *cone, *ornt, *support;
3465       PetscInt        coneSize, supportSize, s;
3466 
3467       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3468       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3469       for (r = 0; r < 3; ++r) {
3470         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
3471         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
3472         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
3473                                     -1, -1,  1,  6,  0,  4,
3474                                      2,  5,  3,  4, -1, -1,
3475                                     -1, -1,  3,  6,  2,  7};
3476 
3477         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3478         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
3479         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
3480         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3481 #if 1
3482         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3483         for (p = 0; p < 2; ++p) {
3484           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);
3485         }
3486 #endif
3487         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
3488         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
3489         for (s = 0; s < supportSize; ++s) {
3490           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3491           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3492           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3493           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
3494           if (support[s] < cMax) {
3495             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
3496             er = GetTetSomethingInverse_Static(ornt[c], r);
3497             if (er == eint[c]) {
3498               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
3499             } else {
3500               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
3501               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
3502             }
3503           } else {
3504             supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (r + 1)%3;
3505           }
3506         }
3507         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3508 #if 1
3509         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3510         for (p = 0; p < intFaces; ++p) {
3511           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);
3512         }
3513 #endif
3514       }
3515     }
3516     /* Interior cell edges have 2 vertices and 4 faces */
3517     for (c = cStart; c < cMax; ++c) {
3518       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3519       const PetscInt *cone, *ornt, *fcone;
3520       PetscInt        coneNew[2], supportNew[4], find;
3521 
3522       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3523       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3524       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
3525       find = GetTriEdge_Static(ornt[0], 0);
3526       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3527       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
3528       find = GetTriEdge_Static(ornt[2], 1);
3529       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3530       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3531 #if 1
3532       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3533       for (p = 0; p < 2; ++p) {
3534         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);
3535       }
3536 #endif
3537       supportNew[0] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 4;
3538       supportNew[1] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 5;
3539       supportNew[2] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 6;
3540       supportNew[3] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 7;
3541       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3542 #if 1
3543       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3544       for (p = 0; p < 4; ++p) {
3545         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);
3546       }
3547 #endif
3548     }
3549     /* Hybrid edges have two vertices and the same faces */
3550     for (e = eMax; e < eEnd; ++e) {
3551       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
3552       const PetscInt *cone, *support, *fcone;
3553       PetscInt        coneNew[2], size, fsize, s;
3554 
3555       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3556       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
3557       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3558       coneNew[0] = vStartNew + (cone[0] - vStart);
3559       coneNew[1] = vStartNew + (cone[1] - vStart);
3560       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3561 #if 1
3562       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3563       for (p = 0; p < 2; ++p) {
3564         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);
3565       }
3566 #endif
3567       for (s = 0; s < size; ++s) {
3568         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
3569         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
3570         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
3571         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
3572         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + c-2;
3573       }
3574       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3575 #if 1
3576       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3577       for (p = 0; p < size; ++p) {
3578         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);
3579       }
3580 #endif
3581     }
3582     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
3583     for (f = fMax; f < fEnd; ++f) {
3584       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
3585       const PetscInt *cone, *support, *ccone, *cornt;
3586       PetscInt        coneNew[2], size, csize, s;
3587 
3588       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3589       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3590       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3591       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
3592       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
3593       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3594 #if 1
3595       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3596       for (p = 0; p < 2; ++p) {
3597         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);
3598       }
3599 #endif
3600       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 0;
3601       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 1;
3602       for (s = 0; s < size; ++s) {
3603         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
3604         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
3605         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
3606         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
3607         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]);
3608         supportRef[2+s*2+0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + c-2;
3609         supportRef[2+s*2+1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (c-1)%3;
3610       }
3611       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3612 #if 1
3613       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3614       for (p = 0; p < 2+size*2; ++p) {
3615         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);
3616       }
3617 #endif
3618     }
3619     /* Interior vertices have identical supports */
3620     for (v = vStart; v < vEnd; ++v) {
3621       const PetscInt  newp = vStartNew + (v - vStart);
3622       const PetscInt *support, *cone;
3623       PetscInt        size, s;
3624 
3625       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
3626       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
3627       for (s = 0; s < size; ++s) {
3628         PetscInt r = 0;
3629 
3630         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3631         if (cone[1] == v) r = 1;
3632         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
3633         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (support[s] - eMax);
3634       }
3635       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3636 #if 1
3637       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3638       for (p = 0; p < size; ++p) {
3639         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);
3640       }
3641 #endif
3642     }
3643     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
3644     for (e = eStart; e < eMax; ++e) {
3645       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
3646       const PetscInt *cone, *support;
3647       PetscInt       *star = NULL, starSize, faceSize = 0, cellSize = 0, coneSize, size, s;
3648 
3649       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
3650       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3651       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
3652       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
3653       for (s = 0; s < size; ++s) {
3654         PetscInt r = 0;
3655 
3656         if (support[s] < fMax) {
3657           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3658           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3659           for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
3660           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
3661           supportRef[2+faceSize+1] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
3662           faceSize += 2;
3663         } else {
3664           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (support[s] - fMax);
3665           ++faceSize;
3666         }
3667       }
3668       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
3669       for (s = 0; s < starSize*2; s += 2) {
3670         const PetscInt *cone, *ornt;
3671         PetscInt        e01, e23;
3672 
3673         if ((star[s] >= cStart) && (star[s] < cMax)) {
3674           /* Check edge 0-1 */
3675           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
3676           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
3677           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
3678           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
3679           /* Check edge 2-3 */
3680           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
3681           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
3682           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
3683           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
3684           if ((e01 == e) || (e23 == e)) {supportRef[2+faceSize+cellSize++] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (star[s] - cStart);}
3685         }
3686       }
3687       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
3688       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3689 #if 1
3690       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3691       for (p = 0; p < 2+faceSize+cellSize; ++p) {
3692         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);
3693       }
3694 #endif
3695     }
3696     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3697     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
3698     break;
3699   case 6:
3700     /* Hex 3D */
3701     /*
3702      Bottom (viewed from top)    Top
3703      1---------2---------2       7---------2---------6
3704      |         |         |       |         |         |
3705      |    B    2    C    |       |    H    2    G    |
3706      |         |         |       |         |         |
3707      3----3----0----1----1       3----3----0----1----1
3708      |         |         |       |         |         |
3709      |    A    0    D    |       |    E    0    F    |
3710      |         |         |       |         |         |
3711      0---------0---------3       4---------0---------5
3712      */
3713     /* All cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
3714     for (c = cStart; c < cEnd; ++c) {
3715       const PetscInt  newp = (c - cStart)*8;
3716       const PetscInt *cone, *ornt;
3717       PetscInt        coneNew[6], orntNew[6];
3718 
3719       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3720       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3721       /* A hex */
3722       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
3723       orntNew[0] = ornt[0];
3724       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
3725       orntNew[1] = 0;
3726       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
3727       orntNew[2] = ornt[2];
3728       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
3729       orntNew[3] = 0;
3730       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
3731       orntNew[4] = 0;
3732       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
3733       orntNew[5] = ornt[5];
3734       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3735       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3736 #if 1
3737       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);
3738       for (p = 0; p < 6; ++p) {
3739         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);
3740       }
3741 #endif
3742       /* B hex */
3743       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
3744       orntNew[0] = ornt[0];
3745       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
3746       orntNew[1] = 0;
3747       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
3748       orntNew[2] = -1;
3749       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
3750       orntNew[3] = ornt[3];
3751       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
3752       orntNew[4] = 0;
3753       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
3754       orntNew[5] = ornt[5];
3755       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3756       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3757 #if 1
3758       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);
3759       for (p = 0; p < 6; ++p) {
3760         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);
3761       }
3762 #endif
3763       /* C hex */
3764       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
3765       orntNew[0] = ornt[0];
3766       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
3767       orntNew[1] = 0;
3768       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
3769       orntNew[2] = -1;
3770       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
3771       orntNew[3] = ornt[3];
3772       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
3773       orntNew[4] = ornt[4];
3774       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
3775       orntNew[5] = -4;
3776       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3777       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3778 #if 1
3779       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);
3780       for (p = 0; p < 6; ++p) {
3781         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);
3782       }
3783 #endif
3784       /* D hex */
3785       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
3786       orntNew[0] = ornt[0];
3787       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
3788       orntNew[1] = 0;
3789       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
3790       orntNew[2] = ornt[2];
3791       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
3792       orntNew[3] = 0;
3793       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
3794       orntNew[4] = ornt[4];
3795       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
3796       orntNew[5] = -4;
3797       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3798       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3799 #if 1
3800       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);
3801       for (p = 0; p < 6; ++p) {
3802         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);
3803       }
3804 #endif
3805       /* E hex */
3806       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
3807       orntNew[0] = -4;
3808       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
3809       orntNew[1] = ornt[1];
3810       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
3811       orntNew[2] = ornt[2];
3812       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
3813       orntNew[3] = 0;
3814       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
3815       orntNew[4] = -1;
3816       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
3817       orntNew[5] = ornt[5];
3818       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
3819       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
3820 #if 1
3821       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);
3822       for (p = 0; p < 6; ++p) {
3823         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);
3824       }
3825 #endif
3826       /* F hex */
3827       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
3828       orntNew[0] = -4;
3829       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
3830       orntNew[1] = ornt[1];
3831       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
3832       orntNew[2] = ornt[2];
3833       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
3834       orntNew[3] = -1;
3835       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
3836       orntNew[4] = ornt[4];
3837       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
3838       orntNew[5] = 1;
3839       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
3840       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
3841 #if 1
3842       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);
3843       for (p = 0; p < 6; ++p) {
3844         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);
3845       }
3846 #endif
3847       /* G hex */
3848       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
3849       orntNew[0] = -4;
3850       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
3851       orntNew[1] = ornt[1];
3852       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
3853       orntNew[2] = 0;
3854       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
3855       orntNew[3] = ornt[3];
3856       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
3857       orntNew[4] = ornt[4];
3858       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
3859       orntNew[5] = -3;
3860       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
3861       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
3862 #if 1
3863       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);
3864       for (p = 0; p < 6; ++p) {
3865         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);
3866       }
3867 #endif
3868       /* H hex */
3869       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
3870       orntNew[0] = -4;
3871       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
3872       orntNew[1] = ornt[1];
3873       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
3874       orntNew[2] = -1;
3875       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
3876       orntNew[3] = ornt[3];
3877       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
3878       orntNew[4] = 3;
3879       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
3880       orntNew[5] = ornt[5];
3881       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
3882       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
3883 #if 1
3884       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);
3885       for (p = 0; p < 6; ++p) {
3886         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);
3887       }
3888 #endif
3889     }
3890     /* Split faces have 4 edges and the same cells as the parent */
3891     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3892     ierr = PetscMalloc1((4 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
3893     for (f = fStart; f < fEnd; ++f) {
3894       for (r = 0; r < 4; ++r) {
3895         /* TODO: This can come from GetFaces_Internal() */
3896         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};
3897         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
3898         const PetscInt *cone, *ornt, *support;
3899         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
3900 
3901         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3902         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3903         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
3904         orntNew[(r+3)%4] = ornt[(r+3)%4];
3905         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
3906         orntNew[(r+0)%4] = ornt[r];
3907         coneNew[(r+1)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
3908         orntNew[(r+1)%4] = 0;
3909         coneNew[(r+2)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + (r+3)%4;
3910         orntNew[(r+2)%4] = -2;
3911         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3912         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3913 #if 1
3914         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3915         for (p = 0; p < 4; ++p) {
3916           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);
3917         }
3918 #endif
3919         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3920         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3921         for (s = 0; s < supportSize; ++s) {
3922           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3923           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3924           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3925           for (c = 0; c < coneSize; ++c) {
3926             if (cone[c] == f) break;
3927           }
3928           supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+GetQuadSubfaceInverse_Static(ornt[c], r)];
3929         }
3930         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3931 #if 1
3932         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3933         for (p = 0; p < supportSize; ++p) {
3934           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);
3935         }
3936 #endif
3937       }
3938     }
3939     /* Interior faces have 4 edges and 2 cells */
3940     for (c = cStart; c < cEnd; ++c) {
3941       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};
3942       const PetscInt *cone, *ornt;
3943       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
3944 
3945       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3946       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3947       /* A-D face */
3948       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 0;
3949       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
3950       orntNew[0] = 0;
3951       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
3952       orntNew[1] = 0;
3953       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
3954       orntNew[2] = -2;
3955       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
3956       orntNew[3] = -2;
3957       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3958       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3959 #if 1
3960       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3961       for (p = 0; p < 4; ++p) {
3962         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);
3963       }
3964 #endif
3965       /* C-D face */
3966       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 1;
3967       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
3968       orntNew[0] = 0;
3969       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
3970       orntNew[1] = 0;
3971       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
3972       orntNew[2] = -2;
3973       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
3974       orntNew[3] = -2;
3975       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3976       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3977 #if 1
3978       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3979       for (p = 0; p < 4; ++p) {
3980         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);
3981       }
3982 #endif
3983       /* B-C face */
3984       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 2;
3985       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
3986       orntNew[0] = -2;
3987       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
3988       orntNew[1] = 0;
3989       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
3990       orntNew[2] = 0;
3991       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
3992       orntNew[3] = -2;
3993       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3994       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3995 #if 1
3996       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3997       for (p = 0; p < 4; ++p) {
3998         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);
3999       }
4000 #endif
4001       /* A-B face */
4002       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 3;
4003       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
4004       orntNew[0] = -2;
4005       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
4006       orntNew[1] = 0;
4007       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
4008       orntNew[2] = 0;
4009       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
4010       orntNew[3] = -2;
4011       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4012       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4013 #if 1
4014       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4015       for (p = 0; p < 4; ++p) {
4016         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);
4017       }
4018 #endif
4019       /* E-F face */
4020       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 4;
4021       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
4022       orntNew[0] = -2;
4023       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
4024       orntNew[1] = -2;
4025       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
4026       orntNew[2] = 0;
4027       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
4028       orntNew[3] = 0;
4029       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4030       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4031 #if 1
4032       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4033       for (p = 0; p < 4; ++p) {
4034         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);
4035       }
4036 #endif
4037       /* F-G face */
4038       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 5;
4039       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
4040       orntNew[0] = -2;
4041       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
4042       orntNew[1] = -2;
4043       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
4044       orntNew[2] = 0;
4045       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
4046       orntNew[3] = 0;
4047       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4048       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4049 #if 1
4050       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4051       for (p = 0; p < 4; ++p) {
4052         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);
4053       }
4054 #endif
4055       /* G-H face */
4056       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 6;
4057       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
4058       orntNew[0] = -2;
4059       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
4060       orntNew[1] = 0;
4061       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
4062       orntNew[2] = 0;
4063       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
4064       orntNew[3] = -2;
4065       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4066       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4067 #if 1
4068       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4069       for (p = 0; p < 4; ++p) {
4070         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);
4071       }
4072 #endif
4073       /* E-H face */
4074       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 7;
4075       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
4076       orntNew[0] = -2;
4077       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
4078       orntNew[1] = -2;
4079       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
4080       orntNew[2] = 0;
4081       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
4082       orntNew[3] = 0;
4083       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4084       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4085 #if 1
4086       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4087       for (p = 0; p < 4; ++p) {
4088         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);
4089       }
4090 #endif
4091       /* A-E face */
4092       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 8;
4093       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
4094       orntNew[0] = 0;
4095       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
4096       orntNew[1] = 0;
4097       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
4098       orntNew[2] = -2;
4099       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
4100       orntNew[3] = -2;
4101       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4102       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4103 #if 1
4104       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4105       for (p = 0; p < 4; ++p) {
4106         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);
4107       }
4108 #endif
4109       /* D-F face */
4110       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 9;
4111       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
4112       orntNew[0] = -2;
4113       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
4114       orntNew[1] = 0;
4115       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
4116       orntNew[2] = 0;
4117       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
4118       orntNew[3] = -2;
4119       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4120       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4121 #if 1
4122       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4123       for (p = 0; p < 4; ++p) {
4124         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);
4125       }
4126 #endif
4127       /* C-G face */
4128       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 10;
4129       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
4130       orntNew[0] = -2;
4131       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
4132       orntNew[1] = -2;
4133       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
4134       orntNew[2] = 0;
4135       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
4136       orntNew[3] = 0;
4137       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4138       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4139 #if 1
4140       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4141       for (p = 0; p < 4; ++p) {
4142         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);
4143       }
4144 #endif
4145       /* B-H face */
4146       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 11;
4147       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
4148       orntNew[0] = 0;
4149       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
4150       orntNew[1] = -2;
4151       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
4152       orntNew[2] = -2;
4153       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
4154       orntNew[3] = 0;
4155       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4156       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4157 #if 1
4158       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4159       for (p = 0; p < 4; ++p) {
4160         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);
4161       }
4162 #endif
4163       for (r = 0; r < 12; ++r) {
4164         newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
4165         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
4166         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
4167         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4168 #if 1
4169         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4170         for (p = 0; p < 2; ++p) {
4171           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);
4172         }
4173 #endif
4174       }
4175     }
4176     /* Split edges have 2 vertices and the same faces as the parent */
4177     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4178     for (e = eStart; e < eEnd; ++e) {
4179       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
4180 
4181       for (r = 0; r < 2; ++r) {
4182         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
4183         const PetscInt *cone, *ornt, *support;
4184         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4185 
4186         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4187         coneNew[0]       = vStartNew + (cone[0] - vStart);
4188         coneNew[1]       = vStartNew + (cone[1] - vStart);
4189         coneNew[(r+1)%2] = newv;
4190         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4191 #if 1
4192         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4193         for (p = 0; p < 2; ++p) {
4194           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);
4195         }
4196 #endif
4197         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
4198         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4199         for (s = 0; s < supportSize; ++s) {
4200           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4201           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4202           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4203           for (c = 0; c < coneSize; ++c) {
4204             if (cone[c] == e) break;
4205           }
4206           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
4207         }
4208         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4209 #if 1
4210         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4211         for (p = 0; p < supportSize; ++p) {
4212           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);
4213         }
4214 #endif
4215       }
4216     }
4217     /* Face edges have 2 vertices and 2+cells faces */
4218     for (f = fStart; f < fEnd; ++f) {
4219       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};
4220       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
4221       const PetscInt *cone, *coneCell, *orntCell, *support;
4222       PetscInt        coneNew[2], coneSize, c, supportSize, s;
4223 
4224       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4225       for (r = 0; r < 4; ++r) {
4226         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
4227 
4228         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
4229         coneNew[1] = newv;
4230         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4231 #if 1
4232         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4233         for (p = 0; p < 2; ++p) {
4234           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);
4235         }
4236 #endif
4237         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4238         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4239         supportRef[0] = fStartNew + (f - fStart)*4 + r;
4240         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
4241         for (s = 0; s < supportSize; ++s) {
4242           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4243           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
4244           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
4245           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
4246           supportRef[2+s] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
4247         }
4248         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4249 #if 1
4250         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4251         for (p = 0; p < 2+supportSize; ++p) {
4252           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);
4253         }
4254 #endif
4255       }
4256     }
4257     /* Cell edges have 2 vertices and 4 faces */
4258     for (c = cStart; c < cEnd; ++c) {
4259       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};
4260       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
4261       const PetscInt *cone;
4262       PetscInt        coneNew[2], supportNew[4];
4263 
4264       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4265       for (r = 0; r < 6; ++r) {
4266         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
4267 
4268         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
4269         coneNew[1] = newv;
4270         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4271 #if 1
4272         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4273         for (p = 0; p < 2; ++p) {
4274           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);
4275         }
4276 #endif
4277         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
4278         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4279 #if 1
4280         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4281         for (p = 0; p < 4; ++p) {
4282           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);
4283         }
4284 #endif
4285       }
4286     }
4287     /* Old vertices have identical supports */
4288     for (v = vStart; v < vEnd; ++v) {
4289       const PetscInt  newp = vStartNew + (v - vStart);
4290       const PetscInt *support, *cone;
4291       PetscInt        size, s;
4292 
4293       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4294       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4295       for (s = 0; s < size; ++s) {
4296         PetscInt r = 0;
4297 
4298         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4299         if (cone[1] == v) r = 1;
4300         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4301       }
4302       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4303 #if 1
4304       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4305       for (p = 0; p < size; ++p) {
4306         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);
4307       }
4308 #endif
4309     }
4310     /* Edge vertices have 2 + faces supports */
4311     for (e = eStart; e < eEnd; ++e) {
4312       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4313       const PetscInt *cone, *support;
4314       PetscInt        size, s;
4315 
4316       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4317       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4318       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4319       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4320       for (s = 0; s < size; ++s) {
4321         PetscInt r;
4322 
4323         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4324         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
4325         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*4 + r;
4326       }
4327       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4328 #if 1
4329       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4330       for (p = 0; p < 2+size; ++p) {
4331         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);
4332       }
4333 #endif
4334     }
4335     /* Face vertices have 4 + cells supports */
4336     for (f = fStart; f < fEnd; ++f) {
4337       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
4338       const PetscInt *cone, *support;
4339       PetscInt        size, s;
4340 
4341       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4342       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4343       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eEnd - eStart)*2 +  (f - fStart)*4 + r;
4344       for (s = 0; s < size; ++s) {
4345         PetscInt r;
4346 
4347         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4348         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
4349         supportRef[4+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (support[s] - cStart)*6 + r;
4350       }
4351       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4352 #if 1
4353       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4354       for (p = 0; p < 4+size; ++p) {
4355         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);
4356       }
4357 #endif
4358     }
4359     /* Cell vertices have 6 supports */
4360     for (c = cStart; c < cEnd; ++c) {
4361       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
4362       PetscInt       supportNew[6];
4363 
4364       for (r = 0; r < 6; ++r) {
4365         supportNew[r] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
4366       }
4367       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4368     }
4369     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4370     break;
4371   case 8:
4372     /* Hybrid Hex 3D */
4373     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
4374     /*
4375      Bottom (viewed from top)    Top
4376      1---------2---------2       7---------2---------6
4377      |         |         |       |         |         |
4378      |    B    2    C    |       |    H    2    G    |
4379      |         |         |       |         |         |
4380      3----3----0----1----1       3----3----0----1----1
4381      |         |         |       |         |         |
4382      |    A    0    D    |       |    E    0    F    |
4383      |         |         |       |         |         |
4384      0---------0---------3       4---------0---------5
4385      */
4386     /* Interior cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
4387     for (c = cStart; c < cMax; ++c) {
4388       const PetscInt  newp = (c - cStart)*8;
4389       const PetscInt *cone, *ornt;
4390       PetscInt        coneNew[6], orntNew[6];
4391 
4392       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4393       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4394       /* A hex */
4395       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
4396       orntNew[0] = ornt[0];
4397       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
4398       orntNew[1] = 0;
4399       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
4400       orntNew[2] = ornt[2];
4401       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
4402       orntNew[3] = 0;
4403       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
4404       orntNew[4] = 0;
4405       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
4406       orntNew[5] = ornt[5];
4407       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4408       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4409 #if 1
4410       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);
4411       for (p = 0; p < 6; ++p) {
4412         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);
4413       }
4414 #endif
4415       /* B hex */
4416       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
4417       orntNew[0] = ornt[0];
4418       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
4419       orntNew[1] = 0;
4420       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
4421       orntNew[2] = -1;
4422       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
4423       orntNew[3] = ornt[3];
4424       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
4425       orntNew[4] = 0;
4426       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
4427       orntNew[5] = ornt[5];
4428       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4429       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4430 #if 1
4431       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);
4432       for (p = 0; p < 6; ++p) {
4433         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);
4434       }
4435 #endif
4436       /* C hex */
4437       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
4438       orntNew[0] = ornt[0];
4439       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
4440       orntNew[1] = 0;
4441       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
4442       orntNew[2] = -1;
4443       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
4444       orntNew[3] = ornt[3];
4445       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
4446       orntNew[4] = ornt[4];
4447       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
4448       orntNew[5] = -4;
4449       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4450       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4451 #if 1
4452       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);
4453       for (p = 0; p < 6; ++p) {
4454         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);
4455       }
4456 #endif
4457       /* D hex */
4458       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
4459       orntNew[0] = ornt[0];
4460       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
4461       orntNew[1] = 0;
4462       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
4463       orntNew[2] = ornt[2];
4464       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
4465       orntNew[3] = 0;
4466       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
4467       orntNew[4] = ornt[4];
4468       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
4469       orntNew[5] = -4;
4470       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4471       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4472 #if 1
4473       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);
4474       for (p = 0; p < 6; ++p) {
4475         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);
4476       }
4477 #endif
4478       /* E hex */
4479       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
4480       orntNew[0] = -4;
4481       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
4482       orntNew[1] = ornt[1];
4483       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
4484       orntNew[2] = ornt[2];
4485       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
4486       orntNew[3] = 0;
4487       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
4488       orntNew[4] = -1;
4489       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
4490       orntNew[5] = ornt[5];
4491       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
4492       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
4493 #if 1
4494       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);
4495       for (p = 0; p < 6; ++p) {
4496         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);
4497       }
4498 #endif
4499       /* F hex */
4500       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
4501       orntNew[0] = -4;
4502       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
4503       orntNew[1] = ornt[1];
4504       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
4505       orntNew[2] = ornt[2];
4506       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4507       orntNew[3] = -1;
4508       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
4509       orntNew[4] = ornt[4];
4510       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
4511       orntNew[5] = 1;
4512       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
4513       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
4514 #if 1
4515       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);
4516       for (p = 0; p < 6; ++p) {
4517         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);
4518       }
4519 #endif
4520       /* G hex */
4521       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
4522       orntNew[0] = -4;
4523       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
4524       orntNew[1] = ornt[1];
4525       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4526       orntNew[2] = 0;
4527       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
4528       orntNew[3] = ornt[3];
4529       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
4530       orntNew[4] = ornt[4];
4531       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
4532       orntNew[5] = -3;
4533       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
4534       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
4535 #if 1
4536       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);
4537       for (p = 0; p < 6; ++p) {
4538         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);
4539       }
4540 #endif
4541       /* H hex */
4542       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
4543       orntNew[0] = -4;
4544       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
4545       orntNew[1] = ornt[1];
4546       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
4547       orntNew[2] = -1;
4548       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
4549       orntNew[3] = ornt[3];
4550       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
4551       orntNew[4] = 3;
4552       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
4553       orntNew[5] = ornt[5];
4554       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
4555       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
4556 #if 1
4557       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);
4558       for (p = 0; p < 6; ++p) {
4559         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);
4560       }
4561 #endif
4562     }
4563     /* Hybrid cells have 6 faces: Front, Back, Sides */
4564     /*
4565      3---------2---------2
4566      |         |         |
4567      |    D    2    C    |
4568      |         |         |
4569      3----3----0----1----1
4570      |         |         |
4571      |    A    0    B    |
4572      |         |         |
4573      0---------0---------1
4574      */
4575     for (c = cMax; c < cEnd; ++c) {
4576       const PetscInt  newp = (cMax - cStart)*8 + (c - cMax)*4;
4577       const PetscInt *cone, *ornt, *fornt;
4578       PetscInt        coneNew[6], orntNew[6];
4579 
4580       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4581       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4582       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
4583       for (r = 0; r < 4; ++r) {
4584         PetscInt subfA = GetQuadSubface_Static(ornt[0], r);
4585         PetscInt edgeA = GetQuadEdge_Static(ornt[0], r);
4586         PetscInt edgeB = (edgeA+3)%4;
4587         if (ornt[0] != ornt[1]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent ordering for matching ends of hybrid cell %d: %d != %d", c, ornt[0], ornt[1]);
4588         coneNew[0]         = fStartNew + (cone[0] - fStart)*4 + subfA;
4589         orntNew[0]         = ornt[0];
4590         coneNew[1]         = fStartNew + (cone[1] - fStart)*4 + subfA;
4591         orntNew[1]         = ornt[0];
4592         coneNew[(r+0)%4+2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[edgeA+2] - fMax)*2 + (fornt[edgeA] < 0 ? 1 : 0);
4593         orntNew[(r+0)%4+2] = ornt[edgeA];
4594         coneNew[(r+1)%4+2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeA;
4595         orntNew[(r+1)%4+2] = 0;
4596         coneNew[(r+2)%4+2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeB;
4597         orntNew[(r+2)%4+2] = -2;
4598         coneNew[(r+3)%4+2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[edgeB+2] - fMax)*2 + (fornt[edgeB] < 0 ? 0 : 1);
4599         orntNew[(r+3)%4+2] = ornt[edgeB];
4600         ierr       = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
4601         ierr       = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
4602 #if 1
4603         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);
4604         for (p = 0; p < 2; ++p) {
4605           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);
4606         }
4607         for (p = 2; p < 6; ++p) {
4608           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);
4609         }
4610 #endif
4611       }
4612     }
4613     /* Interior split faces have 4 edges and the same cells as the parent */
4614     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4615     ierr = PetscMalloc1((4 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
4616     for (f = fStart; f < fMax; ++f) {
4617       for (r = 0; r < 4; ++r) {
4618         /* TODO: This can come from GetFaces_Internal() */
4619         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};
4620         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
4621         const PetscInt *cone, *ornt, *support;
4622         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
4623 
4624         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4625         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4626         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
4627         orntNew[(r+3)%4] = ornt[(r+3)%4];
4628         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
4629         orntNew[(r+0)%4] = ornt[r];
4630         coneNew[(r+1)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
4631         orntNew[(r+1)%4] = 0;
4632         coneNew[(r+2)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + (r+3)%4;
4633         orntNew[(r+2)%4] = -2;
4634         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4635         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4636 #if 1
4637         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4638         for (p = 0; p < 4; ++p) {
4639           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);
4640         }
4641 #endif
4642         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4643         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4644         for (s = 0; s < supportSize; ++s) {
4645           PetscInt subf;
4646           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4647           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4648           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4649           for (c = 0; c < coneSize; ++c) {
4650             if (cone[c] == f) break;
4651           }
4652           subf = GetQuadSubfaceInverse_Static(ornt[c], r);
4653           if (support[s] < cMax) {
4654             supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+subf];
4655           } else {
4656             supportRef[s] = cStartNew + (cMax       - cStart)*8 + (support[s] - cMax)*4 + subf;
4657           }
4658         }
4659         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4660 #if 1
4661         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4662         for (p = 0; p < supportSize; ++p) {
4663           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);
4664         }
4665 #endif
4666       }
4667     }
4668     /* Interior faces have 4 edges and 2 cells */
4669     for (c = cStart; c < cMax; ++c) {
4670       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};
4671       const PetscInt *cone, *ornt;
4672       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
4673 
4674       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4675       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4676       /* A-D face */
4677       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 0;
4678       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
4679       orntNew[0] = 0;
4680       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4681       orntNew[1] = 0;
4682       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4683       orntNew[2] = -2;
4684       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
4685       orntNew[3] = -2;
4686       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4687       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4688 #if 1
4689       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4690       for (p = 0; p < 4; ++p) {
4691         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);
4692       }
4693 #endif
4694       /* C-D face */
4695       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 1;
4696       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
4697       orntNew[0] = 0;
4698       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4699       orntNew[1] = 0;
4700       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4701       orntNew[2] = -2;
4702       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
4703       orntNew[3] = -2;
4704       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4705       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4706 #if 1
4707       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4708       for (p = 0; p < 4; ++p) {
4709         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);
4710       }
4711 #endif
4712       /* B-C face */
4713       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 2;
4714       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
4715       orntNew[0] = -2;
4716       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
4717       orntNew[1] = 0;
4718       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4719       orntNew[2] = 0;
4720       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4721       orntNew[3] = -2;
4722       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4723       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4724 #if 1
4725       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4726       for (p = 0; p < 4; ++p) {
4727         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);
4728       }
4729 #endif
4730       /* A-B face */
4731       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 3;
4732       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
4733       orntNew[0] = -2;
4734       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
4735       orntNew[1] = 0;
4736       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4737       orntNew[2] = 0;
4738       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4739       orntNew[3] = -2;
4740       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4741       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4742 #if 1
4743       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4744       for (p = 0; p < 4; ++p) {
4745         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);
4746       }
4747 #endif
4748       /* E-F face */
4749       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 4;
4750       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4751       orntNew[0] = -2;
4752       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
4753       orntNew[1] = -2;
4754       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
4755       orntNew[2] = 0;
4756       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4757       orntNew[3] = 0;
4758       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4759       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4760 #if 1
4761       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4762       for (p = 0; p < 4; ++p) {
4763         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);
4764       }
4765 #endif
4766       /* F-G face */
4767       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 5;
4768       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4769       orntNew[0] = -2;
4770       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
4771       orntNew[1] = -2;
4772       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
4773       orntNew[2] = 0;
4774       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4775       orntNew[3] = 0;
4776       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4777       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4778 #if 1
4779       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4780       for (p = 0; p < 4; ++p) {
4781         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);
4782       }
4783 #endif
4784       /* G-H face */
4785       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 6;
4786       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
4787       orntNew[0] = -2;
4788       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
4789       orntNew[1] = 0;
4790       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4791       orntNew[2] = 0;
4792       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4793       orntNew[3] = -2;
4794       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4795       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4796 #if 1
4797       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4798       for (p = 0; p < 4; ++p) {
4799         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);
4800       }
4801 #endif
4802       /* E-H face */
4803       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 7;
4804       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4805       orntNew[0] = -2;
4806       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
4807       orntNew[1] = -2;
4808       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
4809       orntNew[2] = 0;
4810       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4811       orntNew[3] = 0;
4812       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4813       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4814 #if 1
4815       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4816       for (p = 0; p < 4; ++p) {
4817         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);
4818       }
4819 #endif
4820       /* A-E face */
4821       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 8;
4822       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
4823       orntNew[0] = 0;
4824       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4825       orntNew[1] = 0;
4826       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4827       orntNew[2] = -2;
4828       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
4829       orntNew[3] = -2;
4830       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4831       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4832 #if 1
4833       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4834       for (p = 0; p < 4; ++p) {
4835         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);
4836       }
4837 #endif
4838       /* D-F face */
4839       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 9;
4840       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
4841       orntNew[0] = -2;
4842       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
4843       orntNew[1] = 0;
4844       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4845       orntNew[2] = 0;
4846       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4847       orntNew[3] = -2;
4848       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4849       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4850 #if 1
4851       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4852       for (p = 0; p < 4; ++p) {
4853         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);
4854       }
4855 #endif
4856       /* C-G face */
4857       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 10;
4858       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4859       orntNew[0] = -2;
4860       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
4861       orntNew[1] = -2;
4862       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
4863       orntNew[2] = 0;
4864       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4865       orntNew[3] = 0;
4866       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4867       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4868 #if 1
4869       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4870       for (p = 0; p < 4; ++p) {
4871         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);
4872       }
4873 #endif
4874       /* B-H face */
4875       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 11;
4876       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4877       orntNew[0] = 0;
4878       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4879       orntNew[1] = -2;
4880       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
4881       orntNew[2] = -2;
4882       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
4883       orntNew[3] = 0;
4884       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4885       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4886 #if 1
4887       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4888       for (p = 0; p < 4; ++p) {
4889         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);
4890       }
4891 #endif
4892       for (r = 0; r < 12; ++r) {
4893         newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
4894         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
4895         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
4896         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4897 #if 1
4898         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4899         for (p = 0; p < 2; ++p) {
4900           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);
4901         }
4902 #endif
4903       }
4904     }
4905     /* Hybrid split faces have 4 edges and same cells */
4906     for (f = fMax; f < fEnd; ++f) {
4907       const PetscInt *cone, *ornt, *support;
4908       PetscInt        coneNew[4], orntNew[4];
4909       PetscInt        supportNew[2], size, s, c;
4910 
4911       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4912       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4913       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4914       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4915       for (r = 0; r < 2; ++r) {
4916         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
4917 
4918         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
4919         orntNew[0]   = ornt[0];
4920         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
4921         orntNew[1]   = ornt[1];
4922         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (cone[2+r] - eMax);
4923         orntNew[2+r] = 0;
4924         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd      - eMax) + (f - fMax);
4925         orntNew[3-r] = 0;
4926         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4927         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4928 #if 1
4929         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
4930         for (p = 0; p < 2; ++p) {
4931           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);
4932         }
4933         for (p = 2; p < 4; ++p) {
4934           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);
4935         }
4936 #endif
4937         for (s = 0; s < size; ++s) {
4938           const PetscInt *coneCell, *orntCell, *fornt;
4939 
4940           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
4941           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
4942           for (c = 2; c < 6; ++c) if (coneCell[c] == f) break;
4943           if (c >= 6) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
4944           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
4945           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetQuadEdgeInverse_Static(orntCell[0], c-2) + (fornt[c-2] < 0 ? 1-r : r))%4;
4946         }
4947         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4948 #if 1
4949         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
4950         for (p = 0; p < size; ++p) {
4951           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);
4952         }
4953 #endif
4954       }
4955     }
4956     /* Hybrid cell faces have 4 edges and 2 cells */
4957     for (c = cMax; c < cEnd; ++c) {
4958       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4;
4959       const PetscInt *cone, *ornt;
4960       PetscInt        coneNew[4], orntNew[4];
4961       PetscInt        supportNew[2];
4962 
4963       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4964       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4965       for (r = 0; r < 4; ++r) {
4966         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], r);
4967         orntNew[0] = 0;
4968         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], r);
4969         orntNew[1] = 0;
4970         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+GetQuadEdge_Static(ornt[0], r)] - fMax);
4971         orntNew[2] = 0;
4972         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd                                   - fMax) + (c - cMax);
4973         orntNew[3] = 0;
4974         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
4975         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
4976 #if 1
4977         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);
4978         for (p = 0; p < 2; ++p) {
4979           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);
4980         }
4981         for (p = 2; p < 4; ++p) {
4982           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);
4983         }
4984 #endif
4985         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], r);
4986         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], (r+1)%4);
4987         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
4988 #if 1
4989         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);
4990         for (p = 0; p < 2; ++p) {
4991           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);
4992         }
4993 #endif
4994       }
4995     }
4996     /* Interior split edges have 2 vertices and the same faces as the parent */
4997     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4998     for (e = eStart; e < eMax; ++e) {
4999       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
5000 
5001       for (r = 0; r < 2; ++r) {
5002         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
5003         const PetscInt *cone, *ornt, *support;
5004         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5005 
5006         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
5007         coneNew[0]       = vStartNew + (cone[0] - vStart);
5008         coneNew[1]       = vStartNew + (cone[1] - vStart);
5009         coneNew[(r+1)%2] = newv;
5010         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5011 #if 1
5012         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5013         for (p = 0; p < 2; ++p) {
5014           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);
5015         }
5016 #endif
5017         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
5018         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5019         for (s = 0; s < supportSize; ++s) {
5020           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5021           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5022           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5023           for (c = 0; c < coneSize; ++c) {
5024             if (cone[c] == e) break;
5025           }
5026           if (support[s] < fMax) {
5027             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%4;
5028           } else {
5029             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
5030           }
5031         }
5032         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5033 #if 1
5034         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5035         for (p = 0; p < supportSize; ++p) {
5036           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);
5037         }
5038 #endif
5039       }
5040     }
5041     /* Interior face edges have 2 vertices and 2+cells faces */
5042     for (f = fStart; f < fMax; ++f) {
5043       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};
5044       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
5045       const PetscInt *cone, *coneCell, *orntCell, *support;
5046       PetscInt        coneNew[2], coneSize, c, supportSize, s;
5047 
5048       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5049       for (r = 0; r < 4; ++r) {
5050         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
5051 
5052         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
5053         coneNew[1] = newv;
5054         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5055 #if 1
5056         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5057         for (p = 0; p < 2; ++p) {
5058           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);
5059         }
5060 #endif
5061         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5062         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5063         supportRef[0] = fStartNew + (f - fStart)*4 + r;
5064         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
5065         for (s = 0; s < supportSize; ++s) {
5066           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5067           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
5068           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
5069           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
5070           if (support[s] < cMax) {
5071             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
5072           } else {
5073             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + GetQuadEdgeInverse_Static(orntCell[c], r);
5074           }
5075         }
5076         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5077 #if 1
5078         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5079         for (p = 0; p < 2+supportSize; ++p) {
5080           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);
5081         }
5082 #endif
5083       }
5084     }
5085     /* Interior cell edges have 2 vertices and 4 faces */
5086     for (c = cStart; c < cMax; ++c) {
5087       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};
5088       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
5089       const PetscInt *cone;
5090       PetscInt        coneNew[2], supportNew[4];
5091 
5092       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5093       for (r = 0; r < 6; ++r) {
5094         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
5095 
5096         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
5097         coneNew[1] = newv;
5098         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5099 #if 1
5100         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5101         for (p = 0; p < 2; ++p) {
5102           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);
5103         }
5104 #endif
5105         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
5106         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5107 #if 1
5108         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5109         for (p = 0; p < 4; ++p) {
5110           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);
5111         }
5112 #endif
5113       }
5114     }
5115     /* Hybrid edges have two vertices and the same faces */
5116     for (e = eMax; e < eEnd; ++e) {
5117       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
5118       const PetscInt *cone, *support, *fcone;
5119       PetscInt        coneNew[2], size, fsize, s;
5120 
5121       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
5122       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
5123       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5124       coneNew[0] = vStartNew + (cone[0] - vStart);
5125       coneNew[1] = vStartNew + (cone[1] - vStart);
5126       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5127 #if 1
5128       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5129       for (p = 0; p < 2; ++p) {
5130         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);
5131       }
5132 #endif
5133       for (s = 0; s < size; ++s) {
5134         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
5135         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
5136         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
5137         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
5138         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + c-2;
5139       }
5140       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5141 #if 1
5142       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5143       for (p = 0; p < size; ++p) {
5144         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);
5145       }
5146 #endif
5147     }
5148     /* Hybrid face edges have 2 vertices and 2+cells faces */
5149     for (f = fMax; f < fEnd; ++f) {
5150       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
5151       const PetscInt *cone, *support, *ccone, *cornt;
5152       PetscInt        coneNew[2], size, csize, s;
5153 
5154       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5155       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5156       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5157       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
5158       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
5159       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5160 #if 1
5161       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5162       for (p = 0; p < 2; ++p) {
5163         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);
5164       }
5165 #endif
5166       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 0;
5167       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 1;
5168       for (s = 0; s < size; ++s) {
5169         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
5170         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
5171         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
5172         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
5173         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]);
5174         supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + GetQuadSubfaceInverse_Static(cornt[0], c-2);
5175       }
5176       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5177 #if 1
5178       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5179       for (p = 0; p < 2+size; ++p) {
5180         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);
5181       }
5182 #endif
5183     }
5184     /* Hybrid cell edges have 2 vertices and 4 faces */
5185     for (c = cMax; c < cEnd; ++c) {
5186       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
5187       const PetscInt *cone, *support;
5188       PetscInt        coneNew[2], size;
5189 
5190       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5191       ierr = DMPlexGetSupportSize(dm, c, &size);CHKERRQ(ierr);
5192       ierr = DMPlexGetSupport(dm, c, &support);CHKERRQ(ierr);
5193       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
5194       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
5195       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5196 #if 1
5197       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5198       for (p = 0; p < 2; ++p) {
5199         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);
5200       }
5201 #endif
5202       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 0;
5203       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 1;
5204       supportRef[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 2;
5205       supportRef[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 3;
5206       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5207 #if 1
5208       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5209       for (p = 0; p < 4; ++p) {
5210         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);
5211       }
5212 #endif
5213     }
5214     /* Interior vertices have identical supports */
5215     for (v = vStart; v < vEnd; ++v) {
5216       const PetscInt  newp = vStartNew + (v - vStart);
5217       const PetscInt *support, *cone;
5218       PetscInt        size, s;
5219 
5220       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5221       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5222       for (s = 0; s < size; ++s) {
5223         PetscInt r = 0;
5224 
5225         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5226         if (cone[1] == v) r = 1;
5227         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
5228         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (support[s] - eMax);
5229       }
5230       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5231 #if 1
5232       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5233       for (p = 0; p < size; ++p) {
5234         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);
5235       }
5236 #endif
5237     }
5238     /* Interior edge vertices have 2 + faces supports */
5239     for (e = eStart; e < eMax; ++e) {
5240       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
5241       const PetscInt *cone, *support;
5242       PetscInt        size, s;
5243 
5244       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
5245       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5246       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
5247       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
5248       for (s = 0; s < size; ++s) {
5249         PetscInt r;
5250 
5251         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5252         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
5253         if (support[s] < fMax) {
5254           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*4 + r;
5255         } else {
5256           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (support[s] - fMax);
5257         }
5258       }
5259       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5260 #if 1
5261       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5262       for (p = 0; p < 2+size; ++p) {
5263         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);
5264       }
5265 #endif
5266     }
5267     /* Interior face vertices have 4 + cells supports */
5268     for (f = fStart; f < fMax; ++f) {
5269       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
5270       const PetscInt *cone, *support;
5271       PetscInt        size, s;
5272 
5273       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5274       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5275       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eMax - eStart)*2 +  (f - fStart)*4 + r;
5276       for (s = 0; s < size; ++s) {
5277         PetscInt r;
5278 
5279         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5280         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
5281         if (support[s] < cMax) {
5282           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (support[s] - cStart)*6 + r;
5283         } else {
5284           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax       - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (support[s] - cMax);
5285         }
5286       }
5287       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5288 #if 1
5289       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5290       for (p = 0; p < 4+size; ++p) {
5291         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);
5292       }
5293 #endif
5294     }
5295     /* Cell vertices have 6 supports */
5296     for (c = cStart; c < cMax; ++c) {
5297       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
5298       PetscInt       supportNew[6];
5299 
5300       for (r = 0; r < 6; ++r) {
5301         supportNew[r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
5302       }
5303       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5304     }
5305     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5306     break;
5307   default:
5308     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5309   }
5310   PetscFunctionReturn(0);
5311 }
5312 
5313 #undef __FUNCT__
5314 #define __FUNCT__ "CellRefinerSetCoordinates"
5315 static PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5316 {
5317   PetscSection   coordSection, coordSectionNew;
5318   Vec            coordinates, coordinatesNew;
5319   PetscScalar   *coords, *coordsNew;
5320   const PetscInt numVertices = depthSize ? depthSize[0] : 0;
5321   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, cMax, c, vStart, vStartNew, vEnd, v, eStart, eEnd, eMax, e, fStart, fEnd, fMax, f;
5322   PetscErrorCode ierr;
5323 
5324   PetscFunctionBegin;
5325   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5326   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5327   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5328   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5329   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5330   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5331   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, NULL);CHKERRQ(ierr);
5332   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);}
5333   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
5334   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5335   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
5336   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
5337   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
5338   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+numVertices);CHKERRQ(ierr);
5339   if (cMax < 0) cMax = cEnd;
5340   if (fMax < 0) fMax = fEnd;
5341   if (eMax < 0) eMax = eEnd;
5342   /* All vertices have the dim coordinates */
5343   for (v = vStartNew; v < vStartNew+numVertices; ++v) {
5344     ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
5345     ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
5346   }
5347   ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
5348   ierr = DMSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
5349   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5350   ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
5351   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);CHKERRQ(ierr);
5352   ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
5353   ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
5354   ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
5355   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
5356   ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5357   switch (refiner) {
5358   case 0: break;
5359   case 6: /* Hex 3D */
5360   case 8: /* Hybrid Hex 3D */
5361     /* Face vertices have the average of corner coordinates */
5362     for (f = fStart; f < fMax; ++f) {
5363       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
5364       PetscInt      *cone = NULL;
5365       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
5366 
5367       ierr = DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5368       for (p = 0; p < closureSize*2; p += 2) {
5369         const PetscInt point = cone[p];
5370         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
5371       }
5372       for (v = 0; v < coneSize; ++v) {
5373         ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
5374       }
5375       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5376       for (d = 0; d < dim; ++d) {
5377         coordsNew[offnew+d] = 0.0;
5378         for (v = 0; v < coneSize; ++v) coordsNew[offnew+d] += coords[off[v]+d];
5379         coordsNew[offnew+d] /= coneSize;
5380       }
5381       ierr = DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5382     }
5383   case 2: /* Hex 2D */
5384   case 4: /* Hybrid Hex 2D */
5385     /* Cell vertices have the average of corner coordinates */
5386     for (c = cStart; c < cMax; ++c) {
5387       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (c - cStart) + (dim > 2 ? (fMax - fStart) : 0);
5388       PetscInt      *cone = NULL;
5389       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
5390 
5391       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5392       for (p = 0; p < closureSize*2; p += 2) {
5393         const PetscInt point = cone[p];
5394         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
5395       }
5396       for (v = 0; v < coneSize; ++v) {
5397         ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
5398       }
5399       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5400       for (d = 0; d < dim; ++d) {
5401         coordsNew[offnew+d] = 0.0;
5402         for (v = 0; v < coneSize; ++v) coordsNew[offnew+d] += coords[off[v]+d];
5403         coordsNew[offnew+d] /= coneSize;
5404       }
5405       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5406     }
5407   case 1: /* Simplicial 2D */
5408   case 3: /* Hybrid Simplicial 2D */
5409   case 5: /* Simplicial 3D */
5410   case 7: /* Hybrid Simplicial 3D */
5411     /* Edge vertices have the average of endpoint coordinates */
5412     for (e = eStart; e < eMax; ++e) {
5413       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
5414       const PetscInt *cone;
5415       PetscInt        coneSize, offA, offB, offnew, d;
5416 
5417       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
5418       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
5419       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
5420       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
5421       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
5422       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5423       for (d = 0; d < dim; ++d) {
5424         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
5425       }
5426     }
5427     /* Old vertices have the same coordinates */
5428     for (v = vStart; v < vEnd; ++v) {
5429       const PetscInt newv = vStartNew + (v - vStart);
5430       PetscInt       off, offnew, d;
5431 
5432       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5433       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5434       for (d = 0; d < dim; ++d) {
5435         coordsNew[offnew+d] = coords[off+d];
5436       }
5437     }
5438     break;
5439   default:
5440     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5441   }
5442   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
5443   ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5444   ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
5445   ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
5446   ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
5447   PetscFunctionReturn(0);
5448 }
5449 
5450 #undef __FUNCT__
5451 #define __FUNCT__ "DMPlexCreateProcessSF"
5452 static PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
5453 {
5454   PetscInt           numRoots, numLeaves, l;
5455   const PetscInt    *localPoints;
5456   const PetscSFNode *remotePoints;
5457   PetscInt          *localPointsNew;
5458   PetscSFNode       *remotePointsNew;
5459   PetscInt          *ranks, *ranksNew;
5460   PetscErrorCode     ierr;
5461 
5462   PetscFunctionBegin;
5463   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5464   ierr = PetscMalloc1(numLeaves, &ranks);CHKERRQ(ierr);
5465   for (l = 0; l < numLeaves; ++l) {
5466     ranks[l] = remotePoints[l].rank;
5467   }
5468   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
5469   ierr = PetscMalloc1(numLeaves,    &ranksNew);CHKERRQ(ierr);
5470   ierr = PetscMalloc1(numLeaves,    &localPointsNew);CHKERRQ(ierr);
5471   ierr = PetscMalloc1(numLeaves, &remotePointsNew);CHKERRQ(ierr);
5472   for (l = 0; l < numLeaves; ++l) {
5473     ranksNew[l]              = ranks[l];
5474     localPointsNew[l]        = l;
5475     remotePointsNew[l].index = 0;
5476     remotePointsNew[l].rank  = ranksNew[l];
5477   }
5478   ierr = PetscFree(ranks);CHKERRQ(ierr);
5479   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
5480   ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
5481   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
5482   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
5483   PetscFunctionReturn(0);
5484 }
5485 
5486 #undef __FUNCT__
5487 #define __FUNCT__ "CellRefinerCreateSF"
5488 static PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5489 {
5490   PetscSF            sf, sfNew, sfProcess;
5491   IS                 processRanks;
5492   MPI_Datatype       depthType;
5493   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
5494   const PetscInt    *localPoints, *neighbors;
5495   const PetscSFNode *remotePoints;
5496   PetscInt          *localPointsNew;
5497   PetscSFNode       *remotePointsNew;
5498   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
5499   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r, n;
5500   PetscInt           cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
5501   PetscErrorCode     ierr;
5502 
5503   PetscFunctionBegin;
5504   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
5505   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5506   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5507   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5508   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5509   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5510   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5511   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
5512   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
5513   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
5514   /* Caculate size of new SF */
5515   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5516   if (numRoots < 0) PetscFunctionReturn(0);
5517   for (l = 0; l < numLeaves; ++l) {
5518     const PetscInt p = localPoints[l];
5519 
5520     switch (refiner) {
5521     case 1:
5522       /* Simplicial 2D */
5523       if ((p >= vStart) && (p < vEnd)) {
5524         /* Old vertices stay the same */
5525         ++numLeavesNew;
5526       } else if ((p >= fStart) && (p < fEnd)) {
5527         /* Old faces add new faces and vertex */
5528         numLeavesNew += 2 + 1;
5529       } else if ((p >= cStart) && (p < cEnd)) {
5530         /* Old cells add new cells and interior faces */
5531         numLeavesNew += 4 + 3;
5532       }
5533       break;
5534     case 3:
5535       /* Hybrid Simplicial 2D */
5536       if ((p >= vStart) && (p < vEnd)) {
5537         /* Interior vertices stay the same */
5538         ++numLeavesNew;
5539       } else if ((p >= fStart) && (p < fMax)) {
5540         /* Interior faces add new faces and vertex */
5541         numLeavesNew += 2 + 1;
5542       } else if ((p >= fMax) && (p < fEnd)) {
5543         /* Hybrid faces stay the same */
5544         ++numLeavesNew;
5545       } else if ((p >= cStart) && (p < cMax)) {
5546         /* Interior cells add new cells and interior faces */
5547         numLeavesNew += 4 + 3;
5548       } else if ((p >= cMax) && (p < cEnd)) {
5549         /* Hybrid cells add new cells and hybrid face */
5550         numLeavesNew += 2 + 1;
5551       }
5552       break;
5553     case 2:
5554       /* Hex 2D */
5555       if ((p >= vStart) && (p < vEnd)) {
5556         /* Old vertices stay the same */
5557         ++numLeavesNew;
5558       } else if ((p >= fStart) && (p < fEnd)) {
5559         /* Old faces add new faces and vertex */
5560         numLeavesNew += 2 + 1;
5561       } else if ((p >= cStart) && (p < cEnd)) {
5562         /* Old cells add new cells, interior faces, and vertex */
5563         numLeavesNew += 4 + 4 + 1;
5564       }
5565       break;
5566     case 4:
5567       /* Hybrid Hex 2D */
5568       if ((p >= vStart) && (p < vEnd)) {
5569         /* Interior vertices stay the same */
5570         ++numLeavesNew;
5571       } else if ((p >= fStart) && (p < fMax)) {
5572         /* Interior faces add new faces and vertex */
5573         numLeavesNew += 2 + 1;
5574       } else if ((p >= fMax) && (p < fEnd)) {
5575         /* Hybrid faces stay the same */
5576         ++numLeavesNew;
5577       } else if ((p >= cStart) && (p < cMax)) {
5578         /* Interior cells add new cells, interior faces, and vertex */
5579         numLeavesNew += 4 + 4 + 1;
5580       } else if ((p >= cMax) && (p < cEnd)) {
5581         /* Hybrid cells add new cells and hybrid face */
5582         numLeavesNew += 2 + 1;
5583       }
5584       break;
5585     case 5:
5586       /* Simplicial 3D */
5587       if ((p >= vStart) && (p < vEnd)) {
5588         /* Old vertices stay the same */
5589         ++numLeavesNew;
5590       } else if ((p >= eStart) && (p < eEnd)) {
5591         /* Old edges add new edges and vertex */
5592         numLeavesNew += 2 + 1;
5593       } else if ((p >= fStart) && (p < fEnd)) {
5594         /* Old faces add new faces and face edges */
5595         numLeavesNew += 4 + 3;
5596       } else if ((p >= cStart) && (p < cEnd)) {
5597         /* Old cells add new cells and interior faces and edges */
5598         numLeavesNew += 8 + 8 + 1;
5599       }
5600       break;
5601     case 7:
5602       /* Hybrid Simplicial 3D */
5603       if ((p >= vStart) && (p < vEnd)) {
5604         /* Interior vertices stay the same */
5605         ++numLeavesNew;
5606       } else if ((p >= eStart) && (p < eMax)) {
5607         /* Interior edges add new edges and vertex */
5608         numLeavesNew += 2 + 1;
5609       } else if ((p >= eMax) && (p < eEnd)) {
5610         /* Hybrid edges stay the same */
5611         ++numLeavesNew;
5612       } else if ((p >= fStart) && (p < fMax)) {
5613         /* Interior faces add new faces and edges */
5614         numLeavesNew += 4 + 3;
5615       } else if ((p >= fMax) && (p < fEnd)) {
5616         /* Hybrid faces add new faces and edges */
5617         numLeavesNew += 2 + 1;
5618       } else if ((p >= cStart) && (p < cMax)) {
5619         /* Interior cells add new cells, faces, and edges */
5620         numLeavesNew += 8 + 8 + 1;
5621       } else if ((p >= cMax) && (p < cEnd)) {
5622         /* Hybrid cells add new cells and faces */
5623         numLeavesNew += 4 + 3;
5624       }
5625       break;
5626     case 6:
5627       /* Hex 3D */
5628       if ((p >= vStart) && (p < vEnd)) {
5629         /* Old vertices stay the same */
5630         ++numLeavesNew;
5631       } else if ((p >= eStart) && (p < eEnd)) {
5632         /* Old edges add new edges, and vertex */
5633         numLeavesNew += 2 + 1;
5634       } else if ((p >= fStart) && (p < fEnd)) {
5635         /* Old faces add new faces, edges, and vertex */
5636         numLeavesNew += 4 + 4 + 1;
5637       } else if ((p >= cStart) && (p < cEnd)) {
5638         /* Old cells add new cells, faces, edges, and vertex */
5639         numLeavesNew += 8 + 12 + 6 + 1;
5640       }
5641       break;
5642     case 8:
5643       /* Hybrid Hex 3D */
5644       if ((p >= vStart) && (p < vEnd)) {
5645         /* Old vertices stay the same */
5646         ++numLeavesNew;
5647       } else if ((p >= eStart) && (p < eMax)) {
5648         /* Interior edges add new edges, and vertex */
5649         numLeavesNew += 2 + 1;
5650       } else if ((p >= eMax) && (p < eEnd)) {
5651         /* Hybrid edges stay the same */
5652         ++numLeavesNew;
5653       } else if ((p >= fStart) && (p < fMax)) {
5654         /* Interior faces add new faces, edges, and vertex */
5655         numLeavesNew += 4 + 4 + 1;
5656       } else if ((p >= fMax) && (p < fEnd)) {
5657         /* Hybrid faces add new faces and edges */
5658         numLeavesNew += 2 + 1;
5659       } else if ((p >= cStart) && (p < cMax)) {
5660         /* Interior cells add new cells, faces, edges, and vertex */
5661         numLeavesNew += 8 + 12 + 6 + 1;
5662       } else if ((p >= cStart) && (p < cEnd)) {
5663         /* Hybrid cells add new cells, faces, and edges */
5664         numLeavesNew += 4 + 4 + 1;
5665       }
5666       break;
5667     default:
5668       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5669     }
5670   }
5671   /* Communicate depthSizes for each remote rank */
5672   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
5673   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
5674   ierr = PetscMalloc5((depth+1)*numNeighbors,&rdepthSize,numNeighbors,&rvStartNew,numNeighbors,&reStartNew,numNeighbors,&rfStartNew,numNeighbors,&rcStartNew);CHKERRQ(ierr);
5675   ierr = PetscMalloc7(depth+1,&depthSizeOld,(depth+1)*numNeighbors,&rdepthSizeOld,(depth+1)*numNeighbors,&rdepthMaxOld,numNeighbors,&rvStart,numNeighbors,&reStart,numNeighbors,&rfStart,numNeighbors,&rcStart);CHKERRQ(ierr);
5676   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
5677   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
5678   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5679   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5680   for (n = 0; n < numNeighbors; ++n) {
5681     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
5682   }
5683   depthSizeOld[depth]   = cMax;
5684   depthSizeOld[0]       = vMax;
5685   depthSizeOld[depth-1] = fMax;
5686   depthSizeOld[1]       = eMax;
5687 
5688   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5689   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5690 
5691   depthSizeOld[depth]   = cEnd - cStart;
5692   depthSizeOld[0]       = vEnd - vStart;
5693   depthSizeOld[depth-1] = fEnd - fStart;
5694   depthSizeOld[1]       = eEnd - eStart;
5695 
5696   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5697   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5698   for (n = 0; n < numNeighbors; ++n) {
5699     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
5700   }
5701   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
5702   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
5703   /* Calculate new point SF */
5704   ierr = PetscMalloc1(numLeavesNew,    &localPointsNew);CHKERRQ(ierr);
5705   ierr = PetscMalloc1(numLeavesNew, &remotePointsNew);CHKERRQ(ierr);
5706   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
5707   for (l = 0, m = 0; l < numLeaves; ++l) {
5708     PetscInt    p     = localPoints[l];
5709     PetscInt    rp    = remotePoints[l].index, n;
5710     PetscMPIInt rrank = remotePoints[l].rank;
5711 
5712     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
5713     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
5714     switch (refiner) {
5715     case 1:
5716       /* Simplicial 2D */
5717       if ((p >= vStart) && (p < vEnd)) {
5718         /* Old vertices stay the same */
5719         localPointsNew[m]        = vStartNew     + (p  - vStart);
5720         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5721         remotePointsNew[m].rank  = rrank;
5722         ++m;
5723       } else if ((p >= fStart) && (p < fEnd)) {
5724         /* Old faces add new faces and vertex */
5725         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5726         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5727         remotePointsNew[m].rank  = rrank;
5728         ++m;
5729         for (r = 0; r < 2; ++r, ++m) {
5730           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5731           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5732           remotePointsNew[m].rank  = rrank;
5733         }
5734       } else if ((p >= cStart) && (p < cEnd)) {
5735         /* Old cells add new cells and interior faces */
5736         for (r = 0; r < 4; ++r, ++m) {
5737           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5738           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5739           remotePointsNew[m].rank  = rrank;
5740         }
5741         for (r = 0; r < 3; ++r, ++m) {
5742           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
5743           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
5744           remotePointsNew[m].rank  = rrank;
5745         }
5746       }
5747       break;
5748     case 2:
5749       /* Hex 2D */
5750       if ((p >= vStart) && (p < vEnd)) {
5751         /* Old vertices stay the same */
5752         localPointsNew[m]        = vStartNew     + (p  - vStart);
5753         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5754         remotePointsNew[m].rank  = rrank;
5755         ++m;
5756       } else if ((p >= fStart) && (p < fEnd)) {
5757         /* Old faces add new faces and vertex */
5758         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5759         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5760         remotePointsNew[m].rank  = rrank;
5761         ++m;
5762         for (r = 0; r < 2; ++r, ++m) {
5763           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5764           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5765           remotePointsNew[m].rank  = rrank;
5766         }
5767       } else if ((p >= cStart) && (p < cEnd)) {
5768         /* Old cells add new cells, interior faces, and vertex */
5769         for (r = 0; r < 4; ++r, ++m) {
5770           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5771           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5772           remotePointsNew[m].rank  = rrank;
5773         }
5774         for (r = 0; r < 4; ++r, ++m) {
5775           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
5776           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
5777           remotePointsNew[m].rank  = rrank;
5778         }
5779         for (r = 0; r < 1; ++r, ++m) {
5780           localPointsNew[m]        = vStartNew     + (vEnd - vStart)               + (fEnd - fStart)                    + (p  - cStart)     + r;
5781           remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0]  + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]) + r;
5782           remotePointsNew[m].rank  = rrank;
5783         }
5784       }
5785       break;
5786     case 3:
5787       /* Hybrid simplicial 2D */
5788       if ((p >= vStart) && (p < vEnd)) {
5789         /* Old vertices stay the same */
5790         localPointsNew[m]        = vStartNew     + (p  - vStart);
5791         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5792         remotePointsNew[m].rank  = rrank;
5793         ++m;
5794       } else if ((p >= fStart) && (p < fMax)) {
5795         /* Old interior faces add new faces and vertex */
5796         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5797         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5798         remotePointsNew[m].rank  = rrank;
5799         ++m;
5800         for (r = 0; r < 2; ++r, ++m) {
5801           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5802           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5803           remotePointsNew[m].rank  = rrank;
5804         }
5805       } else if ((p >= fMax) && (p < fEnd)) {
5806         /* Old hybrid faces stay the same */
5807         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
5808         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
5809         remotePointsNew[m].rank  = rrank;
5810         ++m;
5811       } else if ((p >= cStart) && (p < cMax)) {
5812         /* Old interior cells add new cells and interior faces */
5813         for (r = 0; r < 4; ++r, ++m) {
5814           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5815           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5816           remotePointsNew[m].rank  = rrank;
5817         }
5818         for (r = 0; r < 3; ++r, ++m) {
5819           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
5820           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
5821           remotePointsNew[m].rank  = rrank;
5822         }
5823       } else if ((p >= cStart) && (p < cMax)) {
5824         /* Old hybrid cells add new cells and hybrid face */
5825         for (r = 0; r < 2; ++r, ++m) {
5826           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5827           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5828           remotePointsNew[m].rank  = rrank;
5829         }
5830         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
5831         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]);
5832         remotePointsNew[m].rank  = rrank;
5833         ++m;
5834       }
5835       break;
5836     case 4:
5837       /* Hybrid Hex 2D */
5838       if ((p >= vStart) && (p < vEnd)) {
5839         /* Old vertices stay the same */
5840         localPointsNew[m]        = vStartNew     + (p  - vStart);
5841         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5842         remotePointsNew[m].rank  = rrank;
5843         ++m;
5844       } else if ((p >= fStart) && (p < fMax)) {
5845         /* Old interior faces add new faces and vertex */
5846         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5847         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5848         remotePointsNew[m].rank  = rrank;
5849         ++m;
5850         for (r = 0; r < 2; ++r, ++m) {
5851           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5852           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5853           remotePointsNew[m].rank  = rrank;
5854         }
5855       } else if ((p >= fMax) && (p < fEnd)) {
5856         /* Old hybrid faces stay the same */
5857         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
5858         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
5859         remotePointsNew[m].rank  = rrank;
5860         ++m;
5861       } else if ((p >= cStart) && (p < cMax)) {
5862         /* Old interior cells add new cells, interior faces, and vertex */
5863         localPointsNew[m]        = vStartNew     + (vEnd - vStart)               + (fEnd - fStart)                    + (p  - cStart);
5864         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0]  + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
5865         remotePointsNew[m].rank  = rrank;
5866         ++m;
5867         for (r = 0; r < 4; ++r, ++m) {
5868           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5869           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5870           remotePointsNew[m].rank  = rrank;
5871         }
5872         for (r = 0; r < 4; ++r, ++m) {
5873           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*4     + r;
5874           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*4 + r;
5875           remotePointsNew[m].rank  = rrank;
5876         }
5877       } else if ((p >= cStart) && (p < cMax)) {
5878         /* Old hybrid cells add new cells and hybrid face */
5879         for (r = 0; r < 2; ++r, ++m) {
5880           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5881           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5882           remotePointsNew[m].rank  = rrank;
5883         }
5884         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*4     + (p  - cMax);
5885         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*4 + (rp - rdepthMaxOld[n*(depth+1)+depth]);
5886         remotePointsNew[m].rank  = rrank;
5887         ++m;
5888       }
5889       break;
5890     case 5:
5891       /* Simplicial 3D */
5892       if ((p >= vStart) && (p < vEnd)) {
5893         /* Old vertices stay the same */
5894         localPointsNew[m]        = vStartNew     + (p  - vStart);
5895         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5896         remotePointsNew[m].rank  = rrank;
5897         ++m;
5898       } else if ((p >= eStart) && (p < eEnd)) {
5899         /* Old edges add new edges and vertex */
5900         for (r = 0; r < 2; ++r, ++m) {
5901           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
5902           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
5903           remotePointsNew[m].rank  = rrank;
5904         }
5905         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
5906         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
5907         remotePointsNew[m].rank  = rrank;
5908         ++m;
5909       } else if ((p >= fStart) && (p < fEnd)) {
5910         /* Old faces add new faces and face edges */
5911         for (r = 0; r < 4; ++r, ++m) {
5912           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
5913           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
5914           remotePointsNew[m].rank  = rrank;
5915         }
5916         for (r = 0; r < 3; ++r, ++m) {
5917           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (p  - fStart)*3     + r;
5918           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + (rp - rfStart[n])*3 + r;
5919           remotePointsNew[m].rank  = rrank;
5920         }
5921       } else if ((p >= cStart) && (p < cEnd)) {
5922         /* Old cells add new cells and interior faces and edges */
5923         for (r = 0; r < 8; ++r, ++m) {
5924           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
5925           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
5926           remotePointsNew[m].rank  = rrank;
5927         }
5928         for (r = 0; r < 8; ++r, ++m) {
5929           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*4                    + (p  - cStart)*8     + r;
5930           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*4 + (rp - rcStart[n])*8 + r;
5931           remotePointsNew[m].rank  = rrank;
5932         }
5933         for (r = 0; r < 1; ++r, ++m) {
5934           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (fEnd - fStart)*3                    + (p  - cStart)*1     + r;
5935           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + rdepthSizeOld[n*(depth+1)+depth-1]*3 + (rp - rcStart[n])*1 + r;
5936           remotePointsNew[m].rank  = rrank;
5937         }
5938       }
5939       break;
5940     case 7:
5941       /* Hybrid Simplicial 3D */
5942       if ((p >= vStart) && (p < vEnd)) {
5943         /* Interior vertices stay the same */
5944         localPointsNew[m]        = vStartNew     + (p  - vStart);
5945         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5946         remotePointsNew[m].rank  = rrank;
5947         ++m;
5948       } else if ((p >= eStart) && (p < eMax)) {
5949         /* Interior edges add new edges and vertex */
5950         for (r = 0; r < 2; ++r, ++m) {
5951           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
5952           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
5953           remotePointsNew[m].rank  = rrank;
5954         }
5955         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
5956         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
5957         remotePointsNew[m].rank  = rrank;
5958         ++m;
5959       } else if ((p >= eMax) && (p < eEnd)) {
5960         /* Hybrid edges stay the same */
5961         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - eMax);
5962         remotePointsNew[m].index = reStartNew[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]);
5963         remotePointsNew[m].rank  = rrank;
5964         ++m;
5965       } else if ((p >= fStart) && (p < fMax)) {
5966         /* Interior faces add new faces and edges */
5967         for (r = 0; r < 4; ++r, ++m) {
5968           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
5969           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
5970           remotePointsNew[m].rank  = rrank;
5971         }
5972         for (r = 0; r < 3; ++r, ++m) {
5973           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*3     + r;
5974           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
5975           remotePointsNew[m].rank  = rrank;
5976         }
5977       } else if ((p >= fMax) && (p < fEnd)) {
5978         /* Hybrid faces add new faces and edges */
5979         for (r = 0; r < 2; ++r, ++m) {
5980           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fMax)*2                              + r;
5981           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth-1])*2 + r;
5982           remotePointsNew[m].rank  = rrank;
5983         }
5984         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (eEnd                                    - eMax)                        + (p  - fMax);
5985         remotePointsNew[m].index = reStartNew[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]) + (rdepthSizeOld[n*(depth+1)+1]+reStart[n] - rdepthMaxOld[n*(depth+1)+1]) + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
5986         remotePointsNew[m].rank  = rrank;
5987         ++m;
5988       } else if ((p >= cStart) && (p < cMax)) {
5989         /* Interior cells add new cells, faces, and edges */
5990         for (r = 0; r < 8; ++r, ++m) {
5991           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
5992           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
5993           remotePointsNew[m].rank  = rrank;
5994         }
5995         for (r = 0; r < 8; ++r, ++m) {
5996           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*8     + r;
5997           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*8 + r;
5998           remotePointsNew[m].rank  = rrank;
5999         }
6000         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (p  - cStart)*1     + r;
6001         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;
6002         remotePointsNew[m].rank  = rrank;
6003         ++m;
6004       } else if ((p >= cMax) && (p < cEnd)) {
6005         /* Hybrid cells add new cells and faces */
6006         for (r = 0; r < 4; ++r, ++m) {
6007           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
6008           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
6009           remotePointsNew[m].rank  = rrank;
6010         }
6011         for (r = 0; r < 3; ++r, ++m) {
6012           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*2                              + (p  - cMax)*3                            + r;
6013           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])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth])*3 + r;
6014           remotePointsNew[m].rank  = rrank;
6015         }
6016       }
6017       break;
6018     case 6:
6019       /* Hex 3D */
6020       if ((p >= vStart) && (p < vEnd)) {
6021         /* Old vertices stay the same */
6022         localPointsNew[m]        = vStartNew     + (p  - vStart);
6023         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6024         remotePointsNew[m].rank  = rrank;
6025         ++m;
6026       } else if ((p >= eStart) && (p < eEnd)) {
6027         /* Old edges add new edges and vertex */
6028         for (r = 0; r < 2; ++r, ++m) {
6029           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
6030           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
6031           remotePointsNew[m].rank  = rrank;
6032         }
6033         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
6034         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
6035         remotePointsNew[m].rank  = rrank;
6036         ++m;
6037       } else if ((p >= fStart) && (p < fEnd)) {
6038         /* Old faces add new faces, edges, and vertex */
6039         for (r = 0; r < 4; ++r, ++m) {
6040           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
6041           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
6042           remotePointsNew[m].rank  = rrank;
6043         }
6044         for (r = 0; r < 4; ++r, ++m) {
6045           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (p  - fStart)*4     + r;
6046           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + (rp - rfStart[n])*4 + r;
6047           remotePointsNew[m].rank  = rrank;
6048         }
6049         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eEnd - eStart)              + (p  - fStart);
6050         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+1] + (rp - rfStart[n]);
6051         remotePointsNew[m].rank  = rrank;
6052         ++m;
6053       } else if ((p >= cStart) && (p < cEnd)) {
6054         /* Old cells add new cells, faces, edges, and vertex */
6055         for (r = 0; r < 8; ++r, ++m) {
6056           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
6057           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
6058           remotePointsNew[m].rank  = rrank;
6059         }
6060         for (r = 0; r < 12; ++r, ++m) {
6061           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*4                    + (p  - cStart)*12     + r;
6062           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*4 + (rp - rcStart[n])*12 + r;
6063           remotePointsNew[m].rank  = rrank;
6064         }
6065         for (r = 0; r < 6; ++r, ++m) {
6066           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (fEnd - fStart)*4                    + (p  - cStart)*6     + r;
6067           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + rdepthSizeOld[n*(depth+1)+depth-1]*4 + (rp - rcStart[n])*6 + r;
6068           remotePointsNew[m].rank  = rrank;
6069         }
6070         for (r = 0; r < 1; ++r, ++m) {
6071           localPointsNew[m]        = vStartNew     + (eEnd - eStart)              + (fEnd - fStart)                    + (p  - cStart)     + r;
6072           remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+1] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]) + r;
6073           remotePointsNew[m].rank  = rrank;
6074         }
6075       }
6076       break;
6077     case 8:
6078       /* Hybrid Hex 3D */
6079       if ((p >= vStart) && (p < vEnd)) {
6080         /* Interior vertices stay the same */
6081         localPointsNew[m]        = vStartNew     + (p  - vStart);
6082         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6083         remotePointsNew[m].rank  = rrank;
6084         ++m;
6085       } else if ((p >= eStart) && (p < eMax)) {
6086         /* Interior edges add new edges and vertex */
6087         for (r = 0; r < 2; ++r, ++m) {
6088           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
6089           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
6090           remotePointsNew[m].rank  = rrank;
6091         }
6092         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
6093         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
6094         remotePointsNew[m].rank  = rrank;
6095         ++m;
6096       } else if ((p >= eMax) && (p < eEnd)) {
6097         /* Hybrid edges stay the same */
6098         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (p  - eMax);
6099         remotePointsNew[m].index = rvStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*6 + (rp - rdepthMaxOld[n*(depth+1)+1]);
6100         remotePointsNew[m].rank  = rrank;
6101         ++m;
6102       } else if ((p >= fStart) && (p < fMax)) {
6103         /* Interior faces add new faces, edges, and vertex */
6104         for (r = 0; r < 4; ++r, ++m) {
6105           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
6106           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
6107           remotePointsNew[m].rank  = rrank;
6108         }
6109         for (r = 0; r < 4; ++r, ++m) {
6110           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*4     + r;
6111           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*4 + r;
6112           remotePointsNew[m].rank  = rrank;
6113         }
6114         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax                        - eStart)     + (p  - fStart);
6115         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
6116         remotePointsNew[m].rank  = rrank;
6117         ++m;
6118       } else if ((p >= fMax) && (p < fEnd)) {
6119         /* Hybrid faces add new faces and edges */
6120         for (r = 0; r < 2; ++r, ++m) {
6121           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fMax)*2                              + r;
6122           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth-1])*2 + r;
6123           remotePointsNew[m].rank  = rrank;
6124         }
6125         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (fEnd                                          - fMax);
6126         remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*6 + (rdepthSizeOld[n*(depth+1)+depth-1]+rfStart[n] - rdepthMaxOld[n*(depth+1)+depth-1]);
6127         remotePointsNew[m].rank  = rrank;
6128         ++m;
6129       } else if ((p >= cStart) && (p < cMax)) {
6130         /* Interior cells add new cells, faces, edges, and vertex */
6131         for (r = 0; r < 8; ++r, ++m) {
6132           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
6133           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
6134           remotePointsNew[m].rank  = rrank;
6135         }
6136         for (r = 0; r < 12; ++r, ++m) {
6137           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*12     + r;
6138           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*12 + r;
6139           remotePointsNew[m].rank  = rrank;
6140         }
6141         for (r = 0; r < 6; ++r, ++m) {
6142           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (p  - cStart)*6     + r;
6143           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*6 + r;
6144           remotePointsNew[m].rank  = rrank;
6145         }
6146         for (r = 0; r < 1; ++r, ++m) {
6147           localPointsNew[m]        = vStartNew     + (eMax                        - eStart)     + (fMax                              - fStart)     + (p  - cStart)     + r;
6148           remotePointsNew[m].index = rvStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]) + r;
6149           remotePointsNew[m].rank  = rrank;
6150         }
6151       } else if ((p >= cMax) && (p < cEnd)) {
6152         /* Hybrid cells add new cells, faces, and edges */
6153         for (r = 0; r < 4; ++r, ++m) {
6154           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
6155           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
6156           remotePointsNew[m].rank  = rrank;
6157         }
6158         for (r = 0; r < 4; ++r, ++m) {
6159           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*2                              + (p  - cMax)*4                            + r;
6160           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])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
6161           remotePointsNew[m].rank  = rrank;
6162         }
6163         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (fEnd                                          - fMax)                              + (p  - cMax);
6164         remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*6 + (rdepthSizeOld[n*(depth+1)+depth-1]+rfStart[n] - rdepthMaxOld[n*(depth+1)+depth-1]) + (rp - rdepthMaxOld[n*(depth+1)+depth]);
6165         remotePointsNew[m].rank  = rrank;
6166         ++m;
6167       }
6168       break;
6169     default:
6170       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6171     }
6172   }
6173   if (m != numLeavesNew) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of leaf point %d should be %d", m, numLeavesNew);
6174   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
6175   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
6176   {
6177     PetscSFNode *rp, *rtmp;
6178     PetscInt    *lp, *idx, *ltmp, i;
6179 
6180     /* SF needs sorted leaves to correct calculate Gather */
6181     ierr = PetscMalloc1(numLeavesNew,&idx);CHKERRQ(ierr);
6182     ierr = PetscMalloc1(numLeavesNew, &lp);CHKERRQ(ierr);
6183     ierr = PetscMalloc1(numLeavesNew, &rp);CHKERRQ(ierr);
6184     for (i = 0; i < numLeavesNew; ++i) idx[i] = i;
6185     ierr = PetscSortIntWithPermutation(numLeavesNew, localPointsNew, idx);CHKERRQ(ierr);
6186     for (i = 0; i < numLeavesNew; ++i) {
6187       lp[i] = localPointsNew[idx[i]];
6188       rp[i] = remotePointsNew[idx[i]];
6189     }
6190     ltmp            = localPointsNew;
6191     localPointsNew  = lp;
6192     rtmp            = remotePointsNew;
6193     remotePointsNew = rp;
6194     ierr = PetscFree(idx);CHKERRQ(ierr);
6195     ierr = PetscFree(ltmp);CHKERRQ(ierr);
6196     ierr = PetscFree(rtmp);CHKERRQ(ierr);
6197   }
6198   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6199   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
6200   ierr = PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
6201   PetscFunctionReturn(0);
6202 }
6203 
6204 #undef __FUNCT__
6205 #define __FUNCT__ "CellRefinerCreateLabels"
6206 static PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6207 {
6208   PetscInt       numLabels, l;
6209   PetscInt       depth, newp, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r;
6210   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
6211   PetscErrorCode ierr;
6212 
6213   PetscFunctionBegin;
6214   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6215   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6216   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6217   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6218   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6219   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
6220   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
6221   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6222   switch (refiner) {
6223   case 0: break;
6224   case 7:
6225   case 8:
6226     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
6227   case 3:
6228   case 4:
6229     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6230     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6231   }
6232   for (l = 0; l < numLabels; ++l) {
6233     DMLabel         label, labelNew;
6234     const char     *lname;
6235     PetscBool       isDepth;
6236     IS              valueIS;
6237     const PetscInt *values;
6238     PetscInt        numValues, val;
6239 
6240     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
6241     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
6242     if (isDepth) continue;
6243     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
6244     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
6245     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
6246     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
6247     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
6248     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
6249     for (val = 0; val < numValues; ++val) {
6250       IS              pointIS;
6251       const PetscInt *points;
6252       PetscInt        numPoints, n;
6253 
6254       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
6255       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
6256       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
6257       for (n = 0; n < numPoints; ++n) {
6258         const PetscInt p = points[n];
6259         switch (refiner) {
6260         case 1:
6261           /* Simplicial 2D */
6262           if ((p >= vStart) && (p < vEnd)) {
6263             /* Old vertices stay the same */
6264             newp = vStartNew + (p - vStart);
6265             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6266           } else if ((p >= fStart) && (p < fEnd)) {
6267             /* Old faces add new faces and vertex */
6268             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6269             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6270             for (r = 0; r < 2; ++r) {
6271               newp = fStartNew + (p - fStart)*2 + r;
6272               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6273             }
6274           } else if ((p >= cStart) && (p < cEnd)) {
6275             /* Old cells add new cells and interior faces */
6276             for (r = 0; r < 4; ++r) {
6277               newp = cStartNew + (p - cStart)*4 + r;
6278               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6279             }
6280             for (r = 0; r < 3; ++r) {
6281               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6282               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6283             }
6284           }
6285           break;
6286         case 2:
6287           /* Hex 2D */
6288           if ((p >= vStart) && (p < vEnd)) {
6289             /* Old vertices stay the same */
6290             newp = vStartNew + (p - vStart);
6291             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6292           } else if ((p >= fStart) && (p < fEnd)) {
6293             /* Old faces add new faces and vertex */
6294             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6295             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6296             for (r = 0; r < 2; ++r) {
6297               newp = fStartNew + (p - fStart)*2 + r;
6298               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6299             }
6300           } else if ((p >= cStart) && (p < cEnd)) {
6301             /* Old cells add new cells and interior faces and vertex */
6302             for (r = 0; r < 4; ++r) {
6303               newp = cStartNew + (p - cStart)*4 + r;
6304               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6305             }
6306             for (r = 0; r < 4; ++r) {
6307               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
6308               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6309             }
6310             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
6311             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6312           }
6313           break;
6314         case 3:
6315           /* Hybrid simplicial 2D */
6316           if ((p >= vStart) && (p < vEnd)) {
6317             /* Old vertices stay the same */
6318             newp = vStartNew + (p - vStart);
6319             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6320           } else if ((p >= fStart) && (p < fMax)) {
6321             /* Old interior faces add new faces and vertex */
6322             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6323             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6324             for (r = 0; r < 2; ++r) {
6325               newp = fStartNew + (p - fStart)*2 + r;
6326               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6327             }
6328           } else if ((p >= fMax) && (p < fEnd)) {
6329             /* Old hybrid faces stay the same */
6330             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
6331             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6332           } else if ((p >= cStart) && (p < cMax)) {
6333             /* Old interior cells add new cells and interior faces */
6334             for (r = 0; r < 4; ++r) {
6335               newp = cStartNew + (p - cStart)*4 + r;
6336               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6337             }
6338             for (r = 0; r < 3; ++r) {
6339               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6340               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6341             }
6342           } else if ((p >= cMax) && (p < cEnd)) {
6343             /* Old hybrid cells add new cells and hybrid face */
6344             for (r = 0; r < 2; ++r) {
6345               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
6346               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6347             }
6348             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
6349             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6350           }
6351           break;
6352         case 4:
6353           /* Hybrid Hex 2D */
6354           if ((p >= vStart) && (p < vEnd)) {
6355             /* Old vertices stay the same */
6356             newp = vStartNew + (p - vStart);
6357             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6358           } else if ((p >= fStart) && (p < fMax)) {
6359             /* Old interior faces add new faces and vertex */
6360             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6361             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6362             for (r = 0; r < 2; ++r) {
6363               newp = fStartNew + (p - fStart)*2 + r;
6364               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6365             }
6366           } else if ((p >= fMax) && (p < fEnd)) {
6367             /* Old hybrid faces stay the same */
6368             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
6369             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6370           } else if ((p >= cStart) && (p < cMax)) {
6371             /* Old interior cells add new cells, interior faces, and vertex */
6372             for (r = 0; r < 4; ++r) {
6373               newp = cStartNew + (p - cStart)*4 + r;
6374               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6375             }
6376             for (r = 0; r < 4; ++r) {
6377               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
6378               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6379             }
6380             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
6381             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6382           } else if ((p >= cMax) && (p < cEnd)) {
6383             /* Old hybrid cells add new cells and hybrid face */
6384             for (r = 0; r < 2; ++r) {
6385               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
6386               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6387             }
6388             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (p - cMax);
6389             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6390           }
6391           break;
6392         case 5:
6393           /* Simplicial 3D */
6394           if ((p >= vStart) && (p < vEnd)) {
6395             /* Old vertices stay the same */
6396             newp = vStartNew + (p - vStart);
6397             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6398           } else if ((p >= eStart) && (p < eEnd)) {
6399             /* Old edges add new edges and vertex */
6400             for (r = 0; r < 2; ++r) {
6401               newp = eStartNew + (p - eStart)*2 + r;
6402               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6403             }
6404             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6405             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6406           } else if ((p >= fStart) && (p < fEnd)) {
6407             /* Old faces add new faces and edges */
6408             for (r = 0; r < 4; ++r) {
6409               newp = fStartNew + (p - fStart)*4 + r;
6410               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6411             }
6412             for (r = 0; r < 3; ++r) {
6413               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
6414               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6415             }
6416           } else if ((p >= cStart) && (p < cEnd)) {
6417             /* Old cells add new cells and interior faces and edges */
6418             for (r = 0; r < 8; ++r) {
6419               newp = cStartNew + (p - cStart)*8 + r;
6420               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6421             }
6422             for (r = 0; r < 8; ++r) {
6423               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*8 + r;
6424               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6425             }
6426             for (r = 0; r < 1; ++r) {
6427               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*1 + r;
6428               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6429             }
6430           }
6431           break;
6432         case 7:
6433           /* Hybrid Simplicial 3D */
6434           if ((p >= vStart) && (p < vEnd)) {
6435             /* Interior vertices stay the same */
6436             newp = vStartNew + (p - vStart);
6437             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6438           } else if ((p >= eStart) && (p < eMax)) {
6439             /* Interior edges add new edges and vertex */
6440             for (r = 0; r < 2; ++r) {
6441               newp = eStartNew + (p - eStart)*2 + r;
6442               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6443             }
6444             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6445             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6446           } else if ((p >= eMax) && (p < eEnd)) {
6447             /* Hybrid edges stay the same */
6448             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - eMax);
6449             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6450           } else if ((p >= fStart) && (p < fMax)) {
6451             /* Interior faces add new faces and edges */
6452             for (r = 0; r < 4; ++r) {
6453               newp = fStartNew + (p - fStart)*4 + r;
6454               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6455             }
6456             for (r = 0; r < 3; ++r) {
6457               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
6458               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6459             }
6460           } else if ((p >= fMax) && (p < fEnd)) {
6461             /* Hybrid faces add new faces and edges */
6462             for (r = 0; r < 2; ++r) {
6463               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (p - fMax)*2 + r;
6464               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6465             }
6466             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - fMax);
6467             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6468           } else if ((p >= cStart) && (p < cMax)) {
6469             /* Interior cells add new cells, faces, and edges */
6470             for (r = 0; r < 8; ++r) {
6471               newp = cStartNew + (p - cStart)*8 + r;
6472               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6473             }
6474             for (r = 0; r < 8; ++r) {
6475               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*8 + r;
6476               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6477             }
6478             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart);
6479             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6480           } else if ((p >= cMax) && (p < cEnd)) {
6481             /* Hybrid cells add new cells and faces */
6482             for (r = 0; r < 4; ++r) {
6483               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
6484               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6485             }
6486             for (r = 0; r < 3; ++r) {
6487               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
6488               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6489             }
6490           }
6491           break;
6492         case 6:
6493           /* Hex 3D */
6494           if ((p >= vStart) && (p < vEnd)) {
6495             /* Old vertices stay the same */
6496             newp = vStartNew + (p - vStart);
6497             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6498           } else if ((p >= eStart) && (p < eEnd)) {
6499             /* Old edges add new edges and vertex */
6500             for (r = 0; r < 2; ++r) {
6501               newp = eStartNew + (p - eStart)*2 + r;
6502               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6503             }
6504             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6505             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6506           } else if ((p >= fStart) && (p < fEnd)) {
6507             /* Old faces add new faces, edges, and vertex */
6508             for (r = 0; r < 4; ++r) {
6509               newp = fStartNew + (p - fStart)*4 + r;
6510               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6511             }
6512             for (r = 0; r < 4; ++r) {
6513               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*4 + r;
6514               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6515             }
6516             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (p - fStart);
6517             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6518           } else if ((p >= cStart) && (p < cEnd)) {
6519             /* Old cells add new cells, faces, edges, and vertex */
6520             for (r = 0; r < 8; ++r) {
6521               newp = cStartNew + (p - cStart)*8 + r;
6522               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6523             }
6524             for (r = 0; r < 12; ++r) {
6525               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*12 + r;
6526               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6527             }
6528             for (r = 0; r < 6; ++r) {
6529               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (p - cStart)*6 + r;
6530               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6531             }
6532             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (p - cStart);
6533             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6534           }
6535           break;
6536         case 8:
6537           /* Hybrid Hex 3D */
6538           if ((p >= vStart) && (p < vEnd)) {
6539             /* Interior vertices stay the same */
6540             newp = vStartNew + (p - vStart);
6541             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6542           } else if ((p >= eStart) && (p < eMax)) {
6543             /* Interior edges add new edges and vertex */
6544             for (r = 0; r < 2; ++r) {
6545               newp = eStartNew + (p - eStart)*2 + r;
6546               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6547             }
6548             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6549             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6550           } else if ((p >= eMax) && (p < eEnd)) {
6551             /* Hybrid edges stay the same */
6552             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - eMax);
6553             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6554           } else if ((p >= fStart) && (p < fMax)) {
6555             /* Interior faces add new faces, edges, and vertex */
6556             for (r = 0; r < 4; ++r) {
6557               newp = fStartNew + (p - fStart)*4 + r;
6558               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6559             }
6560             for (r = 0; r < 4; ++r) {
6561               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*4 + r;
6562               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6563             }
6564             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (p - fStart);
6565             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6566           } else if ((p >= fMax) && (p < fEnd)) {
6567             /* Hybrid faces add new faces and edges */
6568             for (r = 0; r < 2; ++r) {
6569               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (p - fMax)*2 + r;
6570               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6571             }
6572             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - fMax);
6573             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6574           } else if ((p >= cStart) && (p < cMax)) {
6575             /* Interior cells add new cells, faces, edges, and vertex */
6576             for (r = 0; r < 8; ++r) {
6577               newp = cStartNew + (p - cStart)*8 + r;
6578               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6579             }
6580             for (r = 0; r < 12; ++r) {
6581               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*12 + r;
6582               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6583             }
6584             for (r = 0; r < 6; ++r) {
6585               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (p - cStart)*6 + r;
6586               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6587             }
6588             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (p - cStart);
6589             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6590           } else if ((p >= cMax) && (p < cEnd)) {
6591             /* Hybrid cells add new cells, faces, and edges */
6592             for (r = 0; r < 4; ++r) {
6593               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
6594               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6595             }
6596             for (r = 0; r < 4; ++r) {
6597               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (p - cMax)*4 + r;
6598               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6599             }
6600             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (fEnd - fMax) + (p - cMax);
6601             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6602           }
6603           break;
6604         default:
6605           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6606         }
6607       }
6608       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
6609       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
6610     }
6611     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
6612     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
6613     if (0) {
6614       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
6615       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
6616       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
6617     }
6618   }
6619   PetscFunctionReturn(0);
6620 }
6621 
6622 #undef __FUNCT__
6623 #define __FUNCT__ "DMPlexRefineUniform_Internal"
6624 /* This will only work for interpolated meshes */
6625 PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
6626 {
6627   DM             rdm;
6628   PetscInt      *depthSize;
6629   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
6630   PetscErrorCode ierr;
6631 
6632   PetscFunctionBegin;
6633   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
6634   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
6635   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6636   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
6637   /* Calculate number of new points of each depth */
6638   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6639   ierr = PetscMalloc1((depth+1), &depthSize);CHKERRQ(ierr);
6640   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
6641   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
6642   /* Step 1: Set chart */
6643   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
6644   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
6645   /* Step 2: Set cone/support sizes */
6646   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6647   /* Step 3: Setup refined DM */
6648   ierr = DMSetUp(rdm);CHKERRQ(ierr);
6649   /* Step 4: Set cones and supports */
6650   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6651   /* Step 5: Stratify */
6652   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
6653   /* Step 6: Set coordinates for vertices */
6654   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6655   /* Step 7: Create pointSF */
6656   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6657   /* Step 8: Create labels */
6658   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6659   ierr = PetscFree(depthSize);CHKERRQ(ierr);
6660 
6661   *dmRefined = rdm;
6662   PetscFunctionReturn(0);
6663 }
6664 
6665 #undef __FUNCT__
6666 #define __FUNCT__ "DMPlexCreateCoarsePointIS"
6667 /*@
6668   DMPlexCreateCoarsePointIS - Creates an IS covering the coarse DM chart with the fine points as data
6669 
6670   Input Parameter:
6671 . dm - The coarse DM
6672 
6673   Output Parameter:
6674 . fpointIS - The IS of all the fine points which exist in the original coarse mesh
6675 
6676   Level: developer
6677 
6678 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexCreateSubpointIS()
6679 @*/
6680 PetscErrorCode DMPlexCreateCoarsePointIS(DM dm, IS *fpointIS)
6681 {
6682   CellRefiner    cellRefiner;
6683   PetscInt      *depthSize, *fpoints;
6684   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
6685   PetscInt       depth, pStart, pEnd, p, vStart, vEnd, v;
6686   PetscErrorCode ierr;
6687 
6688   PetscFunctionBegin;
6689   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6690   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6691   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6692   ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr);
6693   ierr = PetscMalloc1((depth+1), &depthSize);CHKERRQ(ierr);
6694   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
6695   if (cellRefiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
6696   ierr = PetscMalloc1(pEnd-pStart,&fpoints);CHKERRQ(ierr);
6697   for (p = 0; p < pEnd-pStart; ++p) fpoints[p] = -1;
6698   switch (cellRefiner) {
6699   case 1: /* Simplicial 2D */
6700   case 3: /* Hybrid simplicial 2D */
6701   case 2: /* Hex 2D */
6702   case 4: /* Hybrid Hex 2D */
6703   case 5: /* Simplicial 3D */
6704   case 7: /* Hybrid Simplicial 3D */
6705   case 6: /* Hex 3D */
6706   case 8: /* Hybrid Hex 3D */
6707     for (v = vStart; v < vEnd; ++v) fpoints[v-pStart] = vStartNew + (v - vStart);
6708     break;
6709   default:
6710     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", cellRefiner);
6711   }
6712   ierr = ISCreateGeneral(PETSC_COMM_SELF, pEnd-pStart, fpoints, PETSC_OWN_POINTER, fpointIS);CHKERRQ(ierr);
6713   ierr = PetscFree(depthSize);CHKERRQ(ierr);
6714   PetscFunctionReturn(0);
6715 }
6716 
6717 #undef __FUNCT__
6718 #define __FUNCT__ "DMPlexSetRefinementUniform"
6719 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
6720 {
6721   DM_Plex *mesh = (DM_Plex*) dm->data;
6722 
6723   PetscFunctionBegin;
6724   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6725   mesh->refinementUniform = refinementUniform;
6726   PetscFunctionReturn(0);
6727 }
6728 
6729 #undef __FUNCT__
6730 #define __FUNCT__ "DMPlexGetRefinementUniform"
6731 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
6732 {
6733   DM_Plex *mesh = (DM_Plex*) dm->data;
6734 
6735   PetscFunctionBegin;
6736   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6737   PetscValidPointer(refinementUniform,  2);
6738   *refinementUniform = mesh->refinementUniform;
6739   PetscFunctionReturn(0);
6740 }
6741 
6742 #undef __FUNCT__
6743 #define __FUNCT__ "DMPlexSetRefinementLimit"
6744 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
6745 {
6746   DM_Plex *mesh = (DM_Plex*) dm->data;
6747 
6748   PetscFunctionBegin;
6749   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6750   mesh->refinementLimit = refinementLimit;
6751   PetscFunctionReturn(0);
6752 }
6753 
6754 #undef __FUNCT__
6755 #define __FUNCT__ "DMPlexGetRefinementLimit"
6756 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
6757 {
6758   DM_Plex *mesh = (DM_Plex*) dm->data;
6759 
6760   PetscFunctionBegin;
6761   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6762   PetscValidPointer(refinementLimit,  2);
6763   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
6764   *refinementLimit = mesh->refinementLimit;
6765   PetscFunctionReturn(0);
6766 }
6767 
6768 #undef __FUNCT__
6769 #define __FUNCT__ "DMPlexGetCellRefiner_Internal"
6770 PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
6771 {
6772   PetscInt       dim, cStart, cEnd, coneSize, cMax;
6773   PetscErrorCode ierr;
6774 
6775   PetscFunctionBegin;
6776   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6777   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6778   if (cEnd <= cStart) {*cellRefiner = 0; PetscFunctionReturn(0);}
6779   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
6780   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
6781   switch (dim) {
6782   case 2:
6783     switch (coneSize) {
6784     case 3:
6785       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
6786       else *cellRefiner = 1; /* Triangular */
6787       break;
6788     case 4:
6789       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
6790       else *cellRefiner = 2; /* Quadrilateral */
6791       break;
6792     default:
6793       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
6794     }
6795     break;
6796   case 3:
6797     switch (coneSize) {
6798     case 4:
6799       if (cMax >= 0) *cellRefiner = 7; /* Hybrid */
6800       else *cellRefiner = 5; /* Tetrahedral */
6801       break;
6802     case 6:
6803       if (cMax >= 0) *cellRefiner = 8; /* Hybrid */
6804       else *cellRefiner = 6; /* hexahedral */
6805       break;
6806     default:
6807       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
6808     }
6809     break;
6810   default:
6811     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
6812   }
6813   PetscFunctionReturn(0);
6814 }
6815