xref: /petsc/src/dm/impls/plex/plexrefine.c (revision bb04b57d8fc8b99a9ce04c03188cf4f575836949)
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) {
5400         coordsNew[offnew+d] = 0.0;
5401         for (v = 0; v < coneSize; ++v) coordsNew[offnew+d] += coords[off[v]+d];
5402         coordsNew[offnew+d] /= coneSize;
5403       }
5404       ierr = DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5405     }
5406   case 2: /* Hex 2D */
5407   case 4: /* Hybrid Hex 2D */
5408     /* Cell vertices have the average of corner coordinates */
5409     for (c = cStart; c < cMax; ++c) {
5410       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (c - cStart) + (dim > 2 ? (fMax - fStart) : 0);
5411       PetscInt      *cone = NULL;
5412       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
5413 
5414       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5415       for (p = 0; p < closureSize*2; p += 2) {
5416         const PetscInt point = cone[p];
5417         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
5418       }
5419       for (v = 0; v < coneSize; ++v) {
5420         ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
5421       }
5422       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5423       for (d = 0; d < dim; ++d) {
5424         coordsNew[offnew+d] = 0.0;
5425         for (v = 0; v < coneSize; ++v) coordsNew[offnew+d] += coords[off[v]+d];
5426         coordsNew[offnew+d] /= coneSize;
5427       }
5428       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5429     }
5430   case 1: /* Simplicial 2D */
5431   case 3: /* Hybrid Simplicial 2D */
5432   case 5: /* Simplicial 3D */
5433   case 7: /* Hybrid Simplicial 3D */
5434     /* Edge vertices have the average of endpoint coordinates */
5435     for (e = eStart; e < eMax; ++e) {
5436       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
5437       const PetscInt *cone;
5438       PetscInt        coneSize, offA, offB, offnew, d;
5439 
5440       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
5441       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
5442       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
5443       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
5444       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
5445       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5446       for (d = 0; d < dim; ++d) {
5447         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
5448       }
5449     }
5450     /* Old vertices have the same coordinates */
5451     for (v = vStart; v < vEnd; ++v) {
5452       const PetscInt newv = vStartNew + (v - vStart);
5453       PetscInt       off, offnew, d;
5454 
5455       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5456       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5457       for (d = 0; d < dim; ++d) {
5458         coordsNew[offnew+d] = coords[off+d];
5459       }
5460     }
5461     break;
5462   default:
5463     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5464   }
5465   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
5466   ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5467   ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
5468   ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
5469   ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
5470   PetscFunctionReturn(0);
5471 }
5472 
5473 #undef __FUNCT__
5474 #define __FUNCT__ "DMPlexCreateProcessSF"
5475 static PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
5476 {
5477   PetscInt           numRoots, numLeaves, l;
5478   const PetscInt    *localPoints;
5479   const PetscSFNode *remotePoints;
5480   PetscInt          *localPointsNew;
5481   PetscSFNode       *remotePointsNew;
5482   PetscInt          *ranks, *ranksNew;
5483   PetscErrorCode     ierr;
5484 
5485   PetscFunctionBegin;
5486   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5487   ierr = PetscMalloc1(numLeaves, &ranks);CHKERRQ(ierr);
5488   for (l = 0; l < numLeaves; ++l) {
5489     ranks[l] = remotePoints[l].rank;
5490   }
5491   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
5492   ierr = PetscMalloc1(numLeaves,    &ranksNew);CHKERRQ(ierr);
5493   ierr = PetscMalloc1(numLeaves,    &localPointsNew);CHKERRQ(ierr);
5494   ierr = PetscMalloc1(numLeaves, &remotePointsNew);CHKERRQ(ierr);
5495   for (l = 0; l < numLeaves; ++l) {
5496     ranksNew[l]              = ranks[l];
5497     localPointsNew[l]        = l;
5498     remotePointsNew[l].index = 0;
5499     remotePointsNew[l].rank  = ranksNew[l];
5500   }
5501   ierr = PetscFree(ranks);CHKERRQ(ierr);
5502   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
5503   ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
5504   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
5505   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
5506   PetscFunctionReturn(0);
5507 }
5508 
5509 #undef __FUNCT__
5510 #define __FUNCT__ "CellRefinerCreateSF"
5511 static PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5512 {
5513   PetscSF            sf, sfNew, sfProcess;
5514   IS                 processRanks;
5515   MPI_Datatype       depthType;
5516   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
5517   const PetscInt    *localPoints, *neighbors;
5518   const PetscSFNode *remotePoints;
5519   PetscInt          *localPointsNew;
5520   PetscSFNode       *remotePointsNew;
5521   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
5522   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r, n;
5523   PetscInt           cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
5524   PetscErrorCode     ierr;
5525 
5526   PetscFunctionBegin;
5527   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
5528   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5529   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5530   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5531   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5532   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5533   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5534   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
5535   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
5536   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
5537   /* Caculate size of new SF */
5538   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5539   if (numRoots < 0) PetscFunctionReturn(0);
5540   for (l = 0; l < numLeaves; ++l) {
5541     const PetscInt p = localPoints[l];
5542 
5543     switch (refiner) {
5544     case 1:
5545       /* Simplicial 2D */
5546       if ((p >= vStart) && (p < vEnd)) {
5547         /* Old vertices stay the same */
5548         ++numLeavesNew;
5549       } else if ((p >= fStart) && (p < fEnd)) {
5550         /* Old faces add new faces and vertex */
5551         numLeavesNew += 2 + 1;
5552       } else if ((p >= cStart) && (p < cEnd)) {
5553         /* Old cells add new cells and interior faces */
5554         numLeavesNew += 4 + 3;
5555       }
5556       break;
5557     case 3:
5558       /* Hybrid Simplicial 2D */
5559       if ((p >= vStart) && (p < vEnd)) {
5560         /* Interior vertices stay the same */
5561         ++numLeavesNew;
5562       } else if ((p >= fStart) && (p < fMax)) {
5563         /* Interior faces add new faces and vertex */
5564         numLeavesNew += 2 + 1;
5565       } else if ((p >= fMax) && (p < fEnd)) {
5566         /* Hybrid faces stay the same */
5567         ++numLeavesNew;
5568       } else if ((p >= cStart) && (p < cMax)) {
5569         /* Interior cells add new cells and interior faces */
5570         numLeavesNew += 4 + 3;
5571       } else if ((p >= cMax) && (p < cEnd)) {
5572         /* Hybrid cells add new cells and hybrid face */
5573         numLeavesNew += 2 + 1;
5574       }
5575       break;
5576     case 2:
5577       /* Hex 2D */
5578       if ((p >= vStart) && (p < vEnd)) {
5579         /* Old vertices stay the same */
5580         ++numLeavesNew;
5581       } else if ((p >= fStart) && (p < fEnd)) {
5582         /* Old faces add new faces and vertex */
5583         numLeavesNew += 2 + 1;
5584       } else if ((p >= cStart) && (p < cEnd)) {
5585         /* Old cells add new cells, interior faces, and vertex */
5586         numLeavesNew += 4 + 4 + 1;
5587       }
5588       break;
5589     case 4:
5590       /* Hybrid Hex 2D */
5591       if ((p >= vStart) && (p < vEnd)) {
5592         /* Interior vertices stay the same */
5593         ++numLeavesNew;
5594       } else if ((p >= fStart) && (p < fMax)) {
5595         /* Interior faces add new faces and vertex */
5596         numLeavesNew += 2 + 1;
5597       } else if ((p >= fMax) && (p < fEnd)) {
5598         /* Hybrid faces stay the same */
5599         ++numLeavesNew;
5600       } else if ((p >= cStart) && (p < cMax)) {
5601         /* Interior cells add new cells, interior faces, and vertex */
5602         numLeavesNew += 4 + 4 + 1;
5603       } else if ((p >= cMax) && (p < cEnd)) {
5604         /* Hybrid cells add new cells and hybrid face */
5605         numLeavesNew += 2 + 1;
5606       }
5607       break;
5608     case 5:
5609       /* Simplicial 3D */
5610       if ((p >= vStart) && (p < vEnd)) {
5611         /* Old vertices stay the same */
5612         ++numLeavesNew;
5613       } else if ((p >= eStart) && (p < eEnd)) {
5614         /* Old edges add new edges and vertex */
5615         numLeavesNew += 2 + 1;
5616       } else if ((p >= fStart) && (p < fEnd)) {
5617         /* Old faces add new faces and face edges */
5618         numLeavesNew += 4 + 3;
5619       } else if ((p >= cStart) && (p < cEnd)) {
5620         /* Old cells add new cells and interior faces and edges */
5621         numLeavesNew += 8 + 8 + 1;
5622       }
5623       break;
5624     case 7:
5625       /* Hybrid Simplicial 3D */
5626       if ((p >= vStart) && (p < vEnd)) {
5627         /* Interior vertices stay the same */
5628         ++numLeavesNew;
5629       } else if ((p >= eStart) && (p < eMax)) {
5630         /* Interior edges add new edges and vertex */
5631         numLeavesNew += 2 + 1;
5632       } else if ((p >= eMax) && (p < eEnd)) {
5633         /* Hybrid edges stay the same */
5634         ++numLeavesNew;
5635       } else if ((p >= fStart) && (p < fMax)) {
5636         /* Interior faces add new faces and edges */
5637         numLeavesNew += 4 + 3;
5638       } else if ((p >= fMax) && (p < fEnd)) {
5639         /* Hybrid faces add new faces and edges */
5640         numLeavesNew += 2 + 1;
5641       } else if ((p >= cStart) && (p < cMax)) {
5642         /* Interior cells add new cells, faces, and edges */
5643         numLeavesNew += 8 + 8 + 1;
5644       } else if ((p >= cMax) && (p < cEnd)) {
5645         /* Hybrid cells add new cells and faces */
5646         numLeavesNew += 4 + 3;
5647       }
5648       break;
5649     case 6:
5650       /* Hex 3D */
5651       if ((p >= vStart) && (p < vEnd)) {
5652         /* Old vertices stay the same */
5653         ++numLeavesNew;
5654       } else if ((p >= eStart) && (p < eEnd)) {
5655         /* Old edges add new edges, and vertex */
5656         numLeavesNew += 2 + 1;
5657       } else if ((p >= fStart) && (p < fEnd)) {
5658         /* Old faces add new faces, edges, and vertex */
5659         numLeavesNew += 4 + 4 + 1;
5660       } else if ((p >= cStart) && (p < cEnd)) {
5661         /* Old cells add new cells, faces, edges, and vertex */
5662         numLeavesNew += 8 + 12 + 6 + 1;
5663       }
5664       break;
5665     case 8:
5666       /* Hybrid Hex 3D */
5667       if ((p >= vStart) && (p < vEnd)) {
5668         /* Old vertices stay the same */
5669         ++numLeavesNew;
5670       } else if ((p >= eStart) && (p < eMax)) {
5671         /* Interior edges add new edges, and vertex */
5672         numLeavesNew += 2 + 1;
5673       } else if ((p >= eMax) && (p < eEnd)) {
5674         /* Hybrid edges stay the same */
5675         ++numLeavesNew;
5676       } else if ((p >= fStart) && (p < fMax)) {
5677         /* Interior faces add new faces, edges, and vertex */
5678         numLeavesNew += 4 + 4 + 1;
5679       } else if ((p >= fMax) && (p < fEnd)) {
5680         /* Hybrid faces add new faces and edges */
5681         numLeavesNew += 2 + 1;
5682       } else if ((p >= cStart) && (p < cMax)) {
5683         /* Interior cells add new cells, faces, edges, and vertex */
5684         numLeavesNew += 8 + 12 + 6 + 1;
5685       } else if ((p >= cStart) && (p < cEnd)) {
5686         /* Hybrid cells add new cells, faces, and edges */
5687         numLeavesNew += 4 + 4 + 1;
5688       }
5689       break;
5690     default:
5691       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5692     }
5693   }
5694   /* Communicate depthSizes for each remote rank */
5695   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
5696   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
5697   ierr = PetscMalloc5((depth+1)*numNeighbors,&rdepthSize,numNeighbors,&rvStartNew,numNeighbors,&reStartNew,numNeighbors,&rfStartNew,numNeighbors,&rcStartNew);CHKERRQ(ierr);
5698   ierr = PetscMalloc7(depth+1,&depthSizeOld,(depth+1)*numNeighbors,&rdepthSizeOld,(depth+1)*numNeighbors,&rdepthMaxOld,numNeighbors,&rvStart,numNeighbors,&reStart,numNeighbors,&rfStart,numNeighbors,&rcStart);CHKERRQ(ierr);
5699   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
5700   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
5701   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5702   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5703   for (n = 0; n < numNeighbors; ++n) {
5704     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
5705   }
5706   depthSizeOld[depth]   = cMax;
5707   depthSizeOld[0]       = vMax;
5708   depthSizeOld[depth-1] = fMax;
5709   depthSizeOld[1]       = eMax;
5710 
5711   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5712   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5713 
5714   depthSizeOld[depth]   = cEnd - cStart;
5715   depthSizeOld[0]       = vEnd - vStart;
5716   depthSizeOld[depth-1] = fEnd - fStart;
5717   depthSizeOld[1]       = eEnd - eStart;
5718 
5719   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5720   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5721   for (n = 0; n < numNeighbors; ++n) {
5722     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
5723   }
5724   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
5725   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
5726   /* Calculate new point SF */
5727   ierr = PetscMalloc1(numLeavesNew,    &localPointsNew);CHKERRQ(ierr);
5728   ierr = PetscMalloc1(numLeavesNew, &remotePointsNew);CHKERRQ(ierr);
5729   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
5730   for (l = 0, m = 0; l < numLeaves; ++l) {
5731     PetscInt    p     = localPoints[l];
5732     PetscInt    rp    = remotePoints[l].index, n;
5733     PetscMPIInt rrank = remotePoints[l].rank;
5734 
5735     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
5736     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
5737     switch (refiner) {
5738     case 1:
5739       /* Simplicial 2D */
5740       if ((p >= vStart) && (p < vEnd)) {
5741         /* Old vertices stay the same */
5742         localPointsNew[m]        = vStartNew     + (p  - vStart);
5743         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5744         remotePointsNew[m].rank  = rrank;
5745         ++m;
5746       } else if ((p >= fStart) && (p < fEnd)) {
5747         /* Old faces add new faces and vertex */
5748         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5749         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5750         remotePointsNew[m].rank  = rrank;
5751         ++m;
5752         for (r = 0; r < 2; ++r, ++m) {
5753           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5754           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5755           remotePointsNew[m].rank  = rrank;
5756         }
5757       } else if ((p >= cStart) && (p < cEnd)) {
5758         /* Old cells add new cells and interior faces */
5759         for (r = 0; r < 4; ++r, ++m) {
5760           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5761           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5762           remotePointsNew[m].rank  = rrank;
5763         }
5764         for (r = 0; r < 3; ++r, ++m) {
5765           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
5766           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
5767           remotePointsNew[m].rank  = rrank;
5768         }
5769       }
5770       break;
5771     case 2:
5772       /* Hex 2D */
5773       if ((p >= vStart) && (p < vEnd)) {
5774         /* Old vertices stay the same */
5775         localPointsNew[m]        = vStartNew     + (p  - vStart);
5776         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5777         remotePointsNew[m].rank  = rrank;
5778         ++m;
5779       } else if ((p >= fStart) && (p < fEnd)) {
5780         /* Old faces add new faces and vertex */
5781         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5782         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5783         remotePointsNew[m].rank  = rrank;
5784         ++m;
5785         for (r = 0; r < 2; ++r, ++m) {
5786           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5787           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5788           remotePointsNew[m].rank  = rrank;
5789         }
5790       } else if ((p >= cStart) && (p < cEnd)) {
5791         /* Old cells add new cells, interior faces, and vertex */
5792         for (r = 0; r < 4; ++r, ++m) {
5793           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5794           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5795           remotePointsNew[m].rank  = rrank;
5796         }
5797         for (r = 0; r < 4; ++r, ++m) {
5798           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
5799           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
5800           remotePointsNew[m].rank  = rrank;
5801         }
5802         for (r = 0; r < 1; ++r, ++m) {
5803           localPointsNew[m]        = vStartNew     + (vEnd - vStart)               + (fEnd - fStart)                    + (p  - cStart)     + r;
5804           remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0]  + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]) + r;
5805           remotePointsNew[m].rank  = rrank;
5806         }
5807       }
5808       break;
5809     case 3:
5810       /* Hybrid simplicial 2D */
5811       if ((p >= vStart) && (p < vEnd)) {
5812         /* Old vertices stay the same */
5813         localPointsNew[m]        = vStartNew     + (p  - vStart);
5814         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5815         remotePointsNew[m].rank  = rrank;
5816         ++m;
5817       } else if ((p >= fStart) && (p < fMax)) {
5818         /* Old interior faces add new faces and vertex */
5819         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5820         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5821         remotePointsNew[m].rank  = rrank;
5822         ++m;
5823         for (r = 0; r < 2; ++r, ++m) {
5824           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5825           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5826           remotePointsNew[m].rank  = rrank;
5827         }
5828       } else if ((p >= fMax) && (p < fEnd)) {
5829         /* Old hybrid faces stay the same */
5830         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
5831         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
5832         remotePointsNew[m].rank  = rrank;
5833         ++m;
5834       } else if ((p >= cStart) && (p < cMax)) {
5835         /* Old interior cells add new cells and interior faces */
5836         for (r = 0; r < 4; ++r, ++m) {
5837           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5838           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5839           remotePointsNew[m].rank  = rrank;
5840         }
5841         for (r = 0; r < 3; ++r, ++m) {
5842           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
5843           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
5844           remotePointsNew[m].rank  = rrank;
5845         }
5846       } else if ((p >= cStart) && (p < cMax)) {
5847         /* Old hybrid cells add new cells and hybrid face */
5848         for (r = 0; r < 2; ++r, ++m) {
5849           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5850           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5851           remotePointsNew[m].rank  = rrank;
5852         }
5853         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
5854         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]);
5855         remotePointsNew[m].rank  = rrank;
5856         ++m;
5857       }
5858       break;
5859     case 4:
5860       /* Hybrid Hex 2D */
5861       if ((p >= vStart) && (p < vEnd)) {
5862         /* Old vertices stay the same */
5863         localPointsNew[m]        = vStartNew     + (p  - vStart);
5864         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5865         remotePointsNew[m].rank  = rrank;
5866         ++m;
5867       } else if ((p >= fStart) && (p < fMax)) {
5868         /* Old interior faces add new faces and vertex */
5869         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5870         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5871         remotePointsNew[m].rank  = rrank;
5872         ++m;
5873         for (r = 0; r < 2; ++r, ++m) {
5874           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5875           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5876           remotePointsNew[m].rank  = rrank;
5877         }
5878       } else if ((p >= fMax) && (p < fEnd)) {
5879         /* Old hybrid faces stay the same */
5880         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
5881         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
5882         remotePointsNew[m].rank  = rrank;
5883         ++m;
5884       } else if ((p >= cStart) && (p < cMax)) {
5885         /* Old interior cells add new cells, interior faces, and vertex */
5886         localPointsNew[m]        = vStartNew     + (vEnd - vStart)               + (fEnd - fStart)                    + (p  - cStart);
5887         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0]  + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
5888         remotePointsNew[m].rank  = rrank;
5889         ++m;
5890         for (r = 0; r < 4; ++r, ++m) {
5891           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5892           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5893           remotePointsNew[m].rank  = rrank;
5894         }
5895         for (r = 0; r < 4; ++r, ++m) {
5896           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*4     + r;
5897           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*4 + r;
5898           remotePointsNew[m].rank  = rrank;
5899         }
5900       } else if ((p >= cStart) && (p < cMax)) {
5901         /* Old hybrid cells add new cells and hybrid face */
5902         for (r = 0; r < 2; ++r, ++m) {
5903           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5904           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5905           remotePointsNew[m].rank  = rrank;
5906         }
5907         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*4     + (p  - cMax);
5908         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]);
5909         remotePointsNew[m].rank  = rrank;
5910         ++m;
5911       }
5912       break;
5913     case 5:
5914       /* Simplicial 3D */
5915       if ((p >= vStart) && (p < vEnd)) {
5916         /* Old vertices stay the same */
5917         localPointsNew[m]        = vStartNew     + (p  - vStart);
5918         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5919         remotePointsNew[m].rank  = rrank;
5920         ++m;
5921       } else if ((p >= eStart) && (p < eEnd)) {
5922         /* Old edges add new edges and vertex */
5923         for (r = 0; r < 2; ++r, ++m) {
5924           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
5925           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
5926           remotePointsNew[m].rank  = rrank;
5927         }
5928         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
5929         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
5930         remotePointsNew[m].rank  = rrank;
5931         ++m;
5932       } else if ((p >= fStart) && (p < fEnd)) {
5933         /* Old faces add new faces and face edges */
5934         for (r = 0; r < 4; ++r, ++m) {
5935           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
5936           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
5937           remotePointsNew[m].rank  = rrank;
5938         }
5939         for (r = 0; r < 3; ++r, ++m) {
5940           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (p  - fStart)*3     + r;
5941           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + (rp - rfStart[n])*3 + r;
5942           remotePointsNew[m].rank  = rrank;
5943         }
5944       } else if ((p >= cStart) && (p < cEnd)) {
5945         /* Old cells add new cells and interior faces and edges */
5946         for (r = 0; r < 8; ++r, ++m) {
5947           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
5948           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
5949           remotePointsNew[m].rank  = rrank;
5950         }
5951         for (r = 0; r < 8; ++r, ++m) {
5952           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*4                    + (p  - cStart)*8     + r;
5953           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*4 + (rp - rcStart[n])*8 + r;
5954           remotePointsNew[m].rank  = rrank;
5955         }
5956         for (r = 0; r < 1; ++r, ++m) {
5957           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (fEnd - fStart)*3                    + (p  - cStart)*1     + r;
5958           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + rdepthSizeOld[n*(depth+1)+depth-1]*3 + (rp - rcStart[n])*1 + r;
5959           remotePointsNew[m].rank  = rrank;
5960         }
5961       }
5962       break;
5963     case 7:
5964       /* Hybrid Simplicial 3D */
5965       if ((p >= vStart) && (p < vEnd)) {
5966         /* Interior vertices stay the same */
5967         localPointsNew[m]        = vStartNew     + (p  - vStart);
5968         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5969         remotePointsNew[m].rank  = rrank;
5970         ++m;
5971       } else if ((p >= eStart) && (p < eMax)) {
5972         /* Interior edges add new edges and vertex */
5973         for (r = 0; r < 2; ++r, ++m) {
5974           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
5975           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
5976           remotePointsNew[m].rank  = rrank;
5977         }
5978         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
5979         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
5980         remotePointsNew[m].rank  = rrank;
5981         ++m;
5982       } else if ((p >= eMax) && (p < eEnd)) {
5983         /* Hybrid edges stay the same */
5984         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - eMax);
5985         remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*3 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n]) + (rp - rdepthMaxOld[n*(depth+1)+1]);
5986         remotePointsNew[m].rank  = rrank;
5987         ++m;
5988       } else if ((p >= fStart) && (p < fMax)) {
5989         /* Interior faces add new faces and edges */
5990         for (r = 0; r < 4; ++r, ++m) {
5991           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
5992           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
5993           remotePointsNew[m].rank  = rrank;
5994         }
5995         for (r = 0; r < 3; ++r, ++m) {
5996           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*3     + r;
5997           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
5998           remotePointsNew[m].rank  = rrank;
5999         }
6000       } else if ((p >= fMax) && (p < fEnd)) {
6001         /* Hybrid faces add new faces and edges */
6002         for (r = 0; r < 2; ++r, ++m) {
6003           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fMax)*2                              + r;
6004           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;
6005           remotePointsNew[m].rank  = rrank;
6006         }
6007         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (eEnd                                    - eMax)                        + (p  - fMax);
6008         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]);
6009         remotePointsNew[m].rank  = rrank;
6010         ++m;
6011       } else if ((p >= cStart) && (p < cMax)) {
6012         /* Interior cells add new cells, faces, and edges */
6013         for (r = 0; r < 8; ++r, ++m) {
6014           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
6015           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
6016           remotePointsNew[m].rank  = rrank;
6017         }
6018         for (r = 0; r < 8; ++r, ++m) {
6019           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*8     + r;
6020           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*8 + r;
6021           remotePointsNew[m].rank  = rrank;
6022         }
6023         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (p  - cStart)*1     + r;
6024         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;
6025         remotePointsNew[m].rank  = rrank;
6026         ++m;
6027       } else if ((p >= cMax) && (p < cEnd)) {
6028         /* Hybrid cells add new cells and faces */
6029         for (r = 0; r < 4; ++r, ++m) {
6030           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
6031           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
6032           remotePointsNew[m].rank  = rrank;
6033         }
6034         for (r = 0; r < 3; ++r, ++m) {
6035           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*2                              + (p  - cMax)*3                            + r;
6036           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;
6037           remotePointsNew[m].rank  = rrank;
6038         }
6039       }
6040       break;
6041     case 6:
6042       /* Hex 3D */
6043       if ((p >= vStart) && (p < vEnd)) {
6044         /* Old vertices stay the same */
6045         localPointsNew[m]        = vStartNew     + (p  - vStart);
6046         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6047         remotePointsNew[m].rank  = rrank;
6048         ++m;
6049       } else if ((p >= eStart) && (p < eEnd)) {
6050         /* Old edges add new edges and vertex */
6051         for (r = 0; r < 2; ++r, ++m) {
6052           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
6053           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
6054           remotePointsNew[m].rank  = rrank;
6055         }
6056         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
6057         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
6058         remotePointsNew[m].rank  = rrank;
6059         ++m;
6060       } else if ((p >= fStart) && (p < fEnd)) {
6061         /* Old faces add new faces, edges, and vertex */
6062         for (r = 0; r < 4; ++r, ++m) {
6063           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
6064           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
6065           remotePointsNew[m].rank  = rrank;
6066         }
6067         for (r = 0; r < 4; ++r, ++m) {
6068           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (p  - fStart)*4     + r;
6069           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + (rp - rfStart[n])*4 + r;
6070           remotePointsNew[m].rank  = rrank;
6071         }
6072         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eEnd - eStart)              + (p  - fStart);
6073         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+1] + (rp - rfStart[n]);
6074         remotePointsNew[m].rank  = rrank;
6075         ++m;
6076       } else if ((p >= cStart) && (p < cEnd)) {
6077         /* Old cells add new cells, faces, edges, and vertex */
6078         for (r = 0; r < 8; ++r, ++m) {
6079           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
6080           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
6081           remotePointsNew[m].rank  = rrank;
6082         }
6083         for (r = 0; r < 12; ++r, ++m) {
6084           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*4                    + (p  - cStart)*12     + r;
6085           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*4 + (rp - rcStart[n])*12 + r;
6086           remotePointsNew[m].rank  = rrank;
6087         }
6088         for (r = 0; r < 6; ++r, ++m) {
6089           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (fEnd - fStart)*4                    + (p  - cStart)*6     + r;
6090           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + rdepthSizeOld[n*(depth+1)+depth-1]*4 + (rp - rcStart[n])*6 + r;
6091           remotePointsNew[m].rank  = rrank;
6092         }
6093         for (r = 0; r < 1; ++r, ++m) {
6094           localPointsNew[m]        = vStartNew     + (eEnd - eStart)              + (fEnd - fStart)                    + (p  - cStart)     + r;
6095           remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+1] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]) + r;
6096           remotePointsNew[m].rank  = rrank;
6097         }
6098       }
6099       break;
6100     case 8:
6101       /* Hybrid Hex 3D */
6102       if ((p >= vStart) && (p < vEnd)) {
6103         /* Interior vertices stay the same */
6104         localPointsNew[m]        = vStartNew     + (p  - vStart);
6105         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6106         remotePointsNew[m].rank  = rrank;
6107         ++m;
6108       } else if ((p >= eStart) && (p < eMax)) {
6109         /* Interior edges add new edges and vertex */
6110         for (r = 0; r < 2; ++r, ++m) {
6111           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
6112           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
6113           remotePointsNew[m].rank  = rrank;
6114         }
6115         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
6116         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
6117         remotePointsNew[m].rank  = rrank;
6118         ++m;
6119       } else if ((p >= eMax) && (p < eEnd)) {
6120         /* Hybrid edges stay the same */
6121         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (p  - eMax);
6122         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]);
6123         remotePointsNew[m].rank  = rrank;
6124         ++m;
6125       } else if ((p >= fStart) && (p < fMax)) {
6126         /* Interior faces add new faces, edges, and vertex */
6127         for (r = 0; r < 4; ++r, ++m) {
6128           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
6129           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
6130           remotePointsNew[m].rank  = rrank;
6131         }
6132         for (r = 0; r < 4; ++r, ++m) {
6133           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*4     + r;
6134           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*4 + r;
6135           remotePointsNew[m].rank  = rrank;
6136         }
6137         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax                        - eStart)     + (p  - fStart);
6138         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
6139         remotePointsNew[m].rank  = rrank;
6140         ++m;
6141       } else if ((p >= fMax) && (p < fEnd)) {
6142         /* Hybrid faces add new faces and edges */
6143         for (r = 0; r < 2; ++r, ++m) {
6144           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fMax)*2                              + r;
6145           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;
6146           remotePointsNew[m].rank  = rrank;
6147         }
6148         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (fEnd                                          - fMax);
6149         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]);
6150         remotePointsNew[m].rank  = rrank;
6151         ++m;
6152       } else if ((p >= cStart) && (p < cMax)) {
6153         /* Interior cells add new cells, faces, edges, and vertex */
6154         for (r = 0; r < 8; ++r, ++m) {
6155           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
6156           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
6157           remotePointsNew[m].rank  = rrank;
6158         }
6159         for (r = 0; r < 12; ++r, ++m) {
6160           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*12     + r;
6161           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*12 + r;
6162           remotePointsNew[m].rank  = rrank;
6163         }
6164         for (r = 0; r < 6; ++r, ++m) {
6165           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (p  - cStart)*6     + r;
6166           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;
6167           remotePointsNew[m].rank  = rrank;
6168         }
6169         for (r = 0; r < 1; ++r, ++m) {
6170           localPointsNew[m]        = vStartNew     + (eMax                        - eStart)     + (fMax                              - fStart)     + (p  - cStart)     + r;
6171           remotePointsNew[m].index = rvStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]) + r;
6172           remotePointsNew[m].rank  = rrank;
6173         }
6174       } else if ((p >= cMax) && (p < cEnd)) {
6175         /* Hybrid cells add new cells, faces, and edges */
6176         for (r = 0; r < 4; ++r, ++m) {
6177           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
6178           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
6179           remotePointsNew[m].rank  = rrank;
6180         }
6181         for (r = 0; r < 4; ++r, ++m) {
6182           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*2                              + (p  - cMax)*4                            + r;
6183           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;
6184           remotePointsNew[m].rank  = rrank;
6185         }
6186         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (fEnd                                          - fMax)                              + (p  - cMax);
6187         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]);
6188         remotePointsNew[m].rank  = rrank;
6189         ++m;
6190       }
6191       break;
6192     default:
6193       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6194     }
6195   }
6196   if (m != numLeavesNew) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of leaf point %d should be %d", m, numLeavesNew);
6197   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
6198   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
6199   {
6200     PetscSFNode *rp, *rtmp;
6201     PetscInt    *lp, *idx, *ltmp, i;
6202 
6203     /* SF needs sorted leaves to correct calculate Gather */
6204     ierr = PetscMalloc1(numLeavesNew,&idx);CHKERRQ(ierr);
6205     ierr = PetscMalloc1(numLeavesNew, &lp);CHKERRQ(ierr);
6206     ierr = PetscMalloc1(numLeavesNew, &rp);CHKERRQ(ierr);
6207     for (i = 0; i < numLeavesNew; ++i) idx[i] = i;
6208     ierr = PetscSortIntWithPermutation(numLeavesNew, localPointsNew, idx);CHKERRQ(ierr);
6209     for (i = 0; i < numLeavesNew; ++i) {
6210       lp[i] = localPointsNew[idx[i]];
6211       rp[i] = remotePointsNew[idx[i]];
6212     }
6213     ltmp            = localPointsNew;
6214     localPointsNew  = lp;
6215     rtmp            = remotePointsNew;
6216     remotePointsNew = rp;
6217     ierr = PetscFree(idx);CHKERRQ(ierr);
6218     ierr = PetscFree(ltmp);CHKERRQ(ierr);
6219     ierr = PetscFree(rtmp);CHKERRQ(ierr);
6220   }
6221   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6222   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
6223   ierr = PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
6224   PetscFunctionReturn(0);
6225 }
6226 
6227 #undef __FUNCT__
6228 #define __FUNCT__ "CellRefinerCreateLabels"
6229 static PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6230 {
6231   PetscInt       numLabels, l;
6232   PetscInt       depth, newp, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r;
6233   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
6234   PetscErrorCode ierr;
6235 
6236   PetscFunctionBegin;
6237   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6238   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6239   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6240   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6241   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6242   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
6243   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
6244   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6245   switch (refiner) {
6246   case 0: break;
6247   case 7:
6248   case 8:
6249     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
6250   case 3:
6251   case 4:
6252     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6253     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6254   }
6255   for (l = 0; l < numLabels; ++l) {
6256     DMLabel         label, labelNew;
6257     const char     *lname;
6258     PetscBool       isDepth;
6259     IS              valueIS;
6260     const PetscInt *values;
6261     PetscInt        numValues, val;
6262 
6263     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
6264     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
6265     if (isDepth) continue;
6266     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
6267     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
6268     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
6269     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
6270     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
6271     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
6272     for (val = 0; val < numValues; ++val) {
6273       IS              pointIS;
6274       const PetscInt *points;
6275       PetscInt        numPoints, n;
6276 
6277       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
6278       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
6279       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
6280       for (n = 0; n < numPoints; ++n) {
6281         const PetscInt p = points[n];
6282         switch (refiner) {
6283         case 1:
6284           /* Simplicial 2D */
6285           if ((p >= vStart) && (p < vEnd)) {
6286             /* Old vertices stay the same */
6287             newp = vStartNew + (p - vStart);
6288             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6289           } else if ((p >= fStart) && (p < fEnd)) {
6290             /* Old faces add new faces and vertex */
6291             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6292             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6293             for (r = 0; r < 2; ++r) {
6294               newp = fStartNew + (p - fStart)*2 + r;
6295               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6296             }
6297           } else if ((p >= cStart) && (p < cEnd)) {
6298             /* Old cells add new cells and interior faces */
6299             for (r = 0; r < 4; ++r) {
6300               newp = cStartNew + (p - cStart)*4 + r;
6301               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6302             }
6303             for (r = 0; r < 3; ++r) {
6304               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6305               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6306             }
6307           }
6308           break;
6309         case 2:
6310           /* Hex 2D */
6311           if ((p >= vStart) && (p < vEnd)) {
6312             /* Old vertices stay the same */
6313             newp = vStartNew + (p - vStart);
6314             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6315           } else if ((p >= fStart) && (p < fEnd)) {
6316             /* Old faces add new faces and vertex */
6317             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6318             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6319             for (r = 0; r < 2; ++r) {
6320               newp = fStartNew + (p - fStart)*2 + r;
6321               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6322             }
6323           } else if ((p >= cStart) && (p < cEnd)) {
6324             /* Old cells add new cells and interior faces and vertex */
6325             for (r = 0; r < 4; ++r) {
6326               newp = cStartNew + (p - cStart)*4 + r;
6327               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6328             }
6329             for (r = 0; r < 4; ++r) {
6330               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
6331               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6332             }
6333             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
6334             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6335           }
6336           break;
6337         case 3:
6338           /* Hybrid simplicial 2D */
6339           if ((p >= vStart) && (p < vEnd)) {
6340             /* Old vertices stay the same */
6341             newp = vStartNew + (p - vStart);
6342             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6343           } else if ((p >= fStart) && (p < fMax)) {
6344             /* Old interior faces add new faces and vertex */
6345             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6346             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6347             for (r = 0; r < 2; ++r) {
6348               newp = fStartNew + (p - fStart)*2 + r;
6349               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6350             }
6351           } else if ((p >= fMax) && (p < fEnd)) {
6352             /* Old hybrid faces stay the same */
6353             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
6354             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6355           } else if ((p >= cStart) && (p < cMax)) {
6356             /* Old interior cells add new cells and interior faces */
6357             for (r = 0; r < 4; ++r) {
6358               newp = cStartNew + (p - cStart)*4 + r;
6359               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6360             }
6361             for (r = 0; r < 3; ++r) {
6362               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6363               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6364             }
6365           } else if ((p >= cMax) && (p < cEnd)) {
6366             /* Old hybrid cells add new cells and hybrid face */
6367             for (r = 0; r < 2; ++r) {
6368               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
6369               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6370             }
6371             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
6372             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6373           }
6374           break;
6375         case 4:
6376           /* Hybrid Hex 2D */
6377           if ((p >= vStart) && (p < vEnd)) {
6378             /* Old vertices stay the same */
6379             newp = vStartNew + (p - vStart);
6380             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6381           } else if ((p >= fStart) && (p < fMax)) {
6382             /* Old interior faces add new faces and vertex */
6383             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6384             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6385             for (r = 0; r < 2; ++r) {
6386               newp = fStartNew + (p - fStart)*2 + r;
6387               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6388             }
6389           } else if ((p >= fMax) && (p < fEnd)) {
6390             /* Old hybrid faces stay the same */
6391             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
6392             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6393           } else if ((p >= cStart) && (p < cMax)) {
6394             /* Old interior cells add new cells, interior faces, and vertex */
6395             for (r = 0; r < 4; ++r) {
6396               newp = cStartNew + (p - cStart)*4 + r;
6397               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6398             }
6399             for (r = 0; r < 4; ++r) {
6400               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
6401               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6402             }
6403             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
6404             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6405           } else if ((p >= cMax) && (p < cEnd)) {
6406             /* Old hybrid cells add new cells and hybrid face */
6407             for (r = 0; r < 2; ++r) {
6408               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
6409               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6410             }
6411             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (p - cMax);
6412             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6413           }
6414           break;
6415         case 5:
6416           /* Simplicial 3D */
6417           if ((p >= vStart) && (p < vEnd)) {
6418             /* Old vertices stay the same */
6419             newp = vStartNew + (p - vStart);
6420             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6421           } else if ((p >= eStart) && (p < eEnd)) {
6422             /* Old edges add new edges and vertex */
6423             for (r = 0; r < 2; ++r) {
6424               newp = eStartNew + (p - eStart)*2 + r;
6425               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6426             }
6427             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6428             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6429           } else if ((p >= fStart) && (p < fEnd)) {
6430             /* Old faces add new faces and edges */
6431             for (r = 0; r < 4; ++r) {
6432               newp = fStartNew + (p - fStart)*4 + r;
6433               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6434             }
6435             for (r = 0; r < 3; ++r) {
6436               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
6437               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6438             }
6439           } else if ((p >= cStart) && (p < cEnd)) {
6440             /* Old cells add new cells and interior faces and edges */
6441             for (r = 0; r < 8; ++r) {
6442               newp = cStartNew + (p - cStart)*8 + r;
6443               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6444             }
6445             for (r = 0; r < 8; ++r) {
6446               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*8 + r;
6447               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6448             }
6449             for (r = 0; r < 1; ++r) {
6450               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*1 + r;
6451               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6452             }
6453           }
6454           break;
6455         case 7:
6456           /* Hybrid Simplicial 3D */
6457           if ((p >= vStart) && (p < vEnd)) {
6458             /* Interior vertices stay the same */
6459             newp = vStartNew + (p - vStart);
6460             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6461           } else if ((p >= eStart) && (p < eMax)) {
6462             /* Interior edges add new edges and vertex */
6463             for (r = 0; r < 2; ++r) {
6464               newp = eStartNew + (p - eStart)*2 + r;
6465               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6466             }
6467             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6468             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6469           } else if ((p >= eMax) && (p < eEnd)) {
6470             /* Hybrid edges stay the same */
6471             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - eMax);
6472             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6473           } else if ((p >= fStart) && (p < fMax)) {
6474             /* Interior faces add new faces and edges */
6475             for (r = 0; r < 4; ++r) {
6476               newp = fStartNew + (p - fStart)*4 + r;
6477               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6478             }
6479             for (r = 0; r < 3; ++r) {
6480               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
6481               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6482             }
6483           } else if ((p >= fMax) && (p < fEnd)) {
6484             /* Hybrid faces add new faces and edges */
6485             for (r = 0; r < 2; ++r) {
6486               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (p - fMax)*2 + r;
6487               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6488             }
6489             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - fMax);
6490             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6491           } else if ((p >= cStart) && (p < cMax)) {
6492             /* Interior cells add new cells, faces, and edges */
6493             for (r = 0; r < 8; ++r) {
6494               newp = cStartNew + (p - cStart)*8 + r;
6495               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6496             }
6497             for (r = 0; r < 8; ++r) {
6498               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*8 + r;
6499               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6500             }
6501             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart);
6502             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6503           } else if ((p >= cMax) && (p < cEnd)) {
6504             /* Hybrid cells add new cells and faces */
6505             for (r = 0; r < 4; ++r) {
6506               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
6507               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6508             }
6509             for (r = 0; r < 3; ++r) {
6510               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
6511               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6512             }
6513           }
6514           break;
6515         case 6:
6516           /* Hex 3D */
6517           if ((p >= vStart) && (p < vEnd)) {
6518             /* Old vertices stay the same */
6519             newp = vStartNew + (p - vStart);
6520             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6521           } else if ((p >= eStart) && (p < eEnd)) {
6522             /* Old edges add new edges and vertex */
6523             for (r = 0; r < 2; ++r) {
6524               newp = eStartNew + (p - eStart)*2 + r;
6525               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6526             }
6527             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6528             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6529           } else if ((p >= fStart) && (p < fEnd)) {
6530             /* Old faces add new faces, edges, and vertex */
6531             for (r = 0; r < 4; ++r) {
6532               newp = fStartNew + (p - fStart)*4 + r;
6533               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6534             }
6535             for (r = 0; r < 4; ++r) {
6536               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*4 + r;
6537               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6538             }
6539             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (p - fStart);
6540             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6541           } else if ((p >= cStart) && (p < cEnd)) {
6542             /* Old cells add new cells, faces, edges, and vertex */
6543             for (r = 0; r < 8; ++r) {
6544               newp = cStartNew + (p - cStart)*8 + r;
6545               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6546             }
6547             for (r = 0; r < 12; ++r) {
6548               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*12 + r;
6549               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6550             }
6551             for (r = 0; r < 6; ++r) {
6552               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (p - cStart)*6 + r;
6553               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6554             }
6555             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (p - cStart);
6556             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6557           }
6558           break;
6559         case 8:
6560           /* Hybrid Hex 3D */
6561           if ((p >= vStart) && (p < vEnd)) {
6562             /* Interior vertices stay the same */
6563             newp = vStartNew + (p - vStart);
6564             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6565           } else if ((p >= eStart) && (p < eMax)) {
6566             /* Interior edges add new edges and vertex */
6567             for (r = 0; r < 2; ++r) {
6568               newp = eStartNew + (p - eStart)*2 + r;
6569               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6570             }
6571             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6572             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6573           } else if ((p >= eMax) && (p < eEnd)) {
6574             /* Hybrid edges stay the same */
6575             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - eMax);
6576             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6577           } else if ((p >= fStart) && (p < fMax)) {
6578             /* Interior faces add new faces, edges, and vertex */
6579             for (r = 0; r < 4; ++r) {
6580               newp = fStartNew + (p - fStart)*4 + r;
6581               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6582             }
6583             for (r = 0; r < 4; ++r) {
6584               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*4 + r;
6585               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6586             }
6587             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (p - fStart);
6588             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6589           } else if ((p >= fMax) && (p < fEnd)) {
6590             /* Hybrid faces add new faces and edges */
6591             for (r = 0; r < 2; ++r) {
6592               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (p - fMax)*2 + r;
6593               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6594             }
6595             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - fMax);
6596             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6597           } else if ((p >= cStart) && (p < cMax)) {
6598             /* Interior cells add new cells, faces, edges, and vertex */
6599             for (r = 0; r < 8; ++r) {
6600               newp = cStartNew + (p - cStart)*8 + r;
6601               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6602             }
6603             for (r = 0; r < 12; ++r) {
6604               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*12 + r;
6605               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6606             }
6607             for (r = 0; r < 6; ++r) {
6608               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (p - cStart)*6 + r;
6609               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6610             }
6611             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (p - cStart);
6612             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6613           } else if ((p >= cMax) && (p < cEnd)) {
6614             /* Hybrid cells add new cells, faces, and edges */
6615             for (r = 0; r < 4; ++r) {
6616               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
6617               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6618             }
6619             for (r = 0; r < 4; ++r) {
6620               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (p - cMax)*4 + r;
6621               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6622             }
6623             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (fEnd - fMax) + (p - cMax);
6624             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6625           }
6626           break;
6627         default:
6628           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6629         }
6630       }
6631       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
6632       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
6633     }
6634     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
6635     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
6636     if (0) {
6637       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
6638       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
6639       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
6640     }
6641   }
6642   PetscFunctionReturn(0);
6643 }
6644 
6645 #undef __FUNCT__
6646 #define __FUNCT__ "DMPlexRefineUniform_Internal"
6647 /* This will only work for interpolated meshes */
6648 PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
6649 {
6650   DM             rdm;
6651   PetscInt      *depthSize;
6652   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
6653   PetscErrorCode ierr;
6654 
6655   PetscFunctionBegin;
6656   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
6657   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
6658   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6659   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
6660   /* Calculate number of new points of each depth */
6661   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6662   ierr = PetscMalloc1((depth+1), &depthSize);CHKERRQ(ierr);
6663   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
6664   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
6665   /* Step 1: Set chart */
6666   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
6667   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
6668   /* Step 2: Set cone/support sizes */
6669   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6670   /* Step 3: Setup refined DM */
6671   ierr = DMSetUp(rdm);CHKERRQ(ierr);
6672   /* Step 4: Set cones and supports */
6673   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6674   /* Step 5: Stratify */
6675   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
6676   /* Step 6: Set coordinates for vertices */
6677   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6678   /* Step 7: Create pointSF */
6679   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6680   /* Step 8: Create labels */
6681   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6682   ierr = PetscFree(depthSize);CHKERRQ(ierr);
6683 
6684   *dmRefined = rdm;
6685   PetscFunctionReturn(0);
6686 }
6687 
6688 #undef __FUNCT__
6689 #define __FUNCT__ "DMPlexCreateCoarsePointIS"
6690 /*@
6691   DMPlexCreateCoarsePointIS - Creates an IS covering the coarse DM chart with the fine points as data
6692 
6693   Input Parameter:
6694 . dm - The coarse DM
6695 
6696   Output Parameter:
6697 . fpointIS - The IS of all the fine points which exist in the original coarse mesh
6698 
6699   Level: developer
6700 
6701 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexCreateSubpointIS()
6702 @*/
6703 PetscErrorCode DMPlexCreateCoarsePointIS(DM dm, IS *fpointIS)
6704 {
6705   CellRefiner    cellRefiner;
6706   PetscInt      *depthSize, *fpoints;
6707   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
6708   PetscInt       depth, pStart, pEnd, p, vStart, vEnd, v;
6709   PetscErrorCode ierr;
6710 
6711   PetscFunctionBegin;
6712   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6713   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6714   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6715   ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr);
6716   ierr = PetscMalloc1((depth+1), &depthSize);CHKERRQ(ierr);
6717   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
6718   if (cellRefiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
6719   ierr = PetscMalloc1(pEnd-pStart,&fpoints);CHKERRQ(ierr);
6720   for (p = 0; p < pEnd-pStart; ++p) fpoints[p] = -1;
6721   switch (cellRefiner) {
6722   case 1: /* Simplicial 2D */
6723   case 3: /* Hybrid simplicial 2D */
6724   case 2: /* Hex 2D */
6725   case 4: /* Hybrid Hex 2D */
6726   case 5: /* Simplicial 3D */
6727   case 7: /* Hybrid Simplicial 3D */
6728   case 6: /* Hex 3D */
6729   case 8: /* Hybrid Hex 3D */
6730     for (v = vStart; v < vEnd; ++v) fpoints[v-pStart] = vStartNew + (v - vStart);
6731     break;
6732   default:
6733     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", cellRefiner);
6734   }
6735   ierr = ISCreateGeneral(PETSC_COMM_SELF, pEnd-pStart, fpoints, PETSC_OWN_POINTER, fpointIS);CHKERRQ(ierr);
6736   ierr = PetscFree(depthSize);CHKERRQ(ierr);
6737   PetscFunctionReturn(0);
6738 }
6739 
6740 #undef __FUNCT__
6741 #define __FUNCT__ "DMPlexSetRefinementUniform"
6742 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
6743 {
6744   DM_Plex *mesh = (DM_Plex*) dm->data;
6745 
6746   PetscFunctionBegin;
6747   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6748   mesh->refinementUniform = refinementUniform;
6749   PetscFunctionReturn(0);
6750 }
6751 
6752 #undef __FUNCT__
6753 #define __FUNCT__ "DMPlexGetRefinementUniform"
6754 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
6755 {
6756   DM_Plex *mesh = (DM_Plex*) dm->data;
6757 
6758   PetscFunctionBegin;
6759   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6760   PetscValidPointer(refinementUniform,  2);
6761   *refinementUniform = mesh->refinementUniform;
6762   PetscFunctionReturn(0);
6763 }
6764 
6765 #undef __FUNCT__
6766 #define __FUNCT__ "DMPlexSetRefinementLimit"
6767 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
6768 {
6769   DM_Plex *mesh = (DM_Plex*) dm->data;
6770 
6771   PetscFunctionBegin;
6772   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6773   mesh->refinementLimit = refinementLimit;
6774   PetscFunctionReturn(0);
6775 }
6776 
6777 #undef __FUNCT__
6778 #define __FUNCT__ "DMPlexGetRefinementLimit"
6779 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
6780 {
6781   DM_Plex *mesh = (DM_Plex*) dm->data;
6782 
6783   PetscFunctionBegin;
6784   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6785   PetscValidPointer(refinementLimit,  2);
6786   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
6787   *refinementLimit = mesh->refinementLimit;
6788   PetscFunctionReturn(0);
6789 }
6790 
6791 #undef __FUNCT__
6792 #define __FUNCT__ "DMPlexGetCellRefiner_Internal"
6793 PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
6794 {
6795   PetscInt       dim, cStart, cEnd, coneSize, cMax;
6796   PetscErrorCode ierr;
6797 
6798   PetscFunctionBegin;
6799   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6800   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6801   if (cEnd <= cStart) {*cellRefiner = 0; PetscFunctionReturn(0);}
6802   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
6803   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
6804   switch (dim) {
6805   case 2:
6806     switch (coneSize) {
6807     case 3:
6808       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
6809       else *cellRefiner = 1; /* Triangular */
6810       break;
6811     case 4:
6812       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
6813       else *cellRefiner = 2; /* Quadrilateral */
6814       break;
6815     default:
6816       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
6817     }
6818     break;
6819   case 3:
6820     switch (coneSize) {
6821     case 4:
6822       if (cMax >= 0) *cellRefiner = 7; /* Hybrid */
6823       else *cellRefiner = 5; /* Tetrahedral */
6824       break;
6825     case 6:
6826       if (cMax >= 0) *cellRefiner = 8; /* Hybrid */
6827       else *cellRefiner = 6; /* hexahedral */
6828       break;
6829     default:
6830       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
6831     }
6832     break;
6833   default:
6834     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
6835   }
6836   PetscFunctionReturn(0);
6837 }
6838