xref: /petsc/src/dm/impls/plex/plexrefine.c (revision 49fcfd5b29fad77244f0c22942e5e14def09da40)
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], o, of, i;
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       o = ornt[0] < 0 ? -1 : 1;
4584       for (r = 0; r < 4; ++r) {
4585         PetscInt subfA = GetQuadSubface_Static(ornt[0], r);
4586         PetscInt edgeA = GetQuadEdge_Static(ornt[0], r);
4587         PetscInt edgeB = GetQuadEdge_Static(ornt[0], (r+3)%4);
4588         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]);
4589         coneNew[0]         = fStartNew + (cone[0] - fStart)*4 + subfA;
4590         orntNew[0]         = ornt[0];
4591         coneNew[1]         = fStartNew + (cone[1] - fStart)*4 + subfA;
4592         orntNew[1]         = ornt[0];
4593         of = fornt[edgeA] < 0 ? -1 : 1;
4594         i  = GetQuadEdgeInverse_Static(ornt[0], r) + 2;
4595         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeA] - fMax)*2 + (o*of < 0 ? 1 : 0);
4596         orntNew[i] = ornt[edgeA];
4597         i  = GetQuadEdgeInverse_Static(ornt[0], (r+1)%4) + 2;
4598         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeA;
4599         orntNew[i] = 0;
4600         i  = GetQuadEdgeInverse_Static(ornt[0], (r+2)%4) + 2;
4601         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeB;
4602         orntNew[i] = -2;
4603         of = fornt[edgeB] < 0 ? -1 : 1;
4604         i  = GetQuadEdgeInverse_Static(ornt[0], (r+3)%4) + 2;
4605         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeB] - fMax)*2 + (o*of < 0 ? 0 : 1);
4606         orntNew[i] = ornt[edgeB];
4607         ierr       = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
4608         ierr       = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
4609 #if 1
4610         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);
4611         for (p = 0; p < 2; ++p) {
4612           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);
4613         }
4614         for (p = 2; p < 6; ++p) {
4615           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);
4616         }
4617 #endif
4618       }
4619     }
4620     /* Interior split faces have 4 edges and the same cells as the parent */
4621     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4622     ierr = PetscMalloc1((4 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
4623     for (f = fStart; f < fMax; ++f) {
4624       for (r = 0; r < 4; ++r) {
4625         /* TODO: This can come from GetFaces_Internal() */
4626         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};
4627         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
4628         const PetscInt *cone, *ornt, *support;
4629         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
4630 
4631         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4632         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4633         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
4634         orntNew[(r+3)%4] = ornt[(r+3)%4];
4635         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
4636         orntNew[(r+0)%4] = ornt[r];
4637         coneNew[(r+1)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
4638         orntNew[(r+1)%4] = 0;
4639         coneNew[(r+2)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + (r+3)%4;
4640         orntNew[(r+2)%4] = -2;
4641         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4642         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4643 #if 1
4644         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4645         for (p = 0; p < 4; ++p) {
4646           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);
4647         }
4648 #endif
4649         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4650         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4651         for (s = 0; s < supportSize; ++s) {
4652           PetscInt subf;
4653           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4654           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4655           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4656           for (c = 0; c < coneSize; ++c) {
4657             if (cone[c] == f) break;
4658           }
4659           subf = GetQuadSubfaceInverse_Static(ornt[c], r);
4660           if (support[s] < cMax) {
4661             supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+subf];
4662           } else {
4663             supportRef[s] = cStartNew + (cMax       - cStart)*8 + (support[s] - cMax)*4 + subf;
4664           }
4665         }
4666         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4667 #if 1
4668         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4669         for (p = 0; p < supportSize; ++p) {
4670           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);
4671         }
4672 #endif
4673       }
4674     }
4675     /* Interior cell faces have 4 edges and 2 cells */
4676     for (c = cStart; c < cMax; ++c) {
4677       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};
4678       const PetscInt *cone, *ornt;
4679       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
4680 
4681       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4682       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4683       /* A-D face */
4684       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 0;
4685       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
4686       orntNew[0] = 0;
4687       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4688       orntNew[1] = 0;
4689       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4690       orntNew[2] = -2;
4691       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
4692       orntNew[3] = -2;
4693       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4694       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4695 #if 1
4696       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4697       for (p = 0; p < 4; ++p) {
4698         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);
4699       }
4700 #endif
4701       /* C-D face */
4702       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 1;
4703       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
4704       orntNew[0] = 0;
4705       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4706       orntNew[1] = 0;
4707       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4708       orntNew[2] = -2;
4709       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
4710       orntNew[3] = -2;
4711       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4712       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4713 #if 1
4714       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4715       for (p = 0; p < 4; ++p) {
4716         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);
4717       }
4718 #endif
4719       /* B-C face */
4720       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 2;
4721       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
4722       orntNew[0] = -2;
4723       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
4724       orntNew[1] = 0;
4725       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4726       orntNew[2] = 0;
4727       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4728       orntNew[3] = -2;
4729       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4730       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4731 #if 1
4732       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4733       for (p = 0; p < 4; ++p) {
4734         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);
4735       }
4736 #endif
4737       /* A-B face */
4738       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 3;
4739       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
4740       orntNew[0] = -2;
4741       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
4742       orntNew[1] = 0;
4743       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4744       orntNew[2] = 0;
4745       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4746       orntNew[3] = -2;
4747       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4748       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4749 #if 1
4750       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4751       for (p = 0; p < 4; ++p) {
4752         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);
4753       }
4754 #endif
4755       /* E-F face */
4756       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 4;
4757       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4758       orntNew[0] = -2;
4759       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
4760       orntNew[1] = -2;
4761       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
4762       orntNew[2] = 0;
4763       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4764       orntNew[3] = 0;
4765       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4766       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4767 #if 1
4768       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4769       for (p = 0; p < 4; ++p) {
4770         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);
4771       }
4772 #endif
4773       /* F-G face */
4774       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 5;
4775       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4776       orntNew[0] = -2;
4777       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
4778       orntNew[1] = -2;
4779       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
4780       orntNew[2] = 0;
4781       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4782       orntNew[3] = 0;
4783       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4784       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4785 #if 1
4786       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4787       for (p = 0; p < 4; ++p) {
4788         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);
4789       }
4790 #endif
4791       /* G-H face */
4792       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 6;
4793       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
4794       orntNew[0] = -2;
4795       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
4796       orntNew[1] = 0;
4797       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4798       orntNew[2] = 0;
4799       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4800       orntNew[3] = -2;
4801       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4802       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4803 #if 1
4804       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4805       for (p = 0; p < 4; ++p) {
4806         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);
4807       }
4808 #endif
4809       /* E-H face */
4810       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 7;
4811       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4812       orntNew[0] = -2;
4813       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
4814       orntNew[1] = -2;
4815       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
4816       orntNew[2] = 0;
4817       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4818       orntNew[3] = 0;
4819       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4820       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4821 #if 1
4822       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4823       for (p = 0; p < 4; ++p) {
4824         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);
4825       }
4826 #endif
4827       /* A-E face */
4828       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 8;
4829       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
4830       orntNew[0] = 0;
4831       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4832       orntNew[1] = 0;
4833       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4834       orntNew[2] = -2;
4835       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
4836       orntNew[3] = -2;
4837       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4838       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4839 #if 1
4840       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4841       for (p = 0; p < 4; ++p) {
4842         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);
4843       }
4844 #endif
4845       /* D-F face */
4846       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 9;
4847       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
4848       orntNew[0] = -2;
4849       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
4850       orntNew[1] = 0;
4851       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4852       orntNew[2] = 0;
4853       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4854       orntNew[3] = -2;
4855       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4856       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4857 #if 1
4858       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4859       for (p = 0; p < 4; ++p) {
4860         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);
4861       }
4862 #endif
4863       /* C-G face */
4864       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 10;
4865       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4866       orntNew[0] = -2;
4867       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
4868       orntNew[1] = -2;
4869       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
4870       orntNew[2] = 0;
4871       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4872       orntNew[3] = 0;
4873       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4874       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4875 #if 1
4876       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4877       for (p = 0; p < 4; ++p) {
4878         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);
4879       }
4880 #endif
4881       /* B-H face */
4882       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 11;
4883       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4884       orntNew[0] = 0;
4885       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4886       orntNew[1] = -2;
4887       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
4888       orntNew[2] = -2;
4889       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
4890       orntNew[3] = 0;
4891       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4892       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4893 #if 1
4894       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4895       for (p = 0; p < 4; ++p) {
4896         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);
4897       }
4898 #endif
4899       for (r = 0; r < 12; ++r) {
4900         newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
4901         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
4902         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
4903         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4904 #if 1
4905         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4906         for (p = 0; p < 2; ++p) {
4907           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);
4908         }
4909 #endif
4910       }
4911     }
4912     /* Hybrid split faces have 4 edges and same cells */
4913     for (f = fMax; f < fEnd; ++f) {
4914       const PetscInt *cone, *ornt, *support;
4915       PetscInt        coneNew[4], orntNew[4];
4916       PetscInt        supportNew[2], size, s, c;
4917 
4918       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4919       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4920       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4921       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4922       for (r = 0; r < 2; ++r) {
4923         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
4924 
4925         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
4926         orntNew[0]   = ornt[0];
4927         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
4928         orntNew[1]   = ornt[1];
4929         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (cone[2+r] - eMax);
4930         orntNew[2+r] = 0;
4931         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd      - eMax) + (f - fMax);
4932         orntNew[3-r] = 0;
4933         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4934         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4935 #if 1
4936         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
4937         for (p = 0; p < 2; ++p) {
4938           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);
4939         }
4940         for (p = 2; p < 4; ++p) {
4941           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);
4942         }
4943 #endif
4944         for (s = 0; s < size; ++s) {
4945           const PetscInt *coneCell, *orntCell, *fornt;
4946           PetscInt        o, of;
4947 
4948           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
4949           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
4950           o = orntCell[0] < 0 ? -1 : 1;
4951           for (c = 2; c < 6; ++c) if (coneCell[c] == f) break;
4952           if (c >= 6) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
4953           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
4954           of = fornt[c-2] < 0 ? -1 : 1;
4955           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetQuadEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%4;
4956         }
4957         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4958 #if 1
4959         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
4960         for (p = 0; p < size; ++p) {
4961           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);
4962         }
4963 #endif
4964       }
4965     }
4966     /* Hybrid cell faces have 4 edges and 2 cells */
4967     for (c = cMax; c < cEnd; ++c) {
4968       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4;
4969       const PetscInt *cone, *ornt;
4970       PetscInt        coneNew[4], orntNew[4];
4971       PetscInt        supportNew[2];
4972 
4973       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4974       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4975       for (r = 0; r < 4; ++r) {
4976 #if 0
4977         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], r);
4978         orntNew[0] = 0;
4979         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], r);
4980         orntNew[1] = 0;
4981         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+GetQuadEdge_Static(ornt[0], r)] - fMax);
4982         orntNew[2] = 0;
4983         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd                                   - fMax) + (c - cMax);
4984         orntNew[3] = 0;
4985 #else
4986         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + r;
4987         orntNew[0] = 0;
4988         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + r;
4989         orntNew[1] = 0;
4990         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+r] - fMax);
4991         orntNew[2] = 0;
4992         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd      - fMax) + (c - cMax);
4993         orntNew[3] = 0;
4994 #endif
4995         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
4996         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
4997 #if 1
4998         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);
4999         for (p = 0; p < 2; ++p) {
5000           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);
5001         }
5002         for (p = 2; p < 4; ++p) {
5003           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);
5004         }
5005 #endif
5006         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], r);
5007         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], (r+1)%4);
5008         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
5009 #if 1
5010         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);
5011         for (p = 0; p < 2; ++p) {
5012           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);
5013         }
5014 #endif
5015       }
5016     }
5017     /* Interior split edges have 2 vertices and the same faces as the parent */
5018     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5019     for (e = eStart; e < eMax; ++e) {
5020       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
5021 
5022       for (r = 0; r < 2; ++r) {
5023         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
5024         const PetscInt *cone, *ornt, *support;
5025         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5026 
5027         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
5028         coneNew[0]       = vStartNew + (cone[0] - vStart);
5029         coneNew[1]       = vStartNew + (cone[1] - vStart);
5030         coneNew[(r+1)%2] = newv;
5031         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5032 #if 1
5033         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5034         for (p = 0; p < 2; ++p) {
5035           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);
5036         }
5037 #endif
5038         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
5039         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5040         for (s = 0; s < supportSize; ++s) {
5041           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5042           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5043           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5044           for (c = 0; c < coneSize; ++c) {
5045             if (cone[c] == e) break;
5046           }
5047           if (support[s] < fMax) {
5048             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%4;
5049           } else {
5050             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
5051           }
5052         }
5053         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5054 #if 1
5055         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5056         for (p = 0; p < supportSize; ++p) {
5057           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);
5058         }
5059 #endif
5060       }
5061     }
5062     /* Interior face edges have 2 vertices and 2+cells faces */
5063     for (f = fStart; f < fMax; ++f) {
5064       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};
5065       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
5066       const PetscInt *cone, *coneCell, *orntCell, *support;
5067       PetscInt        coneNew[2], coneSize, c, supportSize, s;
5068 
5069       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5070       for (r = 0; r < 4; ++r) {
5071         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
5072 
5073         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
5074         coneNew[1] = newv;
5075         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5076 #if 1
5077         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5078         for (p = 0; p < 2; ++p) {
5079           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);
5080         }
5081 #endif
5082         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5083         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5084         supportRef[0] = fStartNew + (f - fStart)*4 + r;
5085         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
5086         for (s = 0; s < supportSize; ++s) {
5087           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5088           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
5089           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
5090           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
5091           if (support[s] < cMax) {
5092             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
5093           } else {
5094             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + r;
5095           }
5096         }
5097         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5098 #if 1
5099         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5100         for (p = 0; p < 2+supportSize; ++p) {
5101           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);
5102         }
5103 #endif
5104       }
5105     }
5106     /* Interior cell edges have 2 vertices and 4 faces */
5107     for (c = cStart; c < cMax; ++c) {
5108       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};
5109       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
5110       const PetscInt *cone;
5111       PetscInt        coneNew[2], supportNew[4];
5112 
5113       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5114       for (r = 0; r < 6; ++r) {
5115         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
5116 
5117         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
5118         coneNew[1] = newv;
5119         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5120 #if 1
5121         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5122         for (p = 0; p < 2; ++p) {
5123           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);
5124         }
5125 #endif
5126         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
5127         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5128 #if 1
5129         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5130         for (p = 0; p < 4; ++p) {
5131           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);
5132         }
5133 #endif
5134       }
5135     }
5136     /* Hybrid edges have two vertices and the same faces */
5137     for (e = eMax; e < eEnd; ++e) {
5138       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
5139       const PetscInt *cone, *support, *fcone;
5140       PetscInt        coneNew[2], size, fsize, s;
5141 
5142       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
5143       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
5144       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5145       coneNew[0] = vStartNew + (cone[0] - vStart);
5146       coneNew[1] = vStartNew + (cone[1] - vStart);
5147       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5148 #if 1
5149       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5150       for (p = 0; p < 2; ++p) {
5151         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);
5152       }
5153 #endif
5154       for (s = 0; s < size; ++s) {
5155         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
5156         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
5157         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
5158         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
5159         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + c-2;
5160       }
5161       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5162 #if 1
5163       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5164       for (p = 0; p < size; ++p) {
5165         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);
5166       }
5167 #endif
5168     }
5169     /* Hybrid face edges have 2 vertices and 2+cells faces */
5170     for (f = fMax; f < fEnd; ++f) {
5171       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
5172       const PetscInt *cone, *support, *ccone, *cornt;
5173       PetscInt        coneNew[2], size, csize, s;
5174 
5175       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5176       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5177       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5178       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
5179       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
5180       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5181 #if 1
5182       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5183       for (p = 0; p < 2; ++p) {
5184         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);
5185       }
5186 #endif
5187       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 0;
5188       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 1;
5189       for (s = 0; s < size; ++s) {
5190         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
5191         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
5192         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
5193         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
5194         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]);
5195         supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + c-2;
5196       }
5197       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5198 #if 1
5199       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5200       for (p = 0; p < 2+size; ++p) {
5201         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);
5202       }
5203 #endif
5204     }
5205     /* Hybrid cell edges have 2 vertices and 4 faces */
5206     for (c = cMax; c < cEnd; ++c) {
5207       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
5208       const PetscInt *cone, *support;
5209       PetscInt        coneNew[2], size;
5210 
5211       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5212       ierr = DMPlexGetSupportSize(dm, c, &size);CHKERRQ(ierr);
5213       ierr = DMPlexGetSupport(dm, c, &support);CHKERRQ(ierr);
5214       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
5215       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
5216       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5217 #if 1
5218       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5219       for (p = 0; p < 2; ++p) {
5220         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);
5221       }
5222 #endif
5223       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 0;
5224       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 1;
5225       supportRef[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 2;
5226       supportRef[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 3;
5227       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5228 #if 1
5229       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5230       for (p = 0; p < 4; ++p) {
5231         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);
5232       }
5233 #endif
5234     }
5235     /* Interior vertices have identical supports */
5236     for (v = vStart; v < vEnd; ++v) {
5237       const PetscInt  newp = vStartNew + (v - vStart);
5238       const PetscInt *support, *cone;
5239       PetscInt        size, s;
5240 
5241       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5242       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5243       for (s = 0; s < size; ++s) {
5244         PetscInt r = 0;
5245 
5246         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5247         if (cone[1] == v) r = 1;
5248         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
5249         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (support[s] - eMax);
5250       }
5251       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5252 #if 1
5253       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5254       for (p = 0; p < size; ++p) {
5255         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);
5256       }
5257 #endif
5258     }
5259     /* Interior edge vertices have 2 + faces supports */
5260     for (e = eStart; e < eMax; ++e) {
5261       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
5262       const PetscInt *cone, *support;
5263       PetscInt        size, s;
5264 
5265       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
5266       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5267       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
5268       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
5269       for (s = 0; s < size; ++s) {
5270         PetscInt r;
5271 
5272         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5273         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
5274         if (support[s] < fMax) {
5275           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*4 + r;
5276         } else {
5277           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (support[s] - fMax);
5278         }
5279       }
5280       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5281 #if 1
5282       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5283       for (p = 0; p < 2+size; ++p) {
5284         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);
5285       }
5286 #endif
5287     }
5288     /* Interior face vertices have 4 + cells supports */
5289     for (f = fStart; f < fMax; ++f) {
5290       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
5291       const PetscInt *cone, *support;
5292       PetscInt        size, s;
5293 
5294       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5295       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5296       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eMax - eStart)*2 +  (f - fStart)*4 + r;
5297       for (s = 0; s < size; ++s) {
5298         PetscInt r;
5299 
5300         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5301         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
5302         if (support[s] < cMax) {
5303           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (support[s] - cStart)*6 + r;
5304         } else {
5305           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax       - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (support[s] - cMax);
5306         }
5307       }
5308       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5309 #if 1
5310       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5311       for (p = 0; p < 4+size; ++p) {
5312         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);
5313       }
5314 #endif
5315     }
5316     /* Cell vertices have 6 supports */
5317     for (c = cStart; c < cMax; ++c) {
5318       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
5319       PetscInt       supportNew[6];
5320 
5321       for (r = 0; r < 6; ++r) {
5322         supportNew[r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
5323       }
5324       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5325     }
5326     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5327     break;
5328   default:
5329     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5330   }
5331   PetscFunctionReturn(0);
5332 }
5333 
5334 #undef __FUNCT__
5335 #define __FUNCT__ "CellRefinerSetCoordinates"
5336 static PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5337 {
5338   PetscSection   coordSection, coordSectionNew;
5339   Vec            coordinates, coordinatesNew;
5340   PetscScalar   *coords, *coordsNew;
5341   const PetscInt numVertices = depthSize ? depthSize[0] : 0;
5342   PetscInt       dim, depth, bs, coordSizeNew, cStart, cEnd, cMax, c, vStart, vStartNew, vEnd, v, eStart, eEnd, eMax, e, fStart, fEnd, fMax, f;
5343   PetscErrorCode ierr;
5344 
5345   PetscFunctionBegin;
5346   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5347   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5348   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5349   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5350   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5351   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5352   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, NULL);CHKERRQ(ierr);
5353   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);}
5354   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
5355   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5356   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
5357   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
5358   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
5359   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+numVertices);CHKERRQ(ierr);
5360   if (cMax < 0) cMax = cEnd;
5361   if (fMax < 0) fMax = fEnd;
5362   if (eMax < 0) eMax = eEnd;
5363   /* All vertices have the dim coordinates */
5364   for (v = vStartNew; v < vStartNew+numVertices; ++v) {
5365     ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
5366     ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
5367   }
5368   ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
5369   ierr = DMSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
5370   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5371   ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
5372   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);CHKERRQ(ierr);
5373   ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
5374   ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
5375   ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr);
5376   ierr = VecSetBlockSize(coordinatesNew, bs);CHKERRQ(ierr);
5377   ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
5378   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
5379   ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5380   switch (refiner) {
5381   case 0: break;
5382   case 6: /* Hex 3D */
5383   case 8: /* Hybrid Hex 3D */
5384     /* Face vertices have the average of corner coordinates */
5385     for (f = fStart; f < fMax; ++f) {
5386       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
5387       PetscInt      *cone = NULL;
5388       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
5389 
5390       ierr = DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5391       for (p = 0; p < closureSize*2; p += 2) {
5392         const PetscInt point = cone[p];
5393         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
5394       }
5395       for (v = 0; v < coneSize; ++v) {
5396         ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
5397       }
5398       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5399       for (d = 0; d < dim; ++d) coordsNew[offnew+d] = 0.0;
5400       for (v = 0; v < coneSize; ++v) {ierr = DMPlexLocalizeAddCoordinate_Internal(dm, dim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);CHKERRQ(ierr);}
5401       for (d = 0; d < dim; ++d) coordsNew[offnew+d] /= coneSize;
5402       ierr = DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5403     }
5404   case 2: /* Hex 2D */
5405   case 4: /* Hybrid Hex 2D */
5406     /* Cell vertices have the average of corner coordinates */
5407     for (c = cStart; c < cMax; ++c) {
5408       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (c - cStart) + (dim > 2 ? (fMax - fStart) : 0);
5409       PetscInt      *cone = NULL;
5410       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
5411 
5412       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5413       for (p = 0; p < closureSize*2; p += 2) {
5414         const PetscInt point = cone[p];
5415         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
5416       }
5417       for (v = 0; v < coneSize; ++v) {
5418         ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
5419       }
5420       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5421       for (d = 0; d < dim; ++d) coordsNew[offnew+d] = 0.0;
5422       for (v = 0; v < coneSize; ++v) {ierr = DMPlexLocalizeAddCoordinate_Internal(dm, dim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);CHKERRQ(ierr);}
5423       for (d = 0; d < dim; ++d) coordsNew[offnew+d] /= coneSize;
5424       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5425     }
5426   case 1: /* Simplicial 2D */
5427   case 3: /* Hybrid Simplicial 2D */
5428   case 5: /* Simplicial 3D */
5429   case 7: /* Hybrid Simplicial 3D */
5430     /* Edge vertices have the average of endpoint coordinates */
5431     for (e = eStart; e < eMax; ++e) {
5432       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
5433       const PetscInt *cone;
5434       PetscInt        coneSize, offA, offB, offnew, d;
5435 
5436       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
5437       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
5438       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
5439       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
5440       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
5441       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5442       ierr = DMPlexLocalizeCoordinate_Internal(dm, dim, &coords[offA], &coords[offB], &coordsNew[offnew]);CHKERRQ(ierr);
5443       for (d = 0; d < dim; ++d) {
5444         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coordsNew[offnew+d]);
5445       }
5446     }
5447     /* Old vertices have the same coordinates */
5448     for (v = vStart; v < vEnd; ++v) {
5449       const PetscInt newv = vStartNew + (v - vStart);
5450       PetscInt       off, offnew, d;
5451 
5452       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5453       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5454       for (d = 0; d < dim; ++d) {
5455         coordsNew[offnew+d] = coords[off+d];
5456       }
5457     }
5458     break;
5459   default:
5460     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5461   }
5462   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
5463   ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5464   ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
5465   ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
5466   ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
5467   if (dm->maxCell) {
5468     const PetscReal *maxCell, *L;
5469     ierr = DMGetPeriodicity(dm,  &maxCell, &L);CHKERRQ(ierr);
5470     ierr = DMSetPeriodicity(rdm,  maxCell,  L);CHKERRQ(ierr);
5471   }
5472   PetscFunctionReturn(0);
5473 }
5474 
5475 #undef __FUNCT__
5476 #define __FUNCT__ "DMPlexCreateProcessSF"
5477 static PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
5478 {
5479   PetscInt           numRoots, numLeaves, l;
5480   const PetscInt    *localPoints;
5481   const PetscSFNode *remotePoints;
5482   PetscInt          *localPointsNew;
5483   PetscSFNode       *remotePointsNew;
5484   PetscInt          *ranks, *ranksNew;
5485   PetscErrorCode     ierr;
5486 
5487   PetscFunctionBegin;
5488   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5489   ierr = PetscMalloc1(numLeaves, &ranks);CHKERRQ(ierr);
5490   for (l = 0; l < numLeaves; ++l) {
5491     ranks[l] = remotePoints[l].rank;
5492   }
5493   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
5494   ierr = PetscMalloc1(numLeaves,    &ranksNew);CHKERRQ(ierr);
5495   ierr = PetscMalloc1(numLeaves,    &localPointsNew);CHKERRQ(ierr);
5496   ierr = PetscMalloc1(numLeaves, &remotePointsNew);CHKERRQ(ierr);
5497   for (l = 0; l < numLeaves; ++l) {
5498     ranksNew[l]              = ranks[l];
5499     localPointsNew[l]        = l;
5500     remotePointsNew[l].index = 0;
5501     remotePointsNew[l].rank  = ranksNew[l];
5502   }
5503   ierr = PetscFree(ranks);CHKERRQ(ierr);
5504   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
5505   ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
5506   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
5507   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
5508   PetscFunctionReturn(0);
5509 }
5510 
5511 #undef __FUNCT__
5512 #define __FUNCT__ "CellRefinerCreateSF"
5513 static PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5514 {
5515   PetscSF            sf, sfNew, sfProcess;
5516   IS                 processRanks;
5517   MPI_Datatype       depthType;
5518   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
5519   const PetscInt    *localPoints, *neighbors;
5520   const PetscSFNode *remotePoints;
5521   PetscInt          *localPointsNew;
5522   PetscSFNode       *remotePointsNew;
5523   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
5524   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r, n;
5525   PetscInt           cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
5526   PetscErrorCode     ierr;
5527 
5528   PetscFunctionBegin;
5529   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
5530   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5531   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5532   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5533   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5534   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5535   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5536   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
5537   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
5538   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
5539   /* Caculate size of new SF */
5540   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5541   if (numRoots < 0) PetscFunctionReturn(0);
5542   for (l = 0; l < numLeaves; ++l) {
5543     const PetscInt p = localPoints[l];
5544 
5545     switch (refiner) {
5546     case 1:
5547       /* Simplicial 2D */
5548       if ((p >= vStart) && (p < vEnd)) {
5549         /* Old vertices stay the same */
5550         ++numLeavesNew;
5551       } else if ((p >= fStart) && (p < fEnd)) {
5552         /* Old faces add new faces and vertex */
5553         numLeavesNew += 2 + 1;
5554       } else if ((p >= cStart) && (p < cEnd)) {
5555         /* Old cells add new cells and interior faces */
5556         numLeavesNew += 4 + 3;
5557       }
5558       break;
5559     case 3:
5560       /* Hybrid Simplicial 2D */
5561       if ((p >= vStart) && (p < vEnd)) {
5562         /* Interior vertices stay the same */
5563         ++numLeavesNew;
5564       } else if ((p >= fStart) && (p < fMax)) {
5565         /* Interior faces add new faces and vertex */
5566         numLeavesNew += 2 + 1;
5567       } else if ((p >= fMax) && (p < fEnd)) {
5568         /* Hybrid faces stay the same */
5569         ++numLeavesNew;
5570       } else if ((p >= cStart) && (p < cMax)) {
5571         /* Interior cells add new cells and interior faces */
5572         numLeavesNew += 4 + 3;
5573       } else if ((p >= cMax) && (p < cEnd)) {
5574         /* Hybrid cells add new cells and hybrid face */
5575         numLeavesNew += 2 + 1;
5576       }
5577       break;
5578     case 2:
5579       /* Hex 2D */
5580       if ((p >= vStart) && (p < vEnd)) {
5581         /* Old vertices stay the same */
5582         ++numLeavesNew;
5583       } else if ((p >= fStart) && (p < fEnd)) {
5584         /* Old faces add new faces and vertex */
5585         numLeavesNew += 2 + 1;
5586       } else if ((p >= cStart) && (p < cEnd)) {
5587         /* Old cells add new cells, interior faces, and vertex */
5588         numLeavesNew += 4 + 4 + 1;
5589       }
5590       break;
5591     case 4:
5592       /* Hybrid Hex 2D */
5593       if ((p >= vStart) && (p < vEnd)) {
5594         /* Interior vertices stay the same */
5595         ++numLeavesNew;
5596       } else if ((p >= fStart) && (p < fMax)) {
5597         /* Interior faces add new faces and vertex */
5598         numLeavesNew += 2 + 1;
5599       } else if ((p >= fMax) && (p < fEnd)) {
5600         /* Hybrid faces stay the same */
5601         ++numLeavesNew;
5602       } else if ((p >= cStart) && (p < cMax)) {
5603         /* Interior cells add new cells, interior faces, and vertex */
5604         numLeavesNew += 4 + 4 + 1;
5605       } else if ((p >= cMax) && (p < cEnd)) {
5606         /* Hybrid cells add new cells and hybrid face */
5607         numLeavesNew += 2 + 1;
5608       }
5609       break;
5610     case 5:
5611       /* Simplicial 3D */
5612       if ((p >= vStart) && (p < vEnd)) {
5613         /* Old vertices stay the same */
5614         ++numLeavesNew;
5615       } else if ((p >= eStart) && (p < eEnd)) {
5616         /* Old edges add new edges and vertex */
5617         numLeavesNew += 2 + 1;
5618       } else if ((p >= fStart) && (p < fEnd)) {
5619         /* Old faces add new faces and face edges */
5620         numLeavesNew += 4 + 3;
5621       } else if ((p >= cStart) && (p < cEnd)) {
5622         /* Old cells add new cells and interior faces and edges */
5623         numLeavesNew += 8 + 8 + 1;
5624       }
5625       break;
5626     case 7:
5627       /* Hybrid Simplicial 3D */
5628       if ((p >= vStart) && (p < vEnd)) {
5629         /* Interior vertices stay the same */
5630         ++numLeavesNew;
5631       } else if ((p >= eStart) && (p < eMax)) {
5632         /* Interior edges add new edges and vertex */
5633         numLeavesNew += 2 + 1;
5634       } else if ((p >= eMax) && (p < eEnd)) {
5635         /* Hybrid edges stay the same */
5636         ++numLeavesNew;
5637       } else if ((p >= fStart) && (p < fMax)) {
5638         /* Interior faces add new faces and edges */
5639         numLeavesNew += 4 + 3;
5640       } else if ((p >= fMax) && (p < fEnd)) {
5641         /* Hybrid faces add new faces and edges */
5642         numLeavesNew += 2 + 1;
5643       } else if ((p >= cStart) && (p < cMax)) {
5644         /* Interior cells add new cells, faces, and edges */
5645         numLeavesNew += 8 + 8 + 1;
5646       } else if ((p >= cMax) && (p < cEnd)) {
5647         /* Hybrid cells add new cells and faces */
5648         numLeavesNew += 4 + 3;
5649       }
5650       break;
5651     case 6:
5652       /* Hex 3D */
5653       if ((p >= vStart) && (p < vEnd)) {
5654         /* Old vertices stay the same */
5655         ++numLeavesNew;
5656       } else if ((p >= eStart) && (p < eEnd)) {
5657         /* Old edges add new edges, and vertex */
5658         numLeavesNew += 2 + 1;
5659       } else if ((p >= fStart) && (p < fEnd)) {
5660         /* Old faces add new faces, edges, and vertex */
5661         numLeavesNew += 4 + 4 + 1;
5662       } else if ((p >= cStart) && (p < cEnd)) {
5663         /* Old cells add new cells, faces, edges, and vertex */
5664         numLeavesNew += 8 + 12 + 6 + 1;
5665       }
5666       break;
5667     case 8:
5668       /* Hybrid Hex 3D */
5669       if ((p >= vStart) && (p < vEnd)) {
5670         /* Old vertices stay the same */
5671         ++numLeavesNew;
5672       } else if ((p >= eStart) && (p < eMax)) {
5673         /* Interior edges add new edges, and vertex */
5674         numLeavesNew += 2 + 1;
5675       } else if ((p >= eMax) && (p < eEnd)) {
5676         /* Hybrid edges stay the same */
5677         ++numLeavesNew;
5678       } else if ((p >= fStart) && (p < fMax)) {
5679         /* Interior faces add new faces, edges, and vertex */
5680         numLeavesNew += 4 + 4 + 1;
5681       } else if ((p >= fMax) && (p < fEnd)) {
5682         /* Hybrid faces add new faces and edges */
5683         numLeavesNew += 2 + 1;
5684       } else if ((p >= cStart) && (p < cMax)) {
5685         /* Interior cells add new cells, faces, edges, and vertex */
5686         numLeavesNew += 8 + 12 + 6 + 1;
5687       } else if ((p >= cStart) && (p < cEnd)) {
5688         /* Hybrid cells add new cells, faces, and edges */
5689         numLeavesNew += 4 + 4 + 1;
5690       }
5691       break;
5692     default:
5693       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5694     }
5695   }
5696   /* Communicate depthSizes for each remote rank */
5697   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
5698   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
5699   ierr = PetscMalloc5((depth+1)*numNeighbors,&rdepthSize,numNeighbors,&rvStartNew,numNeighbors,&reStartNew,numNeighbors,&rfStartNew,numNeighbors,&rcStartNew);CHKERRQ(ierr);
5700   ierr = PetscMalloc7(depth+1,&depthSizeOld,(depth+1)*numNeighbors,&rdepthSizeOld,(depth+1)*numNeighbors,&rdepthMaxOld,numNeighbors,&rvStart,numNeighbors,&reStart,numNeighbors,&rfStart,numNeighbors,&rcStart);CHKERRQ(ierr);
5701   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
5702   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
5703   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5704   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5705   for (n = 0; n < numNeighbors; ++n) {
5706     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
5707   }
5708   depthSizeOld[depth]   = cMax;
5709   depthSizeOld[0]       = vMax;
5710   depthSizeOld[depth-1] = fMax;
5711   depthSizeOld[1]       = eMax;
5712 
5713   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5714   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5715 
5716   depthSizeOld[depth]   = cEnd - cStart;
5717   depthSizeOld[0]       = vEnd - vStart;
5718   depthSizeOld[depth-1] = fEnd - fStart;
5719   depthSizeOld[1]       = eEnd - eStart;
5720 
5721   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5722   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5723   for (n = 0; n < numNeighbors; ++n) {
5724     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
5725   }
5726   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
5727   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
5728   /* Calculate new point SF */
5729   ierr = PetscMalloc1(numLeavesNew,    &localPointsNew);CHKERRQ(ierr);
5730   ierr = PetscMalloc1(numLeavesNew, &remotePointsNew);CHKERRQ(ierr);
5731   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
5732   for (l = 0, m = 0; l < numLeaves; ++l) {
5733     PetscInt    p     = localPoints[l];
5734     PetscInt    rp    = remotePoints[l].index, n;
5735     PetscMPIInt rrank = remotePoints[l].rank;
5736 
5737     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
5738     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
5739     switch (refiner) {
5740     case 1:
5741       /* Simplicial 2D */
5742       if ((p >= vStart) && (p < vEnd)) {
5743         /* Old vertices stay the same */
5744         localPointsNew[m]        = vStartNew     + (p  - vStart);
5745         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5746         remotePointsNew[m].rank  = rrank;
5747         ++m;
5748       } else if ((p >= fStart) && (p < fEnd)) {
5749         /* Old faces add new faces and vertex */
5750         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5751         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5752         remotePointsNew[m].rank  = rrank;
5753         ++m;
5754         for (r = 0; r < 2; ++r, ++m) {
5755           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5756           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5757           remotePointsNew[m].rank  = rrank;
5758         }
5759       } else if ((p >= cStart) && (p < cEnd)) {
5760         /* Old cells add new cells and interior faces */
5761         for (r = 0; r < 4; ++r, ++m) {
5762           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5763           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5764           remotePointsNew[m].rank  = rrank;
5765         }
5766         for (r = 0; r < 3; ++r, ++m) {
5767           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
5768           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
5769           remotePointsNew[m].rank  = rrank;
5770         }
5771       }
5772       break;
5773     case 2:
5774       /* Hex 2D */
5775       if ((p >= vStart) && (p < vEnd)) {
5776         /* Old vertices stay the same */
5777         localPointsNew[m]        = vStartNew     + (p  - vStart);
5778         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5779         remotePointsNew[m].rank  = rrank;
5780         ++m;
5781       } else if ((p >= fStart) && (p < fEnd)) {
5782         /* Old faces add new faces and vertex */
5783         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5784         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5785         remotePointsNew[m].rank  = rrank;
5786         ++m;
5787         for (r = 0; r < 2; ++r, ++m) {
5788           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5789           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5790           remotePointsNew[m].rank  = rrank;
5791         }
5792       } else if ((p >= cStart) && (p < cEnd)) {
5793         /* Old cells add new cells, interior faces, and vertex */
5794         for (r = 0; r < 4; ++r, ++m) {
5795           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5796           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5797           remotePointsNew[m].rank  = rrank;
5798         }
5799         for (r = 0; r < 4; ++r, ++m) {
5800           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
5801           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
5802           remotePointsNew[m].rank  = rrank;
5803         }
5804         for (r = 0; r < 1; ++r, ++m) {
5805           localPointsNew[m]        = vStartNew     + (vEnd - vStart)               + (fEnd - fStart)                    + (p  - cStart)     + r;
5806           remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0]  + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]) + r;
5807           remotePointsNew[m].rank  = rrank;
5808         }
5809       }
5810       break;
5811     case 3:
5812       /* Hybrid simplicial 2D */
5813       if ((p >= vStart) && (p < vEnd)) {
5814         /* Old vertices stay the same */
5815         localPointsNew[m]        = vStartNew     + (p  - vStart);
5816         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5817         remotePointsNew[m].rank  = rrank;
5818         ++m;
5819       } else if ((p >= fStart) && (p < fMax)) {
5820         /* Old interior faces add new faces and vertex */
5821         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5822         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5823         remotePointsNew[m].rank  = rrank;
5824         ++m;
5825         for (r = 0; r < 2; ++r, ++m) {
5826           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5827           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5828           remotePointsNew[m].rank  = rrank;
5829         }
5830       } else if ((p >= fMax) && (p < fEnd)) {
5831         /* Old hybrid faces stay the same */
5832         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
5833         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
5834         remotePointsNew[m].rank  = rrank;
5835         ++m;
5836       } else if ((p >= cStart) && (p < cMax)) {
5837         /* Old interior cells add new cells and interior faces */
5838         for (r = 0; r < 4; ++r, ++m) {
5839           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5840           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5841           remotePointsNew[m].rank  = rrank;
5842         }
5843         for (r = 0; r < 3; ++r, ++m) {
5844           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
5845           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
5846           remotePointsNew[m].rank  = rrank;
5847         }
5848       } else if ((p >= cStart) && (p < cMax)) {
5849         /* Old hybrid cells add new cells and hybrid face */
5850         for (r = 0; r < 2; ++r, ++m) {
5851           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5852           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5853           remotePointsNew[m].rank  = rrank;
5854         }
5855         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
5856         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]);
5857         remotePointsNew[m].rank  = rrank;
5858         ++m;
5859       }
5860       break;
5861     case 4:
5862       /* Hybrid Hex 2D */
5863       if ((p >= vStart) && (p < vEnd)) {
5864         /* Old vertices stay the same */
5865         localPointsNew[m]        = vStartNew     + (p  - vStart);
5866         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5867         remotePointsNew[m].rank  = rrank;
5868         ++m;
5869       } else if ((p >= fStart) && (p < fMax)) {
5870         /* Old interior faces add new faces and vertex */
5871         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5872         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5873         remotePointsNew[m].rank  = rrank;
5874         ++m;
5875         for (r = 0; r < 2; ++r, ++m) {
5876           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5877           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5878           remotePointsNew[m].rank  = rrank;
5879         }
5880       } else if ((p >= fMax) && (p < fEnd)) {
5881         /* Old hybrid faces stay the same */
5882         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
5883         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
5884         remotePointsNew[m].rank  = rrank;
5885         ++m;
5886       } else if ((p >= cStart) && (p < cMax)) {
5887         /* Old interior cells add new cells, interior faces, and vertex */
5888         localPointsNew[m]        = vStartNew     + (vEnd - vStart)               + (fEnd - fStart)                    + (p  - cStart);
5889         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0]  + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
5890         remotePointsNew[m].rank  = rrank;
5891         ++m;
5892         for (r = 0; r < 4; ++r, ++m) {
5893           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5894           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5895           remotePointsNew[m].rank  = rrank;
5896         }
5897         for (r = 0; r < 4; ++r, ++m) {
5898           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*4     + r;
5899           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*4 + r;
5900           remotePointsNew[m].rank  = rrank;
5901         }
5902       } else if ((p >= cStart) && (p < cMax)) {
5903         /* Old hybrid cells add new cells and hybrid face */
5904         for (r = 0; r < 2; ++r, ++m) {
5905           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5906           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5907           remotePointsNew[m].rank  = rrank;
5908         }
5909         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*4     + (p  - cMax);
5910         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]);
5911         remotePointsNew[m].rank  = rrank;
5912         ++m;
5913       }
5914       break;
5915     case 5:
5916       /* Simplicial 3D */
5917       if ((p >= vStart) && (p < vEnd)) {
5918         /* Old vertices stay the same */
5919         localPointsNew[m]        = vStartNew     + (p  - vStart);
5920         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5921         remotePointsNew[m].rank  = rrank;
5922         ++m;
5923       } else if ((p >= eStart) && (p < eEnd)) {
5924         /* Old edges add new edges and vertex */
5925         for (r = 0; r < 2; ++r, ++m) {
5926           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
5927           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
5928           remotePointsNew[m].rank  = rrank;
5929         }
5930         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
5931         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
5932         remotePointsNew[m].rank  = rrank;
5933         ++m;
5934       } else if ((p >= fStart) && (p < fEnd)) {
5935         /* Old faces add new faces and face edges */
5936         for (r = 0; r < 4; ++r, ++m) {
5937           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
5938           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
5939           remotePointsNew[m].rank  = rrank;
5940         }
5941         for (r = 0; r < 3; ++r, ++m) {
5942           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (p  - fStart)*3     + r;
5943           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + (rp - rfStart[n])*3 + r;
5944           remotePointsNew[m].rank  = rrank;
5945         }
5946       } else if ((p >= cStart) && (p < cEnd)) {
5947         /* Old cells add new cells and interior faces and edges */
5948         for (r = 0; r < 8; ++r, ++m) {
5949           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
5950           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
5951           remotePointsNew[m].rank  = rrank;
5952         }
5953         for (r = 0; r < 8; ++r, ++m) {
5954           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*4                    + (p  - cStart)*8     + r;
5955           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*4 + (rp - rcStart[n])*8 + r;
5956           remotePointsNew[m].rank  = rrank;
5957         }
5958         for (r = 0; r < 1; ++r, ++m) {
5959           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (fEnd - fStart)*3                    + (p  - cStart)*1     + r;
5960           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + rdepthSizeOld[n*(depth+1)+depth-1]*3 + (rp - rcStart[n])*1 + r;
5961           remotePointsNew[m].rank  = rrank;
5962         }
5963       }
5964       break;
5965     case 7:
5966       /* Hybrid Simplicial 3D */
5967       if ((p >= vStart) && (p < vEnd)) {
5968         /* Interior vertices stay the same */
5969         localPointsNew[m]        = vStartNew     + (p  - vStart);
5970         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5971         remotePointsNew[m].rank  = rrank;
5972         ++m;
5973       } else if ((p >= eStart) && (p < eMax)) {
5974         /* Interior edges add new edges and vertex */
5975         for (r = 0; r < 2; ++r, ++m) {
5976           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
5977           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
5978           remotePointsNew[m].rank  = rrank;
5979         }
5980         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
5981         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
5982         remotePointsNew[m].rank  = rrank;
5983         ++m;
5984       } else if ((p >= eMax) && (p < eEnd)) {
5985         /* Hybrid edges stay the same */
5986         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - eMax);
5987         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]);
5988         remotePointsNew[m].rank  = rrank;
5989         ++m;
5990       } else if ((p >= fStart) && (p < fMax)) {
5991         /* Interior faces add new faces and edges */
5992         for (r = 0; r < 4; ++r, ++m) {
5993           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
5994           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
5995           remotePointsNew[m].rank  = rrank;
5996         }
5997         for (r = 0; r < 3; ++r, ++m) {
5998           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*3     + r;
5999           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
6000           remotePointsNew[m].rank  = rrank;
6001         }
6002       } else if ((p >= fMax) && (p < fEnd)) {
6003         /* Hybrid faces add new faces and edges */
6004         for (r = 0; r < 2; ++r, ++m) {
6005           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fMax)*2                              + r;
6006           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;
6007           remotePointsNew[m].rank  = rrank;
6008         }
6009         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (eEnd                                    - eMax)                        + (p  - fMax);
6010         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]);
6011         remotePointsNew[m].rank  = rrank;
6012         ++m;
6013       } else if ((p >= cStart) && (p < cMax)) {
6014         /* Interior cells add new cells, faces, and edges */
6015         for (r = 0; r < 8; ++r, ++m) {
6016           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
6017           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
6018           remotePointsNew[m].rank  = rrank;
6019         }
6020         for (r = 0; r < 8; ++r, ++m) {
6021           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*8     + r;
6022           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*8 + r;
6023           remotePointsNew[m].rank  = rrank;
6024         }
6025         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (p  - cStart)*1     + r;
6026         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;
6027         remotePointsNew[m].rank  = rrank;
6028         ++m;
6029       } else if ((p >= cMax) && (p < cEnd)) {
6030         /* Hybrid cells add new cells and faces */
6031         for (r = 0; r < 4; ++r, ++m) {
6032           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
6033           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
6034           remotePointsNew[m].rank  = rrank;
6035         }
6036         for (r = 0; r < 3; ++r, ++m) {
6037           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*2                              + (p  - cMax)*3                            + r;
6038           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;
6039           remotePointsNew[m].rank  = rrank;
6040         }
6041       }
6042       break;
6043     case 6:
6044       /* Hex 3D */
6045       if ((p >= vStart) && (p < vEnd)) {
6046         /* Old vertices stay the same */
6047         localPointsNew[m]        = vStartNew     + (p  - vStart);
6048         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6049         remotePointsNew[m].rank  = rrank;
6050         ++m;
6051       } else if ((p >= eStart) && (p < eEnd)) {
6052         /* Old edges add new edges and vertex */
6053         for (r = 0; r < 2; ++r, ++m) {
6054           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
6055           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
6056           remotePointsNew[m].rank  = rrank;
6057         }
6058         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
6059         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
6060         remotePointsNew[m].rank  = rrank;
6061         ++m;
6062       } else if ((p >= fStart) && (p < fEnd)) {
6063         /* Old faces add new faces, edges, and vertex */
6064         for (r = 0; r < 4; ++r, ++m) {
6065           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
6066           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
6067           remotePointsNew[m].rank  = rrank;
6068         }
6069         for (r = 0; r < 4; ++r, ++m) {
6070           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (p  - fStart)*4     + r;
6071           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + (rp - rfStart[n])*4 + r;
6072           remotePointsNew[m].rank  = rrank;
6073         }
6074         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eEnd - eStart)              + (p  - fStart);
6075         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+1] + (rp - rfStart[n]);
6076         remotePointsNew[m].rank  = rrank;
6077         ++m;
6078       } else if ((p >= cStart) && (p < cEnd)) {
6079         /* Old cells add new cells, faces, edges, and vertex */
6080         for (r = 0; r < 8; ++r, ++m) {
6081           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
6082           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
6083           remotePointsNew[m].rank  = rrank;
6084         }
6085         for (r = 0; r < 12; ++r, ++m) {
6086           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*4                    + (p  - cStart)*12     + r;
6087           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*4 + (rp - rcStart[n])*12 + r;
6088           remotePointsNew[m].rank  = rrank;
6089         }
6090         for (r = 0; r < 6; ++r, ++m) {
6091           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (fEnd - fStart)*4                    + (p  - cStart)*6     + r;
6092           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + rdepthSizeOld[n*(depth+1)+depth-1]*4 + (rp - rcStart[n])*6 + r;
6093           remotePointsNew[m].rank  = rrank;
6094         }
6095         for (r = 0; r < 1; ++r, ++m) {
6096           localPointsNew[m]        = vStartNew     + (eEnd - eStart)              + (fEnd - fStart)                    + (p  - cStart)     + r;
6097           remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+1] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]) + r;
6098           remotePointsNew[m].rank  = rrank;
6099         }
6100       }
6101       break;
6102     case 8:
6103       /* Hybrid Hex 3D */
6104       if ((p >= vStart) && (p < vEnd)) {
6105         /* Interior vertices stay the same */
6106         localPointsNew[m]        = vStartNew     + (p  - vStart);
6107         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6108         remotePointsNew[m].rank  = rrank;
6109         ++m;
6110       } else if ((p >= eStart) && (p < eMax)) {
6111         /* Interior edges add new edges and vertex */
6112         for (r = 0; r < 2; ++r, ++m) {
6113           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
6114           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
6115           remotePointsNew[m].rank  = rrank;
6116         }
6117         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
6118         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
6119         remotePointsNew[m].rank  = rrank;
6120         ++m;
6121       } else if ((p >= eMax) && (p < eEnd)) {
6122         /* Hybrid edges stay the same */
6123         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (p  - eMax);
6124         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]);
6125         remotePointsNew[m].rank  = rrank;
6126         ++m;
6127       } else if ((p >= fStart) && (p < fMax)) {
6128         /* Interior faces add new faces, edges, and vertex */
6129         for (r = 0; r < 4; ++r, ++m) {
6130           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
6131           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
6132           remotePointsNew[m].rank  = rrank;
6133         }
6134         for (r = 0; r < 4; ++r, ++m) {
6135           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*4     + r;
6136           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*4 + r;
6137           remotePointsNew[m].rank  = rrank;
6138         }
6139         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax                        - eStart)     + (p  - fStart);
6140         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
6141         remotePointsNew[m].rank  = rrank;
6142         ++m;
6143       } else if ((p >= fMax) && (p < fEnd)) {
6144         /* Hybrid faces add new faces and edges */
6145         for (r = 0; r < 2; ++r, ++m) {
6146           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fMax)*2                              + r;
6147           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;
6148           remotePointsNew[m].rank  = rrank;
6149         }
6150         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (fEnd                                          - fMax);
6151         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]);
6152         remotePointsNew[m].rank  = rrank;
6153         ++m;
6154       } else if ((p >= cStart) && (p < cMax)) {
6155         /* Interior cells add new cells, faces, edges, and vertex */
6156         for (r = 0; r < 8; ++r, ++m) {
6157           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
6158           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
6159           remotePointsNew[m].rank  = rrank;
6160         }
6161         for (r = 0; r < 12; ++r, ++m) {
6162           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*12     + r;
6163           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*12 + r;
6164           remotePointsNew[m].rank  = rrank;
6165         }
6166         for (r = 0; r < 6; ++r, ++m) {
6167           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (p  - cStart)*6     + r;
6168           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;
6169           remotePointsNew[m].rank  = rrank;
6170         }
6171         for (r = 0; r < 1; ++r, ++m) {
6172           localPointsNew[m]        = vStartNew     + (eMax                        - eStart)     + (fMax                              - fStart)     + (p  - cStart)     + r;
6173           remotePointsNew[m].index = rvStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]) + r;
6174           remotePointsNew[m].rank  = rrank;
6175         }
6176       } else if ((p >= cMax) && (p < cEnd)) {
6177         /* Hybrid cells add new cells, faces, and edges */
6178         for (r = 0; r < 4; ++r, ++m) {
6179           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
6180           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
6181           remotePointsNew[m].rank  = rrank;
6182         }
6183         for (r = 0; r < 4; ++r, ++m) {
6184           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*2                              + (p  - cMax)*4                            + r;
6185           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;
6186           remotePointsNew[m].rank  = rrank;
6187         }
6188         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (fEnd                                          - fMax)                              + (p  - cMax);
6189         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]);
6190         remotePointsNew[m].rank  = rrank;
6191         ++m;
6192       }
6193       break;
6194     default:
6195       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6196     }
6197   }
6198   if (m != numLeavesNew) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of leaf point %d should be %d", m, numLeavesNew);
6199   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
6200   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
6201   {
6202     PetscSFNode *rp, *rtmp;
6203     PetscInt    *lp, *idx, *ltmp, i;
6204 
6205     /* SF needs sorted leaves to correct calculate Gather */
6206     ierr = PetscMalloc1(numLeavesNew,&idx);CHKERRQ(ierr);
6207     ierr = PetscMalloc1(numLeavesNew, &lp);CHKERRQ(ierr);
6208     ierr = PetscMalloc1(numLeavesNew, &rp);CHKERRQ(ierr);
6209     for (i = 0; i < numLeavesNew; ++i) idx[i] = i;
6210     ierr = PetscSortIntWithPermutation(numLeavesNew, localPointsNew, idx);CHKERRQ(ierr);
6211     for (i = 0; i < numLeavesNew; ++i) {
6212       lp[i] = localPointsNew[idx[i]];
6213       rp[i] = remotePointsNew[idx[i]];
6214     }
6215     ltmp            = localPointsNew;
6216     localPointsNew  = lp;
6217     rtmp            = remotePointsNew;
6218     remotePointsNew = rp;
6219     ierr = PetscFree(idx);CHKERRQ(ierr);
6220     ierr = PetscFree(ltmp);CHKERRQ(ierr);
6221     ierr = PetscFree(rtmp);CHKERRQ(ierr);
6222   }
6223   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6224   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
6225   ierr = PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
6226   PetscFunctionReturn(0);
6227 }
6228 
6229 #undef __FUNCT__
6230 #define __FUNCT__ "CellRefinerCreateLabels"
6231 static PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6232 {
6233   PetscInt       numLabels, l;
6234   PetscInt       depth, newp, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r;
6235   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
6236   PetscErrorCode ierr;
6237 
6238   PetscFunctionBegin;
6239   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6240   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6241   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6242   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6243   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6244   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
6245   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
6246   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6247   switch (refiner) {
6248   case 0: break;
6249   case 7:
6250   case 8:
6251     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
6252   case 3:
6253   case 4:
6254     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6255     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6256   }
6257   for (l = 0; l < numLabels; ++l) {
6258     DMLabel         label, labelNew;
6259     const char     *lname;
6260     PetscBool       isDepth;
6261     IS              valueIS;
6262     const PetscInt *values;
6263     PetscInt        numValues, val;
6264 
6265     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
6266     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
6267     if (isDepth) continue;
6268     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
6269     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
6270     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
6271     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
6272     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
6273     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
6274     for (val = 0; val < numValues; ++val) {
6275       IS              pointIS;
6276       const PetscInt *points;
6277       PetscInt        numPoints, n;
6278 
6279       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
6280       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
6281       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
6282       for (n = 0; n < numPoints; ++n) {
6283         const PetscInt p = points[n];
6284         switch (refiner) {
6285         case 1:
6286           /* Simplicial 2D */
6287           if ((p >= vStart) && (p < vEnd)) {
6288             /* Old vertices stay the same */
6289             newp = vStartNew + (p - vStart);
6290             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6291           } else if ((p >= fStart) && (p < fEnd)) {
6292             /* Old faces add new faces and vertex */
6293             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6294             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6295             for (r = 0; r < 2; ++r) {
6296               newp = fStartNew + (p - fStart)*2 + r;
6297               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6298             }
6299           } else if ((p >= cStart) && (p < cEnd)) {
6300             /* Old cells add new cells and interior faces */
6301             for (r = 0; r < 4; ++r) {
6302               newp = cStartNew + (p - cStart)*4 + r;
6303               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6304             }
6305             for (r = 0; r < 3; ++r) {
6306               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6307               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6308             }
6309           }
6310           break;
6311         case 2:
6312           /* Hex 2D */
6313           if ((p >= vStart) && (p < vEnd)) {
6314             /* Old vertices stay the same */
6315             newp = vStartNew + (p - vStart);
6316             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6317           } else if ((p >= fStart) && (p < fEnd)) {
6318             /* Old faces add new faces and vertex */
6319             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6320             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6321             for (r = 0; r < 2; ++r) {
6322               newp = fStartNew + (p - fStart)*2 + r;
6323               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6324             }
6325           } else if ((p >= cStart) && (p < cEnd)) {
6326             /* Old cells add new cells and interior faces and vertex */
6327             for (r = 0; r < 4; ++r) {
6328               newp = cStartNew + (p - cStart)*4 + r;
6329               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6330             }
6331             for (r = 0; r < 4; ++r) {
6332               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
6333               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6334             }
6335             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
6336             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6337           }
6338           break;
6339         case 3:
6340           /* Hybrid simplicial 2D */
6341           if ((p >= vStart) && (p < vEnd)) {
6342             /* Old vertices stay the same */
6343             newp = vStartNew + (p - vStart);
6344             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6345           } else if ((p >= fStart) && (p < fMax)) {
6346             /* Old interior faces add new faces and vertex */
6347             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6348             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6349             for (r = 0; r < 2; ++r) {
6350               newp = fStartNew + (p - fStart)*2 + r;
6351               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6352             }
6353           } else if ((p >= fMax) && (p < fEnd)) {
6354             /* Old hybrid faces stay the same */
6355             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
6356             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6357           } else if ((p >= cStart) && (p < cMax)) {
6358             /* Old interior cells add new cells and interior faces */
6359             for (r = 0; r < 4; ++r) {
6360               newp = cStartNew + (p - cStart)*4 + r;
6361               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6362             }
6363             for (r = 0; r < 3; ++r) {
6364               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6365               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6366             }
6367           } else if ((p >= cMax) && (p < cEnd)) {
6368             /* Old hybrid cells add new cells and hybrid face */
6369             for (r = 0; r < 2; ++r) {
6370               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
6371               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6372             }
6373             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
6374             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6375           }
6376           break;
6377         case 4:
6378           /* Hybrid Hex 2D */
6379           if ((p >= vStart) && (p < vEnd)) {
6380             /* Old vertices stay the same */
6381             newp = vStartNew + (p - vStart);
6382             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6383           } else if ((p >= fStart) && (p < fMax)) {
6384             /* Old interior faces add new faces and vertex */
6385             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6386             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6387             for (r = 0; r < 2; ++r) {
6388               newp = fStartNew + (p - fStart)*2 + r;
6389               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6390             }
6391           } else if ((p >= fMax) && (p < fEnd)) {
6392             /* Old hybrid faces stay the same */
6393             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
6394             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6395           } else if ((p >= cStart) && (p < cMax)) {
6396             /* Old interior cells add new cells, interior faces, and vertex */
6397             for (r = 0; r < 4; ++r) {
6398               newp = cStartNew + (p - cStart)*4 + r;
6399               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6400             }
6401             for (r = 0; r < 4; ++r) {
6402               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
6403               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6404             }
6405             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
6406             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6407           } else if ((p >= cMax) && (p < cEnd)) {
6408             /* Old hybrid cells add new cells and hybrid face */
6409             for (r = 0; r < 2; ++r) {
6410               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
6411               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6412             }
6413             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (p - cMax);
6414             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6415           }
6416           break;
6417         case 5:
6418           /* Simplicial 3D */
6419           if ((p >= vStart) && (p < vEnd)) {
6420             /* Old vertices stay the same */
6421             newp = vStartNew + (p - vStart);
6422             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6423           } else if ((p >= eStart) && (p < eEnd)) {
6424             /* Old edges add new edges and vertex */
6425             for (r = 0; r < 2; ++r) {
6426               newp = eStartNew + (p - eStart)*2 + r;
6427               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6428             }
6429             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6430             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6431           } else if ((p >= fStart) && (p < fEnd)) {
6432             /* Old faces add new faces and edges */
6433             for (r = 0; r < 4; ++r) {
6434               newp = fStartNew + (p - fStart)*4 + r;
6435               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6436             }
6437             for (r = 0; r < 3; ++r) {
6438               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
6439               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6440             }
6441           } else if ((p >= cStart) && (p < cEnd)) {
6442             /* Old cells add new cells and interior faces and edges */
6443             for (r = 0; r < 8; ++r) {
6444               newp = cStartNew + (p - cStart)*8 + r;
6445               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6446             }
6447             for (r = 0; r < 8; ++r) {
6448               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*8 + r;
6449               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6450             }
6451             for (r = 0; r < 1; ++r) {
6452               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*1 + r;
6453               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6454             }
6455           }
6456           break;
6457         case 7:
6458           /* Hybrid Simplicial 3D */
6459           if ((p >= vStart) && (p < vEnd)) {
6460             /* Interior vertices stay the same */
6461             newp = vStartNew + (p - vStart);
6462             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6463           } else if ((p >= eStart) && (p < eMax)) {
6464             /* Interior edges add new edges and vertex */
6465             for (r = 0; r < 2; ++r) {
6466               newp = eStartNew + (p - eStart)*2 + r;
6467               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6468             }
6469             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6470             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6471           } else if ((p >= eMax) && (p < eEnd)) {
6472             /* Hybrid edges stay the same */
6473             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - eMax);
6474             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6475           } else if ((p >= fStart) && (p < fMax)) {
6476             /* Interior faces add new faces and edges */
6477             for (r = 0; r < 4; ++r) {
6478               newp = fStartNew + (p - fStart)*4 + r;
6479               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6480             }
6481             for (r = 0; r < 3; ++r) {
6482               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
6483               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6484             }
6485           } else if ((p >= fMax) && (p < fEnd)) {
6486             /* Hybrid faces add new faces and edges */
6487             for (r = 0; r < 2; ++r) {
6488               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (p - fMax)*2 + r;
6489               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6490             }
6491             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - fMax);
6492             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6493           } else if ((p >= cStart) && (p < cMax)) {
6494             /* Interior cells add new cells, faces, and edges */
6495             for (r = 0; r < 8; ++r) {
6496               newp = cStartNew + (p - cStart)*8 + r;
6497               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6498             }
6499             for (r = 0; r < 8; ++r) {
6500               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*8 + r;
6501               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6502             }
6503             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart);
6504             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6505           } else if ((p >= cMax) && (p < cEnd)) {
6506             /* Hybrid cells add new cells and faces */
6507             for (r = 0; r < 4; ++r) {
6508               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
6509               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6510             }
6511             for (r = 0; r < 3; ++r) {
6512               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
6513               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6514             }
6515           }
6516           break;
6517         case 6:
6518           /* Hex 3D */
6519           if ((p >= vStart) && (p < vEnd)) {
6520             /* Old vertices stay the same */
6521             newp = vStartNew + (p - vStart);
6522             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6523           } else if ((p >= eStart) && (p < eEnd)) {
6524             /* Old edges add new edges and vertex */
6525             for (r = 0; r < 2; ++r) {
6526               newp = eStartNew + (p - eStart)*2 + r;
6527               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6528             }
6529             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6530             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6531           } else if ((p >= fStart) && (p < fEnd)) {
6532             /* Old faces add new faces, edges, and vertex */
6533             for (r = 0; r < 4; ++r) {
6534               newp = fStartNew + (p - fStart)*4 + r;
6535               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6536             }
6537             for (r = 0; r < 4; ++r) {
6538               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*4 + r;
6539               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6540             }
6541             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (p - fStart);
6542             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6543           } else if ((p >= cStart) && (p < cEnd)) {
6544             /* Old cells add new cells, faces, edges, and vertex */
6545             for (r = 0; r < 8; ++r) {
6546               newp = cStartNew + (p - cStart)*8 + r;
6547               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6548             }
6549             for (r = 0; r < 12; ++r) {
6550               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*12 + r;
6551               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6552             }
6553             for (r = 0; r < 6; ++r) {
6554               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (p - cStart)*6 + r;
6555               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6556             }
6557             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (p - cStart);
6558             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6559           }
6560           break;
6561         case 8:
6562           /* Hybrid Hex 3D */
6563           if ((p >= vStart) && (p < vEnd)) {
6564             /* Interior vertices stay the same */
6565             newp = vStartNew + (p - vStart);
6566             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6567           } else if ((p >= eStart) && (p < eMax)) {
6568             /* Interior edges add new edges and vertex */
6569             for (r = 0; r < 2; ++r) {
6570               newp = eStartNew + (p - eStart)*2 + r;
6571               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6572             }
6573             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6574             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6575           } else if ((p >= eMax) && (p < eEnd)) {
6576             /* Hybrid edges stay the same */
6577             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - eMax);
6578             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6579           } else if ((p >= fStart) && (p < fMax)) {
6580             /* Interior faces add new faces, edges, and vertex */
6581             for (r = 0; r < 4; ++r) {
6582               newp = fStartNew + (p - fStart)*4 + r;
6583               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6584             }
6585             for (r = 0; r < 4; ++r) {
6586               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*4 + r;
6587               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6588             }
6589             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (p - fStart);
6590             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6591           } else if ((p >= fMax) && (p < fEnd)) {
6592             /* Hybrid faces add new faces and edges */
6593             for (r = 0; r < 2; ++r) {
6594               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (p - fMax)*2 + r;
6595               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6596             }
6597             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - fMax);
6598             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6599           } else if ((p >= cStart) && (p < cMax)) {
6600             /* Interior cells add new cells, faces, edges, and vertex */
6601             for (r = 0; r < 8; ++r) {
6602               newp = cStartNew + (p - cStart)*8 + r;
6603               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6604             }
6605             for (r = 0; r < 12; ++r) {
6606               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*12 + r;
6607               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6608             }
6609             for (r = 0; r < 6; ++r) {
6610               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (p - cStart)*6 + r;
6611               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6612             }
6613             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (p - cStart);
6614             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6615           } else if ((p >= cMax) && (p < cEnd)) {
6616             /* Hybrid cells add new cells, faces, and edges */
6617             for (r = 0; r < 4; ++r) {
6618               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
6619               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6620             }
6621             for (r = 0; r < 4; ++r) {
6622               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (p - cMax)*4 + r;
6623               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6624             }
6625             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (fEnd - fMax) + (p - cMax);
6626             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6627           }
6628           break;
6629         default:
6630           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6631         }
6632       }
6633       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
6634       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
6635     }
6636     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
6637     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
6638     if (0) {
6639       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
6640       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
6641       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
6642     }
6643   }
6644   PetscFunctionReturn(0);
6645 }
6646 
6647 #undef __FUNCT__
6648 #define __FUNCT__ "DMPlexRefineUniform_Internal"
6649 /* This will only work for interpolated meshes */
6650 PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
6651 {
6652   DM             rdm;
6653   PetscInt      *depthSize;
6654   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
6655   PetscErrorCode ierr;
6656 
6657   PetscFunctionBegin;
6658   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
6659   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
6660   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6661   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
6662   /* Calculate number of new points of each depth */
6663   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6664   ierr = PetscMalloc1((depth+1), &depthSize);CHKERRQ(ierr);
6665   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
6666   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
6667   /* Step 1: Set chart */
6668   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
6669   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
6670   /* Step 2: Set cone/support sizes */
6671   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6672   /* Step 3: Setup refined DM */
6673   ierr = DMSetUp(rdm);CHKERRQ(ierr);
6674   /* Step 4: Set cones and supports */
6675   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6676   /* Step 5: Stratify */
6677   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
6678   /* Step 6: Set coordinates for vertices */
6679   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6680   /* Step 7: Create pointSF */
6681   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6682   /* Step 8: Create labels */
6683   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6684   ierr = PetscFree(depthSize);CHKERRQ(ierr);
6685 
6686   *dmRefined = rdm;
6687   PetscFunctionReturn(0);
6688 }
6689 
6690 #undef __FUNCT__
6691 #define __FUNCT__ "DMPlexCreateCoarsePointIS"
6692 /*@
6693   DMPlexCreateCoarsePointIS - Creates an IS covering the coarse DM chart with the fine points as data
6694 
6695   Input Parameter:
6696 . dm - The coarse DM
6697 
6698   Output Parameter:
6699 . fpointIS - The IS of all the fine points which exist in the original coarse mesh
6700 
6701   Level: developer
6702 
6703 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexCreateSubpointIS()
6704 @*/
6705 PetscErrorCode DMPlexCreateCoarsePointIS(DM dm, IS *fpointIS)
6706 {
6707   CellRefiner    cellRefiner;
6708   PetscInt      *depthSize, *fpoints;
6709   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
6710   PetscInt       depth, pStart, pEnd, p, vStart, vEnd, v;
6711   PetscErrorCode ierr;
6712 
6713   PetscFunctionBegin;
6714   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6715   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6716   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6717   ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr);
6718   ierr = PetscMalloc1((depth+1), &depthSize);CHKERRQ(ierr);
6719   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
6720   if (cellRefiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
6721   ierr = PetscMalloc1(pEnd-pStart,&fpoints);CHKERRQ(ierr);
6722   for (p = 0; p < pEnd-pStart; ++p) fpoints[p] = -1;
6723   switch (cellRefiner) {
6724   case 1: /* Simplicial 2D */
6725   case 3: /* Hybrid simplicial 2D */
6726   case 2: /* Hex 2D */
6727   case 4: /* Hybrid Hex 2D */
6728   case 5: /* Simplicial 3D */
6729   case 7: /* Hybrid Simplicial 3D */
6730   case 6: /* Hex 3D */
6731   case 8: /* Hybrid Hex 3D */
6732     for (v = vStart; v < vEnd; ++v) fpoints[v-pStart] = vStartNew + (v - vStart);
6733     break;
6734   default:
6735     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", cellRefiner);
6736   }
6737   ierr = ISCreateGeneral(PETSC_COMM_SELF, pEnd-pStart, fpoints, PETSC_OWN_POINTER, fpointIS);CHKERRQ(ierr);
6738   ierr = PetscFree(depthSize);CHKERRQ(ierr);
6739   PetscFunctionReturn(0);
6740 }
6741 
6742 #undef __FUNCT__
6743 #define __FUNCT__ "DMPlexSetRefinementUniform"
6744 /*@
6745   DMPlexSetRefinementUniform - Set the flag for uniform refinement
6746 
6747   Input Parameters:
6748 + dm - The DM
6749 - refinementUniform - The flag for uniform refinement
6750 
6751   Level: developer
6752 
6753 .seealso: DMRefine(), DMPlexGetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
6754 @*/
6755 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
6756 {
6757   DM_Plex *mesh = (DM_Plex*) dm->data;
6758 
6759   PetscFunctionBegin;
6760   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6761   mesh->refinementUniform = refinementUniform;
6762   PetscFunctionReturn(0);
6763 }
6764 
6765 #undef __FUNCT__
6766 #define __FUNCT__ "DMPlexGetRefinementUniform"
6767 /*@
6768   DMPlexGetRefinementUniform - Retrieve the flag for uniform refinement
6769 
6770   Input Parameter:
6771 . dm - The DM
6772 
6773   Output Parameter:
6774 . refinementUniform - The flag for uniform refinement
6775 
6776   Level: developer
6777 
6778 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
6779 @*/
6780 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
6781 {
6782   DM_Plex *mesh = (DM_Plex*) dm->data;
6783 
6784   PetscFunctionBegin;
6785   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6786   PetscValidPointer(refinementUniform,  2);
6787   *refinementUniform = mesh->refinementUniform;
6788   PetscFunctionReturn(0);
6789 }
6790 
6791 #undef __FUNCT__
6792 #define __FUNCT__ "DMPlexSetRefinementLimit"
6793 /*@
6794   DMPlexSetRefinementLimit - Set the maximum cell volume for refinement
6795 
6796   Input Parameters:
6797 + dm - The DM
6798 - refinementLimit - The maximum cell volume in the refined mesh
6799 
6800   Level: developer
6801 
6802 .seealso: DMRefine(), DMPlexGetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
6803 @*/
6804 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
6805 {
6806   DM_Plex *mesh = (DM_Plex*) dm->data;
6807 
6808   PetscFunctionBegin;
6809   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6810   mesh->refinementLimit = refinementLimit;
6811   PetscFunctionReturn(0);
6812 }
6813 
6814 #undef __FUNCT__
6815 #define __FUNCT__ "DMPlexGetRefinementLimit"
6816 /*@
6817   DMPlexGetRefinementLimit - Retrieve the maximum cell volume for refinement
6818 
6819   Input Parameter:
6820 . dm - The DM
6821 
6822   Output Parameter:
6823 . refinementLimit - The maximum cell volume in the refined mesh
6824 
6825   Level: developer
6826 
6827 .seealso: DMRefine(), DMPlexSetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
6828 @*/
6829 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
6830 {
6831   DM_Plex *mesh = (DM_Plex*) dm->data;
6832 
6833   PetscFunctionBegin;
6834   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6835   PetscValidPointer(refinementLimit,  2);
6836   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
6837   *refinementLimit = mesh->refinementLimit;
6838   PetscFunctionReturn(0);
6839 }
6840 
6841 #undef __FUNCT__
6842 #define __FUNCT__ "DMPlexGetCellRefiner_Internal"
6843 PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
6844 {
6845   PetscInt       dim, cStart, cEnd, coneSize, cMax;
6846   PetscErrorCode ierr;
6847 
6848   PetscFunctionBegin;
6849   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6850   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6851   if (cEnd <= cStart) {*cellRefiner = 0; PetscFunctionReturn(0);}
6852   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
6853   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
6854   switch (dim) {
6855   case 2:
6856     switch (coneSize) {
6857     case 3:
6858       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
6859       else *cellRefiner = 1; /* Triangular */
6860       break;
6861     case 4:
6862       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
6863       else *cellRefiner = 2; /* Quadrilateral */
6864       break;
6865     default:
6866       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
6867     }
6868     break;
6869   case 3:
6870     switch (coneSize) {
6871     case 4:
6872       if (cMax >= 0) *cellRefiner = 7; /* Hybrid */
6873       else *cellRefiner = 5; /* Tetrahedral */
6874       break;
6875     case 6:
6876       if (cMax >= 0) *cellRefiner = 8; /* Hybrid */
6877       else *cellRefiner = 6; /* hexahedral */
6878       break;
6879     default:
6880       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
6881     }
6882     break;
6883   default:
6884     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
6885   }
6886   PetscFunctionReturn(0);
6887 }
6888