xref: /petsc/src/dm/impls/plex/plexrefine.c (revision bed052ea5faea526473af9f209327cf55d85a03e)
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 + cEnd - cStart + fEnd - fStart; /* 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 5:
122     /* Simplicial 3D */
123     depthSize[0] =    vEnd - vStart  +    eEnd - eStart;                    /* Add a vertex on every edge */
124     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 */
125     depthSize[2] = 4*(fEnd - fStart) + 8*(cEnd - cStart);                   /* Every face split into 4 faces and 8 faces are added for each cell */
126     depthSize[3] = 8*(cEnd - cStart);                                       /* Every cell split into 8 cells */
127     break;
128   case 7:
129     /* Hybrid Simplicial 3D */
130     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
131     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
132     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
133     /* Tetrahedra */
134     depthSize[0]  =    vEnd - vStart  +    eMax - eStart;                    /* Add a vertex on every interior edge */
135     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 */
136     depthSize[2]  = 4*(fMax - fStart) + 8*(cMax - cStart);                   /* Every interior face split into 4 faces, 8 faces added for each interior cell */
137     depthSize[3]  = 8*(cMax - cStart);                                       /* Every interior cell split into 8 cells */
138     /* Triangular Prisms */
139     depthSize[0] += 0;                                                       /* No hybrid vertices */
140     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax);                     /* Every hybrid edge remains, 1 edge for every hybrid face */
141     depthSize[2] += 2*(fEnd - fMax)   + 3*(cEnd - cMax);                     /* Every hybrid face split into 2 faces and 3 faces are added for each hybrid cell */
142     depthSize[3] += 4*(cEnd - cMax);                                         /* Every hybrid cell split into 4 cells */
143     break;
144   case 6:
145     /* Hex 3D */
146     depthSize[0] = vEnd - vStart + eEnd - eStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every edge, face and cell */
147     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 */
148     depthSize[2] = 4*(fEnd - fStart) + 12*(cEnd - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
149     depthSize[3] = 8*(cEnd - cStart);                                             /* Every cell split into 8 cells */
150     break;
151   case 8:
152     /* Hybrid Hex 3D */
153     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
154     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
155     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
156     /* Hexahedra */
157     depthSize[0] = vEnd - vStart + eMax - eStart + fMax - fStart + cMax - cStart; /* Add a vertex on every edge, face and cell */
158     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 */
159     depthSize[2] = 4*(fMax - fStart) + 12*(cMax - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
160     depthSize[3] = 8*(cMax - cStart);                                             /* Every cell split into 8 cells */
161     /* Quadrilateral Prisms */
162     depthSize[0] += 0;                                                            /* No hybrid vertices */
163     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax)   +   (cEnd - cMax);      /* Every hybrid edge remains, 1 edge for every hybrid face and hybrid cell */
164     depthSize[2] += 2*(fEnd - fMax)   + 4*(cEnd - cMax);                          /* Every hybrid face split into 2 faces and 4 faces are added for each hybrid cell */
165     depthSize[3] += 4*(cEnd - cMax);                                              /* Every hybrid cell split into 4 cells */
166     break;
167   default:
168     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
169   }
170   PetscFunctionReturn(0);
171 }
172 
173 /* Return triangle edge for orientation o, if it is r for o == 0 */
174 PETSC_STATIC_INLINE PetscInt GetTriEdge_Static(PetscInt o, PetscInt r) {
175   return (o < 0 ? 2-(o+r) : o+r)%3;
176 }
177 PETSC_STATIC_INLINE PetscInt GetTriEdgeInverse_Static(PetscInt o, PetscInt s) {
178   return (o < 0 ? 2-(o+s) : 3+s-o)%3;
179 }
180 
181 /* Return triangle subface for orientation o, if it is r for o == 0 */
182 PETSC_STATIC_INLINE PetscInt GetTriSubface_Static(PetscInt o, PetscInt r) {
183   return (o < 0 ? 3-(o+r) : o+r)%3;
184 }
185 PETSC_STATIC_INLINE PetscInt GetTriSubfaceInverse_Static(PetscInt o, PetscInt s) {
186   return (o < 0 ? 3-(o+s) : 3+s-o)%3;
187 }
188 
189 /* I HAVE NO IDEA: Return ??? for orientation o, if it is r for o == 0 */
190 PETSC_STATIC_INLINE PetscInt GetTetSomething_Static(PetscInt o, PetscInt r) {
191   return (o < 0 ? 1-(o+r) : o+r)%3;
192 }
193 PETSC_STATIC_INLINE PetscInt GetTetSomethingInverse_Static(PetscInt o, PetscInt s) {
194   return (o < 0 ? 1-(o+s) : 3+s-o)%3;
195 }
196 
197 
198 /* Return quad edge for orientation o, if it is r for o == 0 */
199 PETSC_STATIC_INLINE PetscInt GetQuadEdge_Static(PetscInt o, PetscInt r) {
200   return (o < 0 ? 3-(o+r) : o+r)%4;
201 }
202 PETSC_STATIC_INLINE PetscInt GetQuadEdgeInverse_Static(PetscInt o, PetscInt s) {
203   return (o < 0 ? 3-(o+s) : 4+s-o)%4;
204 }
205 
206 /* Return quad subface for orientation o, if it is r for o == 0 */
207 PETSC_STATIC_INLINE PetscInt GetQuadSubface_Static(PetscInt o, PetscInt r) {
208   return (o < 0 ? 4-(o+r) : o+r)%4;
209 }
210 PETSC_STATIC_INLINE PetscInt GetQuadSubfaceInverse_Static(PetscInt o, PetscInt s) {
211   return (o < 0 ? 4-(o+s) : 4+s-o)%4;
212 }
213 
214 #undef __FUNCT__
215 #define __FUNCT__ "CellRefinerSetConeSizes"
216 static PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
217 {
218   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, e, r;
219   PetscErrorCode ierr;
220 
221   PetscFunctionBegin;
222   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
223   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
224   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
225   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
226   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
227   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
228   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
229   switch (refiner) {
230   case 0: break;
231   case 1:
232     /* Simplicial 2D */
233     /* All cells have 3 faces */
234     for (c = cStart; c < cEnd; ++c) {
235       for (r = 0; r < 4; ++r) {
236         const PetscInt newp = (c - cStart)*4 + r;
237 
238         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
239       }
240     }
241     /* Split faces have 2 vertices and the same cells as the parent */
242     for (f = fStart; f < fEnd; ++f) {
243       for (r = 0; r < 2; ++r) {
244         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
245         PetscInt       size;
246 
247         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
248         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
249         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
250       }
251     }
252     /* Interior faces have 2 vertices and 2 cells */
253     for (c = cStart; c < cEnd; ++c) {
254       for (r = 0; r < 3; ++r) {
255         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
256 
257         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
258         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
259       }
260     }
261     /* Old vertices have identical supports */
262     for (v = vStart; v < vEnd; ++v) {
263       const PetscInt newp = vStartNew + (v - vStart);
264       PetscInt       size;
265 
266       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
267       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
268     }
269     /* Face vertices have 2 + cells*2 supports */
270     for (f = fStart; f < fEnd; ++f) {
271       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
272       PetscInt       size;
273 
274       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
275       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
276     }
277     break;
278   case 2:
279     /* Hex 2D */
280     /* All cells have 4 faces */
281     for (c = cStart; c < cEnd; ++c) {
282       for (r = 0; r < 4; ++r) {
283         const PetscInt newp = (c - cStart)*4 + r;
284 
285         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
286       }
287     }
288     /* Split faces have 2 vertices and the same cells as the parent */
289     for (f = fStart; f < fEnd; ++f) {
290       for (r = 0; r < 2; ++r) {
291         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
292         PetscInt       size;
293 
294         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
295         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
296         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
297       }
298     }
299     /* Interior faces have 2 vertices and 2 cells */
300     for (c = cStart; c < cEnd; ++c) {
301       for (r = 0; r < 4; ++r) {
302         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
303 
304         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
305         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
306       }
307     }
308     /* Old vertices have identical supports */
309     for (v = vStart; v < vEnd; ++v) {
310       const PetscInt newp = vStartNew + (v - vStart);
311       PetscInt       size;
312 
313       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
314       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
315     }
316     /* Face vertices have 2 + cells supports */
317     for (f = fStart; f < fEnd; ++f) {
318       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
319       PetscInt       size;
320 
321       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
322       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
323     }
324     /* Cell vertices have 4 supports */
325     for (c = cStart; c < cEnd; ++c) {
326       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
327 
328       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
329     }
330     break;
331   case 3:
332     /* Hybrid Simplicial 2D */
333     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
334     cMax = PetscMin(cEnd, cMax);
335     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
336     fMax = PetscMin(fEnd, fMax);
337     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
338     /* Interior cells have 3 faces */
339     for (c = cStart; c < cMax; ++c) {
340       for (r = 0; r < 4; ++r) {
341         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
342 
343         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
344       }
345     }
346     /* Hybrid cells have 4 faces */
347     for (c = cMax; c < cEnd; ++c) {
348       for (r = 0; r < 2; ++r) {
349         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
350 
351         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
352       }
353     }
354     /* Interior split faces have 2 vertices and the same cells as the parent */
355     for (f = fStart; f < fMax; ++f) {
356       for (r = 0; r < 2; ++r) {
357         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
358         PetscInt       size;
359 
360         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
361         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
362         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
363       }
364     }
365     /* Interior cell faces have 2 vertices and 2 cells */
366     for (c = cStart; c < cMax; ++c) {
367       for (r = 0; r < 3; ++r) {
368         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
369 
370         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
371         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
372       }
373     }
374     /* Hybrid faces have 2 vertices and the same cells */
375     for (f = fMax; f < fEnd; ++f) {
376       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
377       PetscInt       size;
378 
379       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
380       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
381       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
382     }
383     /* Hybrid cell faces have 2 vertices and 2 cells */
384     for (c = cMax; c < cEnd; ++c) {
385       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
386 
387       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
388       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
389     }
390     /* Old vertices have identical supports */
391     for (v = vStart; v < vEnd; ++v) {
392       const PetscInt newp = vStartNew + (v - vStart);
393       PetscInt       size;
394 
395       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
396       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
397     }
398     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
399     for (f = fStart; f < fMax; ++f) {
400       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
401       const PetscInt *support;
402       PetscInt       size, newSize = 2, s;
403 
404       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
405       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
406       for (s = 0; s < size; ++s) {
407         if (support[s] >= cMax) newSize += 1;
408         else newSize += 2;
409       }
410       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
411     }
412     break;
413   case 5:
414     /* Simplicial 3D */
415     /* All cells have 4 faces */
416     for (c = cStart; c < cEnd; ++c) {
417       for (r = 0; r < 8; ++r) {
418         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
419 
420         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
421       }
422     }
423     /* Split faces have 3 edges and the same cells as the parent */
424     for (f = fStart; f < fEnd; ++f) {
425       for (r = 0; r < 4; ++r) {
426         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
427         PetscInt       size;
428 
429         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
430         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
431         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
432       }
433     }
434     /* Interior cell faces have 3 edges and 2 cells */
435     for (c = cStart; c < cEnd; ++c) {
436       for (r = 0; r < 8; ++r) {
437         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + r;
438 
439         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
440         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
441       }
442     }
443     /* Split edges have 2 vertices and the same faces */
444     for (e = eStart; e < eEnd; ++e) {
445       for (r = 0; r < 2; ++r) {
446         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
447         PetscInt       size;
448 
449         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
450         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
451         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
452       }
453     }
454     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
455     for (f = fStart; f < fEnd; ++f) {
456       for (r = 0; r < 3; ++r) {
457         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
458         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
459         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;
460 
461         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
462         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
463         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
464         for (s = 0; s < supportSize; ++s) {
465           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
466           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
467           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
468           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
469           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
470           er = GetTetSomethingInverse_Static(ornt[c], r);
471           if (er == eint[c]) {
472             intFaces += 1;
473           } else {
474             intFaces += 2;
475           }
476         }
477         ierr = DMPlexSetSupportSize(rdm, newp, 2+intFaces);CHKERRQ(ierr);
478       }
479     }
480     /* Interior cell edges have 2 vertices and 4 faces */
481     for (c = cStart; c < cEnd; ++c) {
482       const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
483 
484       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
485       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
486     }
487     /* Old vertices have identical supports */
488     for (v = vStart; v < vEnd; ++v) {
489       const PetscInt newp = vStartNew + (v - vStart);
490       PetscInt       size;
491 
492       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
493       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
494     }
495     /* Edge vertices have 2 + faces*2 + cells*0/1 supports */
496     for (e = eStart; e < eEnd; ++e) {
497       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
498       PetscInt       size, *star = NULL, starSize, s, cellSize = 0;
499 
500       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
501       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
502       for (s = 0; s < starSize*2; s += 2) {
503         const PetscInt *cone, *ornt;
504         PetscInt        e01, e23;
505 
506         if ((star[s] >= cStart) && (star[s] < cEnd)) {
507           /* Check edge 0-1 */
508           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
509           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
510           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
511           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
512           /* Check edge 2-3 */
513           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
514           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
515           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
516           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
517           if ((e01 == e) || (e23 == e)) ++cellSize;
518         }
519       }
520       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
521       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2 + cellSize);CHKERRQ(ierr);
522     }
523     break;
524   case 7:
525     /* Hybrid Simplicial 3D */
526     ierr = DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 8*(cMax - cStart),
527                                  eStartNew + 2*(eMax - eStart) + 3*(fMax - fStart) + (cMax - cStart), PETSC_DETERMINE);CHKERRQ(ierr);
528     /* Interior cells have 4 faces */
529     for (c = cStart; c < cMax; ++c) {
530       for (r = 0; r < 8; ++r) {
531         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
532 
533         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
534       }
535     }
536     /* Hybrid cells have 5 faces */
537     for (c = cMax; c < cEnd; ++c) {
538       for (r = 0; r < 4; ++r) {
539         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;
540 
541         ierr = DMPlexSetConeSize(rdm, newp, 5);CHKERRQ(ierr);
542       }
543     }
544     /* Interior split faces have 3 edges and the same cells as the parent */
545     for (f = fStart; f < fMax; ++f) {
546       for (r = 0; r < 4; ++r) {
547         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
548         PetscInt       size;
549 
550         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
551         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
552         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
553       }
554     }
555     /* Interior cell faces have 3 edges and 2 cells */
556     for (c = cStart; c < cMax; ++c) {
557       for (r = 0; r < 8; ++r) {
558         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + r;
559 
560         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
561         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
562       }
563     }
564     /* Hybrid split faces have 4 edges and the same cells as the parent */
565     for (f = fMax; f < fEnd; ++f) {
566       for (r = 0; r < 2; ++r) {
567         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
568         PetscInt       size;
569 
570         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
571         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
572         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
573       }
574     }
575     /* Hybrid cells faces have 4 edges and 2 cells */
576     for (c = cMax; c < cEnd; ++c) {
577       for (r = 0; r < 3; ++r) {
578         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + r;
579 
580         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
581         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
582       }
583     }
584     /* Interior split edges have 2 vertices and the same faces */
585     for (e = eStart; e < eMax; ++e) {
586       for (r = 0; r < 2; ++r) {
587         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
588         PetscInt       size;
589 
590         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
591         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
592         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
593       }
594     }
595     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
596     for (f = fStart; f < fMax; ++f) {
597       for (r = 0; r < 3; ++r) {
598         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
599         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
600         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;
601 
602         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
603         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
604         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
605         for (s = 0; s < supportSize; ++s) {
606           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
607           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
608           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
609           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
610           if (support[s] < cMax) {
611             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
612             er = GetTetSomethingInverse_Static(ornt[c], r);
613             if (er == eint[c]) {
614               intFaces += 1;
615             } else {
616               intFaces += 2;
617             }
618           } else {
619             intFaces += 1;
620           }
621         }
622         ierr = DMPlexSetSupportSize(rdm, newp, 2+intFaces);CHKERRQ(ierr);
623       }
624     }
625     /* Interior cell edges have 2 vertices and 4 faces */
626     for (c = cStart; c < cMax; ++c) {
627       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
628 
629       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
630       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
631     }
632     /* Hybrid edges have 2 vertices and the same faces */
633     for (e = eMax; e < eEnd; ++e) {
634       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
635       PetscInt       size;
636 
637       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
638       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
639       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
640     }
641     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
642     for (f = fMax; f < fEnd; ++f) {
643       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
644       PetscInt       size;
645 
646       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
647       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
648       ierr = DMPlexSetSupportSize(rdm, newp, 2+2*size);CHKERRQ(ierr);
649     }
650     /* Interior vertices have identical supports */
651     for (v = vStart; v < vEnd; ++v) {
652       const PetscInt newp = vStartNew + (v - vStart);
653       PetscInt       size;
654 
655       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
656       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
657     }
658     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
659     for (e = eStart; e < eMax; ++e) {
660       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
661       const PetscInt *support;
662       PetscInt        size, *star = NULL, starSize, s, faceSize = 0, cellSize = 0;
663 
664       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
665       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
666       for (s = 0; s < size; ++s) {
667         if (support[s] < fMax) faceSize += 2;
668         else                   faceSize += 1;
669       }
670       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
671       for (s = 0; s < starSize*2; s += 2) {
672         const PetscInt *cone, *ornt;
673         PetscInt        e01, e23;
674 
675         if ((star[s] >= cStart) && (star[s] < cMax)) {
676           /* Check edge 0-1 */
677           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
678           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
679           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
680           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
681           /* Check edge 2-3 */
682           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
683           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
684           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
685           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
686           if ((e01 == e) || (e23 == e)) ++cellSize;
687         }
688       }
689       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
690       ierr = DMPlexSetSupportSize(rdm, newp, 2 + faceSize + cellSize);CHKERRQ(ierr);
691     }
692     break;
693   case 6:
694     /* Hex 3D */
695     /* All cells have 6 faces */
696     for (c = cStart; c < cEnd; ++c) {
697       for (r = 0; r < 8; ++r) {
698         const PetscInt newp = (c - cStart)*8 + r;
699 
700         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
701       }
702     }
703     /* Split faces have 4 edges and the same cells as the parent */
704     for (f = fStart; f < fEnd; ++f) {
705       for (r = 0; r < 4; ++r) {
706         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
707         PetscInt       size;
708 
709         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
710         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
711         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
712       }
713     }
714     /* Interior faces have 4 edges and 2 cells */
715     for (c = cStart; c < cEnd; ++c) {
716       for (r = 0; r < 12; ++r) {
717         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
718 
719         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
720         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
721       }
722     }
723     /* Split edges have 2 vertices and the same faces as the parent */
724     for (e = eStart; e < eEnd; ++e) {
725       for (r = 0; r < 2; ++r) {
726         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
727         PetscInt       size;
728 
729         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
730         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
731         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
732       }
733     }
734     /* Face edges have 2 vertices and 2+cells faces */
735     for (f = fStart; f < fEnd; ++f) {
736       for (r = 0; r < 4; ++r) {
737         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
738         PetscInt       size;
739 
740         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
741         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
742         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
743       }
744     }
745     /* Cell edges have 2 vertices and 4 faces */
746     for (c = cStart; c < cEnd; ++c) {
747       for (r = 0; r < 6; ++r) {
748         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
749 
750         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
751         ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
752       }
753     }
754     /* Old vertices have identical supports */
755     for (v = vStart; v < vEnd; ++v) {
756       const PetscInt newp = vStartNew + (v - vStart);
757       PetscInt       size;
758 
759       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
760       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
761     }
762     /* Edge vertices have 2 + faces supports */
763     for (e = eStart; e < eEnd; ++e) {
764       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
765       PetscInt       size;
766 
767       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
768       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
769     }
770     /* Face vertices have 4 + cells supports */
771     for (f = fStart; f < fEnd; ++f) {
772       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
773       PetscInt       size;
774 
775       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
776       ierr = DMPlexSetSupportSize(rdm, newp, 4 + size);CHKERRQ(ierr);
777     }
778     /* Cell vertices have 6 supports */
779     for (c = cStart; c < cEnd; ++c) {
780       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
781 
782       ierr = DMPlexSetSupportSize(rdm, newp, 6);CHKERRQ(ierr);
783     }
784     break;
785   case 8:
786     /* Hybrid Hex 3D */
787     ierr = DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 12*(cMax - cStart),
788                                  eStartNew + 2*(eMax - eStart) + 4*(fMax - fStart) + 6*(cMax - cStart), PETSC_DETERMINE);CHKERRQ(ierr);
789     /* Interior cells have 6 faces */
790     for (c = cStart; c < cMax; ++c) {
791       for (r = 0; r < 8; ++r) {
792         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
793 
794         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
795       }
796     }
797     /* Hybrid cells have 6 faces */
798     for (c = cMax; c < cEnd; ++c) {
799       for (r = 0; r < 4; ++r) {
800         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;
801 
802         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
803       }
804     }
805     /* Interior split faces have 4 edges and the same cells as the parent */
806     for (f = fStart; f < fMax; ++f) {
807       for (r = 0; r < 4; ++r) {
808         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
809         PetscInt       size;
810 
811         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
812         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
813         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
814       }
815     }
816     /* Interior cell faces have 4 edges and 2 cells */
817     for (c = cStart; c < cMax; ++c) {
818       for (r = 0; r < 12; ++r) {
819         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
820 
821         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
822         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
823       }
824     }
825     /* Hybrid split faces have 4 edges and the same cells as the parent */
826     for (f = fMax; f < fEnd; ++f) {
827       for (r = 0; r < 2; ++r) {
828         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
829         PetscInt       size;
830 
831         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
832         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
833         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
834       }
835     }
836     /* Hybrid cells faces have 4 edges and 2 cells */
837     for (c = cMax; c < cEnd; ++c) {
838       for (r = 0; r < 4; ++r) {
839         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + r;
840 
841         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
842         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
843       }
844     }
845     /* Interior split edges have 2 vertices and the same faces as the parent */
846     for (e = eStart; e < eMax; ++e) {
847       for (r = 0; r < 2; ++r) {
848         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
849         PetscInt       size;
850 
851         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
852         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
853         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
854       }
855     }
856     /* Interior face edges have 2 vertices and 2+cells faces */
857     for (f = fStart; f < fMax; ++f) {
858       for (r = 0; r < 4; ++r) {
859         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
860         PetscInt       size;
861 
862         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
863         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
864         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
865       }
866     }
867     /* Interior cell edges have 2 vertices and 4 faces */
868     for (c = cStart; c < cMax; ++c) {
869       for (r = 0; r < 6; ++r) {
870         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
871 
872         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
873         ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
874       }
875     }
876     /* Hybrid edges have 2 vertices and the same faces */
877     for (e = eMax; e < eEnd; ++e) {
878       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
879       PetscInt       size;
880 
881       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
882       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
883       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
884     }
885     /* Hybrid face edges have 2 vertices and 2+cells faces */
886     for (f = fMax; f < fEnd; ++f) {
887       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
888       PetscInt       size;
889 
890       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
891       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
892       ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
893     }
894     /* Hybrid cell edges have 2 vertices and 4 faces */
895     for (c = cMax; c < cEnd; ++c) {
896       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
897 
898       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
899       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
900     }
901     /* Interior vertices have identical supports */
902     for (v = vStart; v < vEnd; ++v) {
903       const PetscInt newp = vStartNew + (v - vStart);
904       PetscInt       size;
905 
906       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
907       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
908     }
909     /* Interior edge vertices have 2 + faces supports */
910     for (e = eStart; e < eMax; ++e) {
911       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
912       PetscInt       size;
913 
914       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
915       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
916     }
917     /* Interior face vertices have 4 + cells supports */
918     for (f = fStart; f < fMax; ++f) {
919       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
920       PetscInt       size;
921 
922       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
923       ierr = DMPlexSetSupportSize(rdm, newp, 4 + size);CHKERRQ(ierr);
924     }
925     /* Interior cell vertices have 6 supports */
926     for (c = cStart; c < cMax; ++c) {
927       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
928 
929       ierr = DMPlexSetSupportSize(rdm, newp, 6);CHKERRQ(ierr);
930     }
931     break;
932   default:
933     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
934   }
935   PetscFunctionReturn(0);
936 }
937 
938 #undef __FUNCT__
939 #define __FUNCT__ "CellRefinerSetCones"
940 static PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
941 {
942   const PetscInt *faces, cellInd[4] = {0, 1, 2, 3};
943   PetscInt        cStart,    cEnd,    cMax,    vStart,    vEnd, vMax, fStart,    fEnd,    fMax,    eStart,    eEnd,    eMax;
944   PetscInt        cStartNew, cEndNew, cMaxNew, vStartNew, vEndNew,    fStartNew, fEndNew, fMaxNew, eStartNew, eEndNew, eMaxNew;
945   PetscInt        depth, maxSupportSize, *supportRef, c, f, e, v, r, p;
946   PetscErrorCode  ierr;
947 
948   PetscFunctionBegin;
949   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
950   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
951   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
952   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
953   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
954   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
955   if (refiner) {
956     ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
957     ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
958   }
959   switch (refiner) {
960   case 0: break;
961   case 1:
962     /* Simplicial 2D */
963     /*
964      2
965      |\
966      | \
967      |  \
968      |   \
969      | C  \
970      |     \
971      |      \
972      2---1---1
973      |\  D  / \
974      | 2   0   \
975      |A \ /  B  \
976      0---0-------1
977      */
978     /* All cells have 3 faces */
979     for (c = cStart; c < cEnd; ++c) {
980       const PetscInt  newp = cStartNew + (c - cStart)*4;
981       const PetscInt *cone, *ornt;
982       PetscInt        coneNew[3], orntNew[3];
983 
984       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
985       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
986       /* A triangle */
987       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
988       orntNew[0] = ornt[0];
989       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
990       orntNew[1] = -2;
991       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
992       orntNew[2] = ornt[2];
993       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
994       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
995 #if 1
996       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);
997       for (p = 0; p < 3; ++p) {
998         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);
999       }
1000 #endif
1001       /* B triangle */
1002       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1003       orntNew[0] = ornt[0];
1004       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1005       orntNew[1] = ornt[1];
1006       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1007       orntNew[2] = -2;
1008       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1009       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1010 #if 1
1011       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);
1012       for (p = 0; p < 3; ++p) {
1013         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);
1014       }
1015 #endif
1016       /* C triangle */
1017       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1018       orntNew[0] = -2;
1019       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1020       orntNew[1] = ornt[1];
1021       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1022       orntNew[2] = ornt[2];
1023       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1024       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1025 #if 1
1026       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);
1027       for (p = 0; p < 3; ++p) {
1028         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);
1029       }
1030 #endif
1031       /* D triangle */
1032       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1033       orntNew[0] = 0;
1034       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1035       orntNew[1] = 0;
1036       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1037       orntNew[2] = 0;
1038       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1039       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1040 #if 1
1041       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);
1042       for (p = 0; p < 3; ++p) {
1043         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);
1044       }
1045 #endif
1046     }
1047     /* Split faces have 2 vertices and the same cells as the parent */
1048     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1049     ierr = PetscMalloc1((2 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
1050     for (f = fStart; f < fEnd; ++f) {
1051       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1052 
1053       for (r = 0; r < 2; ++r) {
1054         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1055         const PetscInt *cone, *ornt, *support;
1056         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1057 
1058         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1059         coneNew[0]       = vStartNew + (cone[0] - vStart);
1060         coneNew[1]       = vStartNew + (cone[1] - vStart);
1061         coneNew[(r+1)%2] = newv;
1062         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1063 #if 1
1064         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1065         for (p = 0; p < 2; ++p) {
1066           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);
1067         }
1068 #endif
1069         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1070         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1071         for (s = 0; s < supportSize; ++s) {
1072           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1073           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1074           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1075           for (c = 0; c < coneSize; ++c) {
1076             if (cone[c] == f) break;
1077           }
1078           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1079         }
1080         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1081 #if 1
1082         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1083         for (p = 0; p < supportSize; ++p) {
1084           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);
1085         }
1086 #endif
1087       }
1088     }
1089     /* Interior faces have 2 vertices and 2 cells */
1090     for (c = cStart; c < cEnd; ++c) {
1091       const PetscInt *cone;
1092 
1093       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1094       for (r = 0; r < 3; ++r) {
1095         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
1096         PetscInt       coneNew[2];
1097         PetscInt       supportNew[2];
1098 
1099         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
1100         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
1101         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1102 #if 1
1103         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1104         for (p = 0; p < 2; ++p) {
1105           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);
1106         }
1107 #endif
1108         supportNew[0] = (c - cStart)*4 + (r+1)%3;
1109         supportNew[1] = (c - cStart)*4 + 3;
1110         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1111 #if 1
1112         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1113         for (p = 0; p < 2; ++p) {
1114           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);
1115         }
1116 #endif
1117       }
1118     }
1119     /* Old vertices have identical supports */
1120     for (v = vStart; v < vEnd; ++v) {
1121       const PetscInt  newp = vStartNew + (v - vStart);
1122       const PetscInt *support, *cone;
1123       PetscInt        size, s;
1124 
1125       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1126       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1127       for (s = 0; s < size; ++s) {
1128         PetscInt r = 0;
1129 
1130         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1131         if (cone[1] == v) r = 1;
1132         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1133       }
1134       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1135 #if 1
1136       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1137       for (p = 0; p < size; ++p) {
1138         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);
1139       }
1140 #endif
1141     }
1142     /* Face vertices have 2 + cells*2 supports */
1143     for (f = fStart; f < fEnd; ++f) {
1144       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1145       const PetscInt *cone, *support;
1146       PetscInt        size, s;
1147 
1148       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1149       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1150       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1151       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1152       for (s = 0; s < size; ++s) {
1153         PetscInt r = 0;
1154 
1155         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1156         if      (cone[1] == f) r = 1;
1157         else if (cone[2] == f) r = 2;
1158         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
1159         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
1160       }
1161       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1162 #if 1
1163       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1164       for (p = 0; p < 2+size*2; ++p) {
1165         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);
1166       }
1167 #endif
1168     }
1169     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1170     break;
1171   case 2:
1172     /* Hex 2D */
1173     /*
1174      3---------2---------2
1175      |         |         |
1176      |    D    2    C    |
1177      |         |         |
1178      3----3----0----1----1
1179      |         |         |
1180      |    A    0    B    |
1181      |         |         |
1182      0---------0---------1
1183      */
1184     /* All cells have 4 faces */
1185     for (c = cStart; c < cEnd; ++c) {
1186       const PetscInt  newp = (c - cStart)*4;
1187       const PetscInt *cone, *ornt;
1188       PetscInt        coneNew[4], orntNew[4];
1189 
1190       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1191       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1192       /* A quad */
1193       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1194       orntNew[0] = ornt[0];
1195       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
1196       orntNew[1] = 0;
1197       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
1198       orntNew[2] = -2;
1199       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
1200       orntNew[3] = ornt[3];
1201       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1202       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1203 #if 1
1204       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);
1205       for (p = 0; p < 4; ++p) {
1206         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);
1207       }
1208 #endif
1209       /* B quad */
1210       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1211       orntNew[0] = ornt[0];
1212       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1213       orntNew[1] = ornt[1];
1214       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
1215       orntNew[2] = 0;
1216       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
1217       orntNew[3] = -2;
1218       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1219       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1220 #if 1
1221       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);
1222       for (p = 0; p < 4; ++p) {
1223         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1224       }
1225 #endif
1226       /* C quad */
1227       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
1228       orntNew[0] = -2;
1229       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1230       orntNew[1] = ornt[1];
1231       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1232       orntNew[2] = ornt[2];
1233       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
1234       orntNew[3] = 0;
1235       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1236       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1237 #if 1
1238       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);
1239       for (p = 0; p < 4; ++p) {
1240         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);
1241       }
1242 #endif
1243       /* D quad */
1244       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
1245       orntNew[0] = 0;
1246       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
1247       orntNew[1] = -2;
1248       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1249       orntNew[2] = ornt[2];
1250       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
1251       orntNew[3] = ornt[3];
1252       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1253       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1254 #if 1
1255       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);
1256       for (p = 0; p < 4; ++p) {
1257         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);
1258       }
1259 #endif
1260     }
1261     /* Split faces have 2 vertices and the same cells as the parent */
1262     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1263     ierr = PetscMalloc1((2 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
1264     for (f = fStart; f < fEnd; ++f) {
1265       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1266 
1267       for (r = 0; r < 2; ++r) {
1268         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1269         const PetscInt *cone, *ornt, *support;
1270         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1271 
1272         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1273         coneNew[0]       = vStartNew + (cone[0] - vStart);
1274         coneNew[1]       = vStartNew + (cone[1] - vStart);
1275         coneNew[(r+1)%2] = newv;
1276         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1277 #if 1
1278         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1279         for (p = 0; p < 2; ++p) {
1280           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);
1281         }
1282 #endif
1283         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1284         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1285         for (s = 0; s < supportSize; ++s) {
1286           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1287           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1288           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1289           for (c = 0; c < coneSize; ++c) {
1290             if (cone[c] == f) break;
1291           }
1292           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
1293         }
1294         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1295 #if 1
1296         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1297         for (p = 0; p < supportSize; ++p) {
1298           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);
1299         }
1300 #endif
1301       }
1302     }
1303     /* Interior faces have 2 vertices and 2 cells */
1304     for (c = cStart; c < cEnd; ++c) {
1305       const PetscInt *cone;
1306       PetscInt        coneNew[2], supportNew[2];
1307 
1308       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1309       for (r = 0; r < 4; ++r) {
1310         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
1311 
1312         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
1313         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
1314         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1315 #if 1
1316         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1317         for (p = 0; p < 2; ++p) {
1318           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);
1319         }
1320 #endif
1321         supportNew[0] = (c - cStart)*4 + r;
1322         supportNew[1] = (c - cStart)*4 + (r+1)%4;
1323         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1324 #if 1
1325         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1326         for (p = 0; p < 2; ++p) {
1327           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);
1328         }
1329 #endif
1330       }
1331     }
1332     /* Old vertices have identical supports */
1333     for (v = vStart; v < vEnd; ++v) {
1334       const PetscInt  newp = vStartNew + (v - vStart);
1335       const PetscInt *support, *cone;
1336       PetscInt        size, s;
1337 
1338       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1339       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1340       for (s = 0; s < size; ++s) {
1341         PetscInt r = 0;
1342 
1343         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1344         if (cone[1] == v) r = 1;
1345         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1346       }
1347       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1348 #if 1
1349       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1350       for (p = 0; p < size; ++p) {
1351         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);
1352       }
1353 #endif
1354     }
1355     /* Face vertices have 2 + cells supports */
1356     for (f = fStart; f < fEnd; ++f) {
1357       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1358       const PetscInt *cone, *support;
1359       PetscInt        size, s;
1360 
1361       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1362       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1363       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1364       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1365       for (s = 0; s < size; ++s) {
1366         PetscInt r = 0;
1367 
1368         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1369         if      (cone[1] == f) r = 1;
1370         else if (cone[2] == f) r = 2;
1371         else if (cone[3] == f) r = 3;
1372         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
1373       }
1374       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1375 #if 1
1376       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1377       for (p = 0; p < 2+size; ++p) {
1378         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);
1379       }
1380 #endif
1381     }
1382     /* Cell vertices have 4 supports */
1383     for (c = cStart; c < cEnd; ++c) {
1384       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
1385       PetscInt       supportNew[4];
1386 
1387       for (r = 0; r < 4; ++r) {
1388         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
1389       }
1390       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1391     }
1392     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1393     break;
1394   case 3:
1395     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
1396     cMax = PetscMin(cEnd, cMax);
1397     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
1398     fMax = PetscMin(fEnd, fMax);
1399     /* Interior cells have 3 faces */
1400     for (c = cStart; c < cMax; ++c) {
1401       const PetscInt  newp = cStartNew + (c - cStart)*4;
1402       const PetscInt *cone, *ornt;
1403       PetscInt        coneNew[3], orntNew[3];
1404 
1405       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1406       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1407       /* A triangle */
1408       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1409       orntNew[0] = ornt[0];
1410       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
1411       orntNew[1] = -2;
1412       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1413       orntNew[2] = ornt[2];
1414       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1415       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1416 #if 1
1417       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);
1418       for (p = 0; p < 3; ++p) {
1419         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);
1420       }
1421 #endif
1422       /* B triangle */
1423       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1424       orntNew[0] = ornt[0];
1425       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1426       orntNew[1] = ornt[1];
1427       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
1428       orntNew[2] = -2;
1429       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1430       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1431 #if 1
1432       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);
1433       for (p = 0; p < 3; ++p) {
1434         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);
1435       }
1436 #endif
1437       /* C triangle */
1438       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
1439       orntNew[0] = -2;
1440       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1441       orntNew[1] = ornt[1];
1442       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1443       orntNew[2] = ornt[2];
1444       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1445       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1446 #if 1
1447       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);
1448       for (p = 0; p < 3; ++p) {
1449         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);
1450       }
1451 #endif
1452       /* D triangle */
1453       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
1454       orntNew[0] = 0;
1455       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
1456       orntNew[1] = 0;
1457       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
1458       orntNew[2] = 0;
1459       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1460       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1461 #if 1
1462       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);
1463       for (p = 0; p < 3; ++p) {
1464         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);
1465       }
1466 #endif
1467     }
1468     /*
1469      2----3----3
1470      |         |
1471      |    B    |
1472      |         |
1473      0----4--- 1
1474      |         |
1475      |    A    |
1476      |         |
1477      0----2----1
1478      */
1479     /* Hybrid cells have 4 faces */
1480     for (c = cMax; c < cEnd; ++c) {
1481       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
1482       const PetscInt *cone, *ornt;
1483       PetscInt        coneNew[4], orntNew[4];
1484 
1485       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1486       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1487       /* A quad */
1488       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1489       orntNew[0] = ornt[0];
1490       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1491       orntNew[1] = ornt[1];
1492       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
1493       orntNew[2] = 0;
1494       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
1495       orntNew[3] = 0;
1496       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1497       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1498 #if 1
1499       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);
1500       for (p = 0; p < 4; ++p) {
1501         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);
1502       }
1503 #endif
1504       /* B quad */
1505       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1506       orntNew[0] = ornt[0];
1507       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1508       orntNew[1] = ornt[1];
1509       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
1510       orntNew[2] = 0;
1511       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
1512       orntNew[3] = 0;
1513       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1514       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1515 #if 1
1516       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);
1517       for (p = 0; p < 4; ++p) {
1518         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);
1519       }
1520 #endif
1521     }
1522     /* Interior split faces have 2 vertices and the same cells as the parent */
1523     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1524     ierr = PetscMalloc1((2 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
1525     for (f = fStart; f < fMax; ++f) {
1526       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1527 
1528       for (r = 0; r < 2; ++r) {
1529         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1530         const PetscInt *cone, *ornt, *support;
1531         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1532 
1533         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1534         coneNew[0]       = vStartNew + (cone[0] - vStart);
1535         coneNew[1]       = vStartNew + (cone[1] - vStart);
1536         coneNew[(r+1)%2] = newv;
1537         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1538 #if 1
1539         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1540         for (p = 0; p < 2; ++p) {
1541           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);
1542         }
1543 #endif
1544         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1545         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1546         for (s = 0; s < supportSize; ++s) {
1547           if (support[s] >= cMax) {
1548             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
1549           } else {
1550             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1551             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1552             ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1553             for (c = 0; c < coneSize; ++c) {
1554               if (cone[c] == f) break;
1555             }
1556             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1557           }
1558         }
1559         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1560 #if 1
1561         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1562         for (p = 0; p < supportSize; ++p) {
1563           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);
1564         }
1565 #endif
1566       }
1567     }
1568     /* Interior cell faces have 2 vertices and 2 cells */
1569     for (c = cStart; c < cMax; ++c) {
1570       const PetscInt *cone;
1571 
1572       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1573       for (r = 0; r < 3; ++r) {
1574         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
1575         PetscInt       coneNew[2];
1576         PetscInt       supportNew[2];
1577 
1578         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
1579         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
1580         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1581 #if 1
1582         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1583         for (p = 0; p < 2; ++p) {
1584           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);
1585         }
1586 #endif
1587         supportNew[0] = (c - cStart)*4 + (r+1)%3;
1588         supportNew[1] = (c - cStart)*4 + 3;
1589         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1590 #if 1
1591         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1592         for (p = 0; p < 2; ++p) {
1593           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);
1594         }
1595 #endif
1596       }
1597     }
1598     /* Interior hybrid faces have 2 vertices and the same cells */
1599     for (f = fMax; f < fEnd; ++f) {
1600       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
1601       const PetscInt *cone;
1602       const PetscInt *support;
1603       PetscInt        coneNew[2];
1604       PetscInt        supportNew[2];
1605       PetscInt        size, s, r;
1606 
1607       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1608       coneNew[0] = vStartNew + (cone[0] - vStart);
1609       coneNew[1] = vStartNew + (cone[1] - vStart);
1610       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1611 #if 1
1612       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1613       for (p = 0; p < 2; ++p) {
1614         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);
1615       }
1616 #endif
1617       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1618       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1619       for (s = 0; s < size; ++s) {
1620         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1621         for (r = 0; r < 2; ++r) {
1622           if (cone[r+2] == f) break;
1623         }
1624         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
1625       }
1626       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1627 #if 1
1628       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1629       for (p = 0; p < size; ++p) {
1630         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);
1631       }
1632 #endif
1633     }
1634     /* Cell hybrid faces have 2 vertices and 2 cells */
1635     for (c = cMax; c < cEnd; ++c) {
1636       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
1637       const PetscInt *cone;
1638       PetscInt        coneNew[2];
1639       PetscInt        supportNew[2];
1640 
1641       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1642       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
1643       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
1644       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1645 #if 1
1646       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1647       for (p = 0; p < 2; ++p) {
1648         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);
1649       }
1650 #endif
1651       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
1652       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
1653       ierr          = DMPlexSetSupport(rdm, newp, supportNew);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 < 2; ++p) {
1657         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);
1658       }
1659 #endif
1660     }
1661     /* Old vertices have identical supports */
1662     for (v = vStart; v < vEnd; ++v) {
1663       const PetscInt  newp = vStartNew + (v - vStart);
1664       const PetscInt *support, *cone;
1665       PetscInt        size, s;
1666 
1667       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1668       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1669       for (s = 0; s < size; ++s) {
1670         if (support[s] >= fMax) {
1671           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
1672         } else {
1673           PetscInt r = 0;
1674 
1675           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1676           if (cone[1] == v) r = 1;
1677           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1678         }
1679       }
1680       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1681 #if 1
1682       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1683       for (p = 0; p < size; ++p) {
1684         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);
1685       }
1686 #endif
1687     }
1688     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
1689     for (f = fStart; f < fMax; ++f) {
1690       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1691       const PetscInt *cone, *support;
1692       PetscInt        size, newSize = 2, s;
1693 
1694       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1695       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1696       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1697       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1698       for (s = 0; s < size; ++s) {
1699         PetscInt r = 0;
1700 
1701         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1702         if (support[s] >= cMax) {
1703           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
1704 
1705           newSize += 1;
1706         } else {
1707           if      (cone[1] == f) r = 1;
1708           else if (cone[2] == f) r = 2;
1709           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
1710           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
1711 
1712           newSize += 2;
1713         }
1714       }
1715       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1716 #if 1
1717       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1718       for (p = 0; p < newSize; ++p) {
1719         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);
1720       }
1721 #endif
1722     }
1723     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1724     break;
1725   case 5:
1726     /* Simplicial 3D */
1727     /* All cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
1728     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
1729     for (c = cStart; c < cEnd; ++c) {
1730       const PetscInt  newp = cStartNew + (c - cStart)*8;
1731       const PetscInt *cone, *ornt;
1732       PetscInt        coneNew[4], orntNew[4];
1733 
1734       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1735       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1736       /* A tetrahedron: {0, a, c, d} */
1737       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
1738       orntNew[0] = ornt[0];
1739       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
1740       orntNew[1] = ornt[1];
1741       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
1742       orntNew[2] = ornt[2];
1743       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
1744       orntNew[3] = 0;
1745       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1746       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1747 #if 1
1748       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);
1749       for (p = 0; p < 4; ++p) {
1750         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);
1751       }
1752 #endif
1753       /* B tetrahedron: {a, 1, b, e} */
1754       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
1755       orntNew[0] = ornt[0];
1756       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
1757       orntNew[1] = ornt[1];
1758       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
1759       orntNew[2] = 0;
1760       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
1761       orntNew[3] = ornt[3];
1762       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1763       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1764 #if 1
1765       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);
1766       for (p = 0; p < 4; ++p) {
1767         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);
1768       }
1769 #endif
1770       /* C tetrahedron: {c, b, 2, f} */
1771       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
1772       orntNew[0] = ornt[0];
1773       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
1774       orntNew[1] = 0;
1775       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
1776       orntNew[2] = ornt[2];
1777       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
1778       orntNew[3] = ornt[3];
1779       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1780       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1781 #if 1
1782       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);
1783       for (p = 0; p < 4; ++p) {
1784         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);
1785       }
1786 #endif
1787       /* D tetrahedron: {d, e, f, 3} */
1788       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
1789       orntNew[0] = 0;
1790       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
1791       orntNew[1] = ornt[1];
1792       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
1793       orntNew[2] = ornt[2];
1794       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
1795       orntNew[3] = ornt[3];
1796       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1797       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1798 #if 1
1799       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);
1800       for (p = 0; p < 4; ++p) {
1801         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);
1802       }
1803 #endif
1804       /* A' tetrahedron: {d, a, c, f} */
1805       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
1806       orntNew[0] = -3;
1807       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
1808       orntNew[1] = ornt[2] < 0 ? -(GetTetSomething_Static(ornt[2], 0)+1) : GetTetSomething_Static(ornt[2], 0);
1809       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
1810       orntNew[2] = 0;
1811       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
1812       orntNew[3] = 2;
1813       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
1814       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
1815 #if 1
1816       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);
1817       for (p = 0; p < 4; ++p) {
1818         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);
1819       }
1820 #endif
1821       /* B' tetrahedron: {e, b, a, f} */
1822       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
1823       orntNew[0] = -3;
1824       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
1825       orntNew[1] = 1;
1826       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
1827       orntNew[2] = 0;
1828       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + 3;
1829       orntNew[3] = ornt[3] < 0 ? -(GetTetSomething_Static(ornt[3], 0)+1) : GetTetSomething_Static(ornt[3], 0);
1830       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
1831       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
1832 #if 1
1833       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);
1834       for (p = 0; p < 4; ++p) {
1835         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);
1836       }
1837 #endif
1838       /* C' tetrahedron: {b, f, c, a} */
1839       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
1840       orntNew[0] = -3;
1841       coneNew[1] = fStartNew + (cone[0] - fStart)*4 + 3;
1842       orntNew[1] = ornt[0] < 0 ? -(GetTetSomething_Static(ornt[0], 2)+1) : GetTetSomething_Static(ornt[0], 2);
1843       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
1844       orntNew[2] = -3;
1845       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
1846       orntNew[3] = -2;
1847       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
1848       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
1849 #if 1
1850       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);
1851       for (p = 0; p < 4; ++p) {
1852         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);
1853       }
1854 #endif
1855       /* D' tetrahedron: {f, e, d, a} */
1856       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
1857       orntNew[0] = -3;
1858       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
1859       orntNew[1] = -3;
1860       coneNew[2] = fStartNew + (cone[1] - fStart)*4 + 3;
1861       orntNew[2] = ornt[1] < 0 ? -(GetTetSomething_Static(ornt[1], 0)+1) : GetTetSomething_Static(ornt[1], 0);
1862       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
1863       orntNew[3] = -3;
1864       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
1865       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
1866 #if 1
1867       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);
1868       for (p = 0; p < 4; ++p) {
1869         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);
1870       }
1871 #endif
1872     }
1873     /* Split faces have 3 edges and the same cells as the parent */
1874     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1875     ierr = PetscMalloc1((2 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
1876     for (f = fStart; f < fEnd; ++f) {
1877       const PetscInt  newp = fStartNew + (f - fStart)*4;
1878       const PetscInt *cone, *ornt, *support;
1879       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
1880 
1881       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1882       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
1883       /* A triangle */
1884       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
1885       orntNew[0] = ornt[0];
1886       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
1887       orntNew[1] = -2;
1888       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
1889       orntNew[2] = ornt[2];
1890       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1891       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1892 #if 1
1893       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);
1894       for (p = 0; p < 3; ++p) {
1895         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);
1896       }
1897 #endif
1898       /* B triangle */
1899       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
1900       orntNew[0] = ornt[0];
1901       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
1902       orntNew[1] = ornt[1];
1903       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
1904       orntNew[2] = -2;
1905       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1906       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1907 #if 1
1908       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);
1909       for (p = 0; p < 3; ++p) {
1910         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);
1911       }
1912 #endif
1913       /* C triangle */
1914       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
1915       orntNew[0] = -2;
1916       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
1917       orntNew[1] = ornt[1];
1918       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
1919       orntNew[2] = ornt[2];
1920       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1921       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1922 #if 1
1923       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);
1924       for (p = 0; p < 3; ++p) {
1925         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);
1926       }
1927 #endif
1928       /* D triangle */
1929       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
1930       orntNew[0] = 0;
1931       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
1932       orntNew[1] = 0;
1933       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
1934       orntNew[2] = 0;
1935       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1936       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1937 #if 1
1938       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);
1939       for (p = 0; p < 3; ++p) {
1940         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);
1941       }
1942 #endif
1943       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1944       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1945       for (r = 0; r < 4; ++r) {
1946         for (s = 0; s < supportSize; ++s) {
1947           PetscInt subf;
1948           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1949           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1950           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1951           for (c = 0; c < coneSize; ++c) {
1952             if (cone[c] == f) break;
1953           }
1954           subf = GetTriSubfaceInverse_Static(ornt[c], r);
1955           supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
1956         }
1957         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
1958 #if 1
1959         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);
1960         for (p = 0; p < supportSize; ++p) {
1961           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);
1962         }
1963 #endif
1964       }
1965     }
1966     /* Interior faces have 3 edges and 2 cells */
1967     for (c = cStart; c < cEnd; ++c) {
1968       PetscInt        newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8;
1969       const PetscInt *cone, *ornt;
1970       PetscInt        coneNew[3], orntNew[3];
1971       PetscInt        supportNew[2];
1972 
1973       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1974       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1975       /* Face A: {c, a, d} */
1976       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
1977       orntNew[0] = ornt[0] < 0 ? -2 : 0;
1978       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
1979       orntNew[1] = ornt[1] < 0 ? -2 : 0;
1980       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 2);
1981       orntNew[2] = ornt[2] < 0 ? -2 : 0;
1982       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1983       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
1984 #if 1
1985       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1986       for (p = 0; p < 3; ++p) {
1987         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);
1988       }
1989 #endif
1990       supportNew[0] = (c - cStart)*8 + 0;
1991       supportNew[1] = (c - cStart)*8 + 0+4;
1992       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1993 #if 1
1994       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1995       for (p = 0; p < 2; ++p) {
1996         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);
1997       }
1998 #endif
1999       ++newp;
2000       /* Face B: {a, b, e} */
2001       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
2002       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2003       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 0);
2004       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2005       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
2006       orntNew[2] = ornt[1] < 0 ? -2 : 0;
2007       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2008       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2009 #if 1
2010       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2011       for (p = 0; p < 3; ++p) {
2012         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);
2013       }
2014 #endif
2015       supportNew[0] = (c - cStart)*8 + 1;
2016       supportNew[1] = (c - cStart)*8 + 1+4;
2017       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2018 #if 1
2019       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2020       for (p = 0; p < 2; ++p) {
2021         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);
2022       }
2023 #endif
2024       ++newp;
2025       /* Face C: {c, f, b} */
2026       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
2027       orntNew[0] = ornt[2] < 0 ? -2 : 0;
2028       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
2029       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2030       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 1);
2031       orntNew[2] = ornt[0] < 0 ? -2 : 0;
2032       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2033       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2034 #if 1
2035       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2036       for (p = 0; p < 3; ++p) {
2037         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);
2038       }
2039 #endif
2040       supportNew[0] = (c - cStart)*8 + 2;
2041       supportNew[1] = (c - cStart)*8 + 2+4;
2042       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2043 #if 1
2044       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2045       for (p = 0; p < 2; ++p) {
2046         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);
2047       }
2048 #endif
2049       ++newp;
2050       /* Face D: {d, e, f} */
2051       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 0);
2052       orntNew[0] = ornt[1] < 0 ? -2 : 0;
2053       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
2054       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2055       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
2056       orntNew[2] = ornt[2] < 0 ? -2 : 0;
2057       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2058       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2059 #if 1
2060       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2061       for (p = 0; p < 3; ++p) {
2062         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);
2063       }
2064 #endif
2065       supportNew[0] = (c - cStart)*8 + 3;
2066       supportNew[1] = (c - cStart)*8 + 3+4;
2067       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2068 #if 1
2069       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2070       for (p = 0; p < 2; ++p) {
2071         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);
2072       }
2073 #endif
2074       ++newp;
2075       /* Face E: {d, f, a} */
2076       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
2077       orntNew[0] = ornt[2] < 0 ? 0 : -2;
2078       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2079       orntNew[1] = -2;
2080       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
2081       orntNew[2] = ornt[1] < 0 ? -2 : 0;
2082       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2083       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2084 #if 1
2085       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2086       for (p = 0; p < 3; ++p) {
2087         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);
2088       }
2089 #endif
2090       supportNew[0] = (c - cStart)*8 + 0+4;
2091       supportNew[1] = (c - cStart)*8 + 3+4;
2092       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2093 #if 1
2094       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2095       for (p = 0; p < 2; ++p) {
2096         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);
2097       }
2098 #endif
2099       ++newp;
2100       /* Face F: {c, a, f} */
2101       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
2102       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2103       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2104       orntNew[1] = 0;
2105       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
2106       orntNew[2] = ornt[2] < 0 ? 0 : -2;
2107       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2108       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2109 #if 1
2110       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2111       for (p = 0; p < 3; ++p) {
2112         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);
2113       }
2114 #endif
2115       supportNew[0] = (c - cStart)*8 + 0+4;
2116       supportNew[1] = (c - cStart)*8 + 2+4;
2117       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2118 #if 1
2119       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2120       for (p = 0; p < 2; ++p) {
2121         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);
2122       }
2123 #endif
2124       ++newp;
2125       /* Face G: {e, a, f} */
2126       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
2127       orntNew[0] = ornt[1] < 0 ? -2 : 0;
2128       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2129       orntNew[1] = 0;
2130       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
2131       orntNew[2] = ornt[3] < 0 ? 0 : -2;
2132       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2133       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2134 #if 1
2135       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2136       for (p = 0; p < 3; ++p) {
2137         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);
2138       }
2139 #endif
2140       supportNew[0] = (c - cStart)*8 + 1+4;
2141       supportNew[1] = (c - cStart)*8 + 3+4;
2142       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2143 #if 1
2144       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2145       for (p = 0; p < 2; ++p) {
2146         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);
2147       }
2148 #endif
2149       ++newp;
2150       /* Face H: {a, b, f} */
2151       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
2152       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2153       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
2154       orntNew[1] = ornt[3] < 0 ? 0 : -2;
2155       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2156       orntNew[2] = -2;
2157       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2158       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2159 #if 1
2160       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2161       for (p = 0; p < 3; ++p) {
2162         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);
2163       }
2164 #endif
2165       supportNew[0] = (c - cStart)*8 + 1+4;
2166       supportNew[1] = (c - cStart)*8 + 2+4;
2167       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2168 #if 1
2169       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2170       for (p = 0; p < 2; ++p) {
2171         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);
2172       }
2173 #endif
2174       ++newp;
2175     }
2176     /* Split Edges have 2 vertices and the same faces as the parent */
2177     for (e = eStart; e < eEnd; ++e) {
2178       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
2179 
2180       for (r = 0; r < 2; ++r) {
2181         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
2182         const PetscInt *cone, *ornt, *support;
2183         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2184 
2185         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
2186         coneNew[0]       = vStartNew + (cone[0] - vStart);
2187         coneNew[1]       = vStartNew + (cone[1] - vStart);
2188         coneNew[(r+1)%2] = newv;
2189         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2190 #if 1
2191         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2192         for (p = 0; p < 2; ++p) {
2193           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);
2194         }
2195 #endif
2196         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
2197         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
2198         for (s = 0; s < supportSize; ++s) {
2199           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2200           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2201           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2202           for (c = 0; c < coneSize; ++c) {
2203             if (cone[c] == e) break;
2204           }
2205           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
2206         }
2207         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2208 #if 1
2209         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2210         for (p = 0; p < supportSize; ++p) {
2211           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);
2212         }
2213 #endif
2214       }
2215     }
2216     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
2217     for (f = fStart; f < fEnd; ++f) {
2218       const PetscInt *cone, *ornt, *support;
2219       PetscInt        coneSize, supportSize, s;
2220 
2221       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2222       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2223       for (r = 0; r < 3; ++r) {
2224         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
2225         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
2226         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
2227                                     -1, -1,  1,  6,  0,  4,
2228                                      2,  5,  3,  4, -1, -1,
2229                                     -1, -1,  3,  6,  2,  7};
2230 
2231         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2232         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
2233         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
2234         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2235 #if 1
2236         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2237         for (p = 0; p < 2; ++p) {
2238           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);
2239         }
2240 #endif
2241         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
2242         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
2243         for (s = 0; s < supportSize; ++s) {
2244           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2245           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2246           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2247           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
2248           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
2249           er = GetTetSomethingInverse_Static(ornt[c], r);
2250           if (er == eint[c]) {
2251             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
2252           } else {
2253             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
2254             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
2255           }
2256         }
2257         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2258 #if 1
2259         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2260         for (p = 0; p < intFaces; ++p) {
2261           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);
2262         }
2263 #endif
2264       }
2265     }
2266     /* Interior edges have 2 vertices and 4 faces */
2267     for (c = cStart; c < cEnd; ++c) {
2268       const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2269       const PetscInt *cone, *ornt, *fcone;
2270       PetscInt        coneNew[2], supportNew[4], find;
2271 
2272       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2273       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2274       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
2275       find = GetTriEdge_Static(ornt[0], 0);
2276       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
2277       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
2278       find = GetTriEdge_Static(ornt[2], 1);
2279       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
2280       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2281 #if 1
2282       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2283       for (p = 0; p < 2; ++p) {
2284         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);
2285       }
2286 #endif
2287       supportNew[0] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 4;
2288       supportNew[1] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 5;
2289       supportNew[2] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 6;
2290       supportNew[3] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 7;
2291       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2292 #if 1
2293       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2294       for (p = 0; p < 4; ++p) {
2295         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);
2296       }
2297 #endif
2298     }
2299     /* Old vertices have identical supports */
2300     for (v = vStart; v < vEnd; ++v) {
2301       const PetscInt  newp = vStartNew + (v - vStart);
2302       const PetscInt *support, *cone;
2303       PetscInt        size, s;
2304 
2305       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2306       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2307       for (s = 0; s < size; ++s) {
2308         PetscInt r = 0;
2309 
2310         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2311         if (cone[1] == v) r = 1;
2312         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
2313       }
2314       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2315 #if 1
2316       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2317       for (p = 0; p < size; ++p) {
2318         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);
2319       }
2320 #endif
2321     }
2322     /* Edge vertices have 2 + face*2 + 0/1 supports */
2323     for (e = eStart; e < eEnd; ++e) {
2324       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
2325       const PetscInt *cone, *support;
2326       PetscInt       *star = NULL, starSize, cellSize = 0, coneSize, size, s;
2327 
2328       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
2329       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
2330       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
2331       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
2332       for (s = 0; s < size; ++s) {
2333         PetscInt r = 0;
2334 
2335         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2336         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2337         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
2338         supportRef[2+s*2+0] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
2339         supportRef[2+s*2+1] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
2340       }
2341       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
2342       for (s = 0; s < starSize*2; s += 2) {
2343         const PetscInt *cone, *ornt;
2344         PetscInt        e01, e23;
2345 
2346         if ((star[s] >= cStart) && (star[s] < cEnd)) {
2347           /* Check edge 0-1 */
2348           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
2349           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
2350           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
2351           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
2352           /* Check edge 2-3 */
2353           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
2354           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
2355           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
2356           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
2357           if ((e01 == e) || (e23 == e)) {supportRef[2+size*2+cellSize++] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (star[s] - cStart);}
2358         }
2359       }
2360       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
2361       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2362 #if 1
2363       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2364       for (p = 0; p < 2+size*2+cellSize; ++p) {
2365         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);
2366       }
2367 #endif
2368     }
2369     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2370     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
2371     break;
2372   case 7:
2373     /* Hybrid Simplicial 3D */
2374     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
2375     /* Interior cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
2376     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
2377     for (c = cStart; c < cMax; ++c) {
2378       const PetscInt  newp = cStartNew + (c - cStart)*8;
2379       const PetscInt *cone, *ornt;
2380       PetscInt        coneNew[4], orntNew[4];
2381 
2382       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2383       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2384       /* A tetrahedron: {0, a, c, d} */
2385       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
2386       orntNew[0] = ornt[0];
2387       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
2388       orntNew[1] = ornt[1];
2389       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
2390       orntNew[2] = ornt[2];
2391       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
2392       orntNew[3] = 0;
2393       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2394       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2395 #if 1
2396       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);
2397       for (p = 0; p < 4; ++p) {
2398         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);
2399       }
2400 #endif
2401       /* B tetrahedron: {a, 1, b, e} */
2402       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
2403       orntNew[0] = ornt[0];
2404       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
2405       orntNew[1] = ornt[1];
2406       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
2407       orntNew[2] = 0;
2408       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
2409       orntNew[3] = ornt[3];
2410       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2411       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2412 #if 1
2413       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);
2414       for (p = 0; p < 4; ++p) {
2415         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);
2416       }
2417 #endif
2418       /* C tetrahedron: {c, b, 2, f} */
2419       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
2420       orntNew[0] = ornt[0];
2421       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
2422       orntNew[1] = 0;
2423       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
2424       orntNew[2] = ornt[2];
2425       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
2426       orntNew[3] = ornt[3];
2427       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2428       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2429 #if 1
2430       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);
2431       for (p = 0; p < 4; ++p) {
2432         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);
2433       }
2434 #endif
2435       /* D tetrahedron: {d, e, f, 3} */
2436       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
2437       orntNew[0] = 0;
2438       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
2439       orntNew[1] = ornt[1];
2440       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
2441       orntNew[2] = ornt[2];
2442       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
2443       orntNew[3] = ornt[3];
2444       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2445       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2446 #if 1
2447       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);
2448       for (p = 0; p < 4; ++p) {
2449         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);
2450       }
2451 #endif
2452       /* A' tetrahedron: {d, a, c, f} */
2453       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
2454       orntNew[0] = -3;
2455       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
2456       orntNew[1] = ornt[2] < 0 ? -(GetTetSomething_Static(ornt[2], 0)+1) : GetTetSomething_Static(ornt[2], 0);
2457       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
2458       orntNew[2] = 0;
2459       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
2460       orntNew[3] = 2;
2461       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
2462       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
2463 #if 1
2464       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);
2465       for (p = 0; p < 4; ++p) {
2466         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);
2467       }
2468 #endif
2469       /* B' tetrahedron: {e, b, a, f} */
2470       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
2471       orntNew[0] = -3;
2472       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
2473       orntNew[1] = 1;
2474       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
2475       orntNew[2] = 0;
2476       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + 3;
2477       orntNew[3] = ornt[3] < 0 ? -(GetTetSomething_Static(ornt[3], 0)+1) : GetTetSomething_Static(ornt[3], 0);
2478       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
2479       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
2480 #if 1
2481       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);
2482       for (p = 0; p < 4; ++p) {
2483         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);
2484       }
2485 #endif
2486       /* C' tetrahedron: {b, f, c, a} */
2487       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
2488       orntNew[0] = -3;
2489       coneNew[1] = fStartNew + (cone[0] - fStart)*4 + 3;
2490       orntNew[1] = ornt[0] < 0 ? -(GetTetSomething_Static(ornt[0], 2)+1) : GetTetSomething_Static(ornt[0], 2);
2491       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
2492       orntNew[2] = -3;
2493       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
2494       orntNew[3] = -2;
2495       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
2496       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
2497 #if 1
2498       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);
2499       for (p = 0; p < 4; ++p) {
2500         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);
2501       }
2502 #endif
2503       /* D' tetrahedron: {f, e, d, a} */
2504       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
2505       orntNew[0] = -3;
2506       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
2507       orntNew[1] = -3;
2508       coneNew[2] = fStartNew + (cone[1] - fStart)*4 + 3;
2509       orntNew[2] = ornt[1] < 0 ? -(GetTetSomething_Static(ornt[1], 0)+1) : GetTetSomething_Static(ornt[1], 0);
2510       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
2511       orntNew[3] = -3;
2512       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
2513       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
2514 #if 1
2515       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);
2516       for (p = 0; p < 4; ++p) {
2517         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);
2518       }
2519 #endif
2520     }
2521     /* Hybrid cells have 5 faces */
2522     for (c = cMax; c < cEnd; ++c) {
2523       const PetscInt  newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4;
2524       const PetscInt *cone, *ornt, *fornt;
2525       PetscInt        coneNew[5], orntNew[5];
2526 
2527       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2528       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2529       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
2530       for (r = 0; r < 3; ++r) {
2531         coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], r);
2532         orntNew[0] = ornt[0];
2533         coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], r);
2534         orntNew[1] = ornt[1];
2535         coneNew[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], (r+2)%3)] - fMax)*2 + (fornt[GetTriEdge_Static(ornt[0], (r+2)%3)] < 0 ? 0 : 1);
2536         orntNew[2] = 0;
2537         coneNew[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], r)]       - fMax)*2 + (fornt[GetTriEdge_Static(ornt[0], r)]       < 0 ? 1 : 0);
2538         orntNew[3] = 0;
2539         coneNew[4] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + GetTriSubface_Static(ornt[0], r);
2540         orntNew[4] = 0;
2541         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
2542         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
2543 #if 1
2544         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);
2545         for (p = 0; p < 2; ++p) {
2546           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);
2547         }
2548         for (p = 2; p < 5; ++p) {
2549           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);
2550         }
2551 #endif
2552       }
2553       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + 3;
2554       orntNew[0] = 0;
2555       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + 3;
2556       orntNew[1] = 0;
2557       coneNew[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
2558       orntNew[2] = 0;
2559       coneNew[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
2560       orntNew[3] = 0;
2561       coneNew[4] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
2562       orntNew[4] = 0;
2563       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2564       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2565 #if 1
2566       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);
2567       for (p = 0; p < 2; ++p) {
2568         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);
2569       }
2570       for (p = 2; p < 5; ++p) {
2571         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);
2572       }
2573 #endif
2574     }
2575     /* Split faces have 3 edges and the same cells as the parent */
2576     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2577     ierr = PetscMalloc1((2 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
2578     for (f = fStart; f < fMax; ++f) {
2579       const PetscInt  newp = fStartNew + (f - fStart)*4;
2580       const PetscInt *cone, *ornt, *support;
2581       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
2582 
2583       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2584       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
2585       /* A triangle */
2586       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
2587       orntNew[0] = ornt[0];
2588       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
2589       orntNew[1] = -2;
2590       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
2591       orntNew[2] = ornt[2];
2592       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2593       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2594 #if 1
2595       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);
2596       for (p = 0; p < 3; ++p) {
2597         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
2598       }
2599 #endif
2600       /* B triangle */
2601       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
2602       orntNew[0] = ornt[0];
2603       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
2604       orntNew[1] = ornt[1];
2605       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
2606       orntNew[2] = -2;
2607       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2608       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2609 #if 1
2610       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);
2611       for (p = 0; p < 3; ++p) {
2612         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);
2613       }
2614 #endif
2615       /* C triangle */
2616       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
2617       orntNew[0] = -2;
2618       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
2619       orntNew[1] = ornt[1];
2620       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
2621       orntNew[2] = ornt[2];
2622       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2623       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2624 #if 1
2625       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);
2626       for (p = 0; p < 3; ++p) {
2627         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);
2628       }
2629 #endif
2630       /* D triangle */
2631       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
2632       orntNew[0] = 0;
2633       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
2634       orntNew[1] = 0;
2635       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
2636       orntNew[2] = 0;
2637       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2638       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2639 #if 1
2640       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);
2641       for (p = 0; p < 3; ++p) {
2642         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);
2643       }
2644 #endif
2645       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2646       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2647       for (r = 0; r < 4; ++r) {
2648         for (s = 0; s < supportSize; ++s) {
2649           PetscInt subf;
2650           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2651           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2652           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2653           for (c = 0; c < coneSize; ++c) {
2654             if (cone[c] == f) break;
2655           }
2656           subf = GetTriSubfaceInverse_Static(ornt[c], r);
2657           if (support[s] < cMax) {
2658             supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
2659           } else {
2660             supportRef[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (r==3 ? r : subf);
2661           }
2662         }
2663         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
2664 #if 1
2665         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);
2666         for (p = 0; p < supportSize; ++p) {
2667           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);
2668         }
2669 #endif
2670       }
2671     }
2672     /* Interior cell faces have 3 edges and 2 cells */
2673     for (c = cStart; c < cMax; ++c) {
2674       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8;
2675       const PetscInt *cone, *ornt;
2676       PetscInt        coneNew[3], orntNew[3];
2677       PetscInt        supportNew[2];
2678 
2679       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2680       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2681       /* Face A: {c, a, d} */
2682       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
2683       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2684       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
2685       orntNew[1] = ornt[1] < 0 ? -2 : 0;
2686       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 2);
2687       orntNew[2] = ornt[2] < 0 ? -2 : 0;
2688       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2689       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2690 #if 1
2691       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2692       for (p = 0; p < 3; ++p) {
2693         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);
2694       }
2695 #endif
2696       supportNew[0] = (c - cStart)*8 + 0;
2697       supportNew[1] = (c - cStart)*8 + 0+4;
2698       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2699 #if 1
2700       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2701       for (p = 0; p < 2; ++p) {
2702         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);
2703       }
2704 #endif
2705       ++newp;
2706       /* Face B: {a, b, e} */
2707       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
2708       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2709       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 0);
2710       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2711       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
2712       orntNew[2] = ornt[1] < 0 ? -2 : 0;
2713       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2714       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2715 #if 1
2716       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);
2717       for (p = 0; p < 3; ++p) {
2718         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);
2719       }
2720 #endif
2721       supportNew[0] = (c - cStart)*8 + 1;
2722       supportNew[1] = (c - cStart)*8 + 1+4;
2723       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2724 #if 1
2725       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2726       for (p = 0; p < 2; ++p) {
2727         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);
2728       }
2729 #endif
2730       ++newp;
2731       /* Face C: {c, f, b} */
2732       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
2733       orntNew[0] = ornt[2] < 0 ? -2 : 0;
2734       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
2735       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2736       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 1);
2737       orntNew[2] = ornt[0] < 0 ? -2 : 0;
2738       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2739       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2740 #if 1
2741       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2742       for (p = 0; p < 3; ++p) {
2743         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);
2744       }
2745 #endif
2746       supportNew[0] = (c - cStart)*8 + 2;
2747       supportNew[1] = (c - cStart)*8 + 2+4;
2748       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2749 #if 1
2750       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2751       for (p = 0; p < 2; ++p) {
2752         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);
2753       }
2754 #endif
2755       ++newp;
2756       /* Face D: {d, e, f} */
2757       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 0);
2758       orntNew[0] = ornt[1] < 0 ? -2 : 0;
2759       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
2760       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2761       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
2762       orntNew[2] = ornt[2] < 0 ? -2 : 0;
2763       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2764       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2765 #if 1
2766       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2767       for (p = 0; p < 3; ++p) {
2768         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);
2769       }
2770 #endif
2771       supportNew[0] = (c - cStart)*8 + 3;
2772       supportNew[1] = (c - cStart)*8 + 3+4;
2773       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2774 #if 1
2775       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2776       for (p = 0; p < 2; ++p) {
2777         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);
2778       }
2779 #endif
2780       ++newp;
2781       /* Face E: {d, f, a} */
2782       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
2783       orntNew[0] = ornt[2] < 0 ? 0 : -2;
2784       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
2785       orntNew[1] = -2;
2786       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
2787       orntNew[2] = ornt[1] < 0 ? -2 : 0;
2788       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2789       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2790 #if 1
2791       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2792       for (p = 0; p < 3; ++p) {
2793         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);
2794       }
2795 #endif
2796       supportNew[0] = (c - cStart)*8 + 0+4;
2797       supportNew[1] = (c - cStart)*8 + 3+4;
2798       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2799 #if 1
2800       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2801       for (p = 0; p < 2; ++p) {
2802         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);
2803       }
2804 #endif
2805       ++newp;
2806       /* Face F: {c, a, f} */
2807       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
2808       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2809       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
2810       orntNew[1] = 0;
2811       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
2812       orntNew[2] = ornt[2] < 0 ? 0 : -2;
2813       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2814       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2815 #if 1
2816       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2817       for (p = 0; p < 3; ++p) {
2818         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);
2819       }
2820 #endif
2821       supportNew[0] = (c - cStart)*8 + 0+4;
2822       supportNew[1] = (c - cStart)*8 + 2+4;
2823       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2824 #if 1
2825       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2826       for (p = 0; p < 2; ++p) {
2827         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);
2828       }
2829 #endif
2830       ++newp;
2831       /* Face G: {e, a, f} */
2832       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
2833       orntNew[0] = ornt[1] < 0 ? -2 : 0;
2834       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
2835       orntNew[1] = 0;
2836       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
2837       orntNew[2] = ornt[3] < 0 ? 0 : -2;
2838       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2839       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2840 #if 1
2841       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2842       for (p = 0; p < 3; ++p) {
2843         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);
2844       }
2845 #endif
2846       supportNew[0] = (c - cStart)*8 + 1+4;
2847       supportNew[1] = (c - cStart)*8 + 3+4;
2848       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2849 #if 1
2850       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2851       for (p = 0; p < 2; ++p) {
2852         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);
2853       }
2854 #endif
2855       ++newp;
2856       /* Face H: {a, b, f} */
2857       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
2858       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2859       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
2860       orntNew[1] = ornt[3] < 0 ? 0 : -2;
2861       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
2862       orntNew[2] = -2;
2863       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2864       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2865 #if 1
2866       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2867       for (p = 0; p < 3; ++p) {
2868         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);
2869       }
2870 #endif
2871       supportNew[0] = (c - cStart)*8 + 1+4;
2872       supportNew[1] = (c - cStart)*8 + 2+4;
2873       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2874 #if 1
2875       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
2876       for (p = 0; p < 2; ++p) {
2877         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);
2878       }
2879 #endif
2880       ++newp;
2881     }
2882     /* Hybrid split faces have 4 edges and same cells */
2883     for (f = fMax; f < fEnd; ++f) {
2884       const PetscInt *cone, *ornt, *support;
2885       PetscInt        coneNew[4], orntNew[4];
2886       PetscInt        supportNew[2], size, s, c;
2887 
2888       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2889       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
2890       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2891       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2892       for (r = 0; r < 2; ++r) {
2893         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
2894 
2895         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
2896         orntNew[0]   = ornt[0];
2897         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
2898         orntNew[1]   = ornt[1];
2899         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (cone[2+r] - eMax);
2900         orntNew[2+r] = 0;
2901         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd      - eMax) + (f - fMax);
2902         orntNew[3-r] = 0;
2903         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2904         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2905 #if 1
2906         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
2907         for (p = 0; p < 2; ++p) {
2908           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);
2909         }
2910         for (p = 2; p < 4; ++p) {
2911           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);
2912         }
2913 #endif
2914         for (s = 0; s < size; ++s) {
2915           const PetscInt *coneCell, *orntCell, *fornt;
2916 
2917           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
2918           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
2919           for (c = 2; c < 5; ++c) if (coneCell[c] == f) break;
2920           if (c >= 5) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
2921           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
2922           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetTriEdgeInverse_Static(orntCell[0], c-2) + (fornt[c-2] < 0 ? 1-r : r))%3;
2923         }
2924         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2925 #if 1
2926         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
2927         for (p = 0; p < size; ++p) {
2928           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);
2929         }
2930 #endif
2931       }
2932     }
2933     /* Hybrid cell faces have 4 edges and 2 cells */
2934     for (c = cMax; c < cEnd; ++c) {
2935       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3;
2936       const PetscInt *cone, *ornt;
2937       PetscInt        coneNew[4], orntNew[4];
2938       PetscInt        supportNew[2];
2939 
2940       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2941       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2942       for (r = 0; r < 3; ++r) {
2943         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], (r+2)%3);
2944         orntNew[0] = 0;
2945         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], (r+2)%3);
2946         orntNew[1] = 0;
2947         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+GetTriSubface_Static(ornt[0], (r+2)%3)] - fMax);
2948         orntNew[2] = 0;
2949         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+GetTriSubface_Static(ornt[0], r)]       - fMax);
2950         orntNew[3] = 0;
2951         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
2952         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
2953 #if 1
2954         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);
2955         for (p = 0; p < 2; ++p) {
2956           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);
2957         }
2958         for (p = 2; p < 4; ++p) {
2959           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);
2960         }
2961 #endif
2962         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetTriSubface_Static(ornt[0], r);
2963         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + 3;
2964         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
2965 #if 1
2966         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);
2967         for (p = 0; p < 2; ++p) {
2968           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);
2969         }
2970 #endif
2971       }
2972     }
2973     /* Interior split edges have 2 vertices and the same faces as the parent */
2974     for (e = eStart; e < eMax; ++e) {
2975       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
2976 
2977       for (r = 0; r < 2; ++r) {
2978         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
2979         const PetscInt *cone, *ornt, *support;
2980         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2981 
2982         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
2983         coneNew[0]       = vStartNew + (cone[0] - vStart);
2984         coneNew[1]       = vStartNew + (cone[1] - vStart);
2985         coneNew[(r+1)%2] = newv;
2986         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2987 #if 1
2988         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
2989         for (p = 0; p < 2; ++p) {
2990           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);
2991         }
2992 #endif
2993         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
2994         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
2995         for (s = 0; s < supportSize; ++s) {
2996           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2997           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2998           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2999           for (c = 0; c < coneSize; ++c) if (cone[c] == e) break;
3000           if (support[s] < fMax) {
3001             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
3002           } else {
3003             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
3004           }
3005         }
3006         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3007 #if 1
3008         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3009         for (p = 0; p < supportSize; ++p) {
3010           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);
3011         }
3012 #endif
3013       }
3014     }
3015     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
3016     for (f = fStart; f < fMax; ++f) {
3017       const PetscInt *cone, *ornt, *support;
3018       PetscInt        coneSize, supportSize, s;
3019 
3020       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3021       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3022       for (r = 0; r < 3; ++r) {
3023         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
3024         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
3025         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
3026                                     -1, -1,  1,  6,  0,  4,
3027                                      2,  5,  3,  4, -1, -1,
3028                                     -1, -1,  3,  6,  2,  7};
3029 
3030         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3031         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
3032         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
3033         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3034 #if 1
3035         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3036         for (p = 0; p < 2; ++p) {
3037           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);
3038         }
3039 #endif
3040         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
3041         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
3042         for (s = 0; s < supportSize; ++s) {
3043           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3044           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3045           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3046           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
3047           if (support[s] < cMax) {
3048             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
3049             er = GetTetSomethingInverse_Static(ornt[c], r);
3050             if (er == eint[c]) {
3051               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
3052             } else {
3053               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
3054               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
3055             }
3056           } else {
3057             supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (GetTriSubfaceInverse_Static(ornt[c], r) + 1)%3;
3058           }
3059         }
3060         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3061 #if 1
3062         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3063         for (p = 0; p < intFaces; ++p) {
3064           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);
3065         }
3066 #endif
3067       }
3068     }
3069     /* Interior cell edges have 2 vertices and 4 faces */
3070     for (c = cStart; c < cMax; ++c) {
3071       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3072       const PetscInt *cone, *ornt, *fcone;
3073       PetscInt        coneNew[2], supportNew[4], find;
3074 
3075       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3076       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3077       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
3078       find = GetTriEdge_Static(ornt[0], 0);
3079       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3080       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
3081       find = GetTriEdge_Static(ornt[2], 1);
3082       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3083       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3084 #if 1
3085       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3086       for (p = 0; p < 2; ++p) {
3087         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);
3088       }
3089 #endif
3090       supportNew[0] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 4;
3091       supportNew[1] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 5;
3092       supportNew[2] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 6;
3093       supportNew[3] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 7;
3094       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3095 #if 1
3096       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3097       for (p = 0; p < 4; ++p) {
3098         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);
3099       }
3100 #endif
3101     }
3102     /* Hybrid edges have two vertices and the same faces */
3103     for (e = eMax; e < eEnd; ++e) {
3104       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
3105       const PetscInt *cone, *support, *fcone;
3106       PetscInt        coneNew[2], size, fsize, s;
3107 
3108       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3109       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
3110       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3111       coneNew[0] = vStartNew + (cone[0] - vStart);
3112       coneNew[1] = vStartNew + (cone[1] - vStart);
3113       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3114 #if 1
3115       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3116       for (p = 0; p < 2; ++p) {
3117         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);
3118       }
3119 #endif
3120       for (s = 0; s < size; ++s) {
3121         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
3122         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
3123         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
3124         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
3125         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + c-2;
3126       }
3127       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3128 #if 1
3129       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3130       for (p = 0; p < size; ++p) {
3131         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);
3132       }
3133 #endif
3134     }
3135     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
3136     for (f = fMax; f < fEnd; ++f) {
3137       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
3138       const PetscInt *cone, *support, *ccone, *cornt;
3139       PetscInt        coneNew[2], size, csize, s;
3140 
3141       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3142       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3143       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3144       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
3145       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
3146       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3147 #if 1
3148       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3149       for (p = 0; p < 2; ++p) {
3150         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);
3151       }
3152 #endif
3153       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 0;
3154       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 1;
3155       for (s = 0; s < size; ++s) {
3156         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
3157         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
3158         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
3159         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
3160         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]);
3161         supportRef[2+s*2+0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + GetTriSubfaceInverse_Static(cornt[0], c-2);
3162         supportRef[2+s*2+1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (GetTriSubfaceInverse_Static(cornt[0], c-2) + 1)%3;
3163       }
3164       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3165 #if 1
3166       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3167       for (p = 0; p < 2+size*2; ++p) {
3168         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);
3169       }
3170 #endif
3171     }
3172     /* Interior vertices have identical supports */
3173     for (v = vStart; v < vEnd; ++v) {
3174       const PetscInt  newp = vStartNew + (v - vStart);
3175       const PetscInt *support, *cone;
3176       PetscInt        size, s;
3177 
3178       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
3179       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
3180       for (s = 0; s < size; ++s) {
3181         PetscInt r = 0;
3182 
3183         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3184         if (cone[1] == v) r = 1;
3185         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
3186         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (support[s] - eMax);
3187       }
3188       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3189 #if 1
3190       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3191       for (p = 0; p < size; ++p) {
3192         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);
3193       }
3194 #endif
3195     }
3196     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
3197     for (e = eStart; e < eMax; ++e) {
3198       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
3199       const PetscInt *cone, *support;
3200       PetscInt       *star = NULL, starSize, faceSize = 0, cellSize = 0, coneSize, size, s;
3201 
3202       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
3203       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3204       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
3205       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
3206       for (s = 0; s < size; ++s) {
3207         PetscInt r = 0;
3208 
3209         if (support[s] < fMax) {
3210           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3211           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3212           for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
3213           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
3214           supportRef[2+faceSize+1] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
3215           faceSize += 2;
3216         } else {
3217           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (support[s] - fMax);
3218           ++faceSize;
3219         }
3220       }
3221       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
3222       for (s = 0; s < starSize*2; s += 2) {
3223         const PetscInt *cone, *ornt;
3224         PetscInt        e01, e23;
3225 
3226         if ((star[s] >= cStart) && (star[s] < cMax)) {
3227           /* Check edge 0-1 */
3228           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
3229           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
3230           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
3231           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
3232           /* Check edge 2-3 */
3233           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
3234           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
3235           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
3236           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
3237           if ((e01 == e) || (e23 == e)) {supportRef[2+faceSize+cellSize++] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (star[s] - cStart);}
3238         }
3239       }
3240       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
3241       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3242 #if 1
3243       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3244       for (p = 0; p < 2+faceSize+cellSize; ++p) {
3245         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);
3246       }
3247 #endif
3248     }
3249     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3250     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
3251     break;
3252   case 6:
3253     /* Hex 3D */
3254     /*
3255      Bottom (viewed from top)    Top
3256      1---------2---------2       7---------2---------6
3257      |         |         |       |         |         |
3258      |    B    2    C    |       |    H    2    G    |
3259      |         |         |       |         |         |
3260      3----3----0----1----1       3----3----0----1----1
3261      |         |         |       |         |         |
3262      |    A    0    D    |       |    E    0    F    |
3263      |         |         |       |         |         |
3264      0---------0---------3       4---------0---------5
3265      */
3266     /* All cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
3267     for (c = cStart; c < cEnd; ++c) {
3268       const PetscInt  newp = (c - cStart)*8;
3269       const PetscInt *cone, *ornt;
3270       PetscInt        coneNew[6], orntNew[6];
3271 
3272       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3273       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3274       /* A hex */
3275       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
3276       orntNew[0] = ornt[0];
3277       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
3278       orntNew[1] = 0;
3279       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
3280       orntNew[2] = ornt[2];
3281       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
3282       orntNew[3] = 0;
3283       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
3284       orntNew[4] = 0;
3285       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
3286       orntNew[5] = ornt[5];
3287       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3288       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3289 #if 1
3290       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);
3291       for (p = 0; p < 6; ++p) {
3292         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);
3293       }
3294 #endif
3295       /* B hex */
3296       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
3297       orntNew[0] = ornt[0];
3298       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
3299       orntNew[1] = 0;
3300       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
3301       orntNew[2] = -1;
3302       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
3303       orntNew[3] = ornt[3];
3304       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
3305       orntNew[4] = 0;
3306       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
3307       orntNew[5] = ornt[5];
3308       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3309       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3310 #if 1
3311       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);
3312       for (p = 0; p < 6; ++p) {
3313         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);
3314       }
3315 #endif
3316       /* C hex */
3317       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
3318       orntNew[0] = ornt[0];
3319       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
3320       orntNew[1] = 0;
3321       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
3322       orntNew[2] = -1;
3323       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
3324       orntNew[3] = ornt[3];
3325       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
3326       orntNew[4] = ornt[4];
3327       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
3328       orntNew[5] = -4;
3329       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3330       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3331 #if 1
3332       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);
3333       for (p = 0; p < 6; ++p) {
3334         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);
3335       }
3336 #endif
3337       /* D hex */
3338       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
3339       orntNew[0] = ornt[0];
3340       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
3341       orntNew[1] = 0;
3342       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
3343       orntNew[2] = ornt[2];
3344       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
3345       orntNew[3] = 0;
3346       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
3347       orntNew[4] = ornt[4];
3348       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
3349       orntNew[5] = -4;
3350       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3351       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3352 #if 1
3353       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);
3354       for (p = 0; p < 6; ++p) {
3355         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);
3356       }
3357 #endif
3358       /* E hex */
3359       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
3360       orntNew[0] = -4;
3361       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
3362       orntNew[1] = ornt[1];
3363       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
3364       orntNew[2] = ornt[2];
3365       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
3366       orntNew[3] = 0;
3367       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
3368       orntNew[4] = -1;
3369       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
3370       orntNew[5] = ornt[5];
3371       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
3372       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
3373 #if 1
3374       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);
3375       for (p = 0; p < 6; ++p) {
3376         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);
3377       }
3378 #endif
3379       /* F hex */
3380       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
3381       orntNew[0] = -4;
3382       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
3383       orntNew[1] = ornt[1];
3384       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
3385       orntNew[2] = ornt[2];
3386       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
3387       orntNew[3] = -1;
3388       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
3389       orntNew[4] = ornt[4];
3390       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
3391       orntNew[5] = 1;
3392       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
3393       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
3394 #if 1
3395       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);
3396       for (p = 0; p < 6; ++p) {
3397         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);
3398       }
3399 #endif
3400       /* G hex */
3401       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
3402       orntNew[0] = -4;
3403       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
3404       orntNew[1] = ornt[1];
3405       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
3406       orntNew[2] = 0;
3407       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
3408       orntNew[3] = ornt[3];
3409       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
3410       orntNew[4] = ornt[4];
3411       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
3412       orntNew[5] = -3;
3413       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
3414       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
3415 #if 1
3416       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);
3417       for (p = 0; p < 6; ++p) {
3418         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);
3419       }
3420 #endif
3421       /* H hex */
3422       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
3423       orntNew[0] = -4;
3424       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
3425       orntNew[1] = ornt[1];
3426       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
3427       orntNew[2] = -1;
3428       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
3429       orntNew[3] = ornt[3];
3430       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
3431       orntNew[4] = 3;
3432       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
3433       orntNew[5] = ornt[5];
3434       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
3435       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
3436 #if 1
3437       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);
3438       for (p = 0; p < 6; ++p) {
3439         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);
3440       }
3441 #endif
3442     }
3443     /* Split faces have 4 edges and the same cells as the parent */
3444     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3445     ierr = PetscMalloc1((4 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
3446     for (f = fStart; f < fEnd; ++f) {
3447       for (r = 0; r < 4; ++r) {
3448         /* TODO: This can come from GetFaces_Internal() */
3449         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};
3450         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
3451         const PetscInt *cone, *ornt, *support;
3452         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
3453 
3454         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3455         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3456         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
3457         orntNew[(r+3)%4] = ornt[(r+3)%4];
3458         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
3459         orntNew[(r+0)%4] = ornt[r];
3460         coneNew[(r+1)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
3461         orntNew[(r+1)%4] = 0;
3462         coneNew[(r+2)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + (r+3)%4;
3463         orntNew[(r+2)%4] = -2;
3464         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3465         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3466 #if 1
3467         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3468         for (p = 0; p < 4; ++p) {
3469           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);
3470         }
3471 #endif
3472         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3473         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3474         for (s = 0; s < supportSize; ++s) {
3475           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3476           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3477           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3478           for (c = 0; c < coneSize; ++c) {
3479             if (cone[c] == f) break;
3480           }
3481           supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+GetQuadSubfaceInverse_Static(ornt[c], r)];
3482         }
3483         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3484 #if 1
3485         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3486         for (p = 0; p < supportSize; ++p) {
3487           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);
3488         }
3489 #endif
3490       }
3491     }
3492     /* Interior faces have 4 edges and 2 cells */
3493     for (c = cStart; c < cEnd; ++c) {
3494       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};
3495       const PetscInt *cone, *ornt;
3496       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
3497 
3498       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3499       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3500       /* A-D face */
3501       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 0;
3502       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
3503       orntNew[0] = 0;
3504       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
3505       orntNew[1] = 0;
3506       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
3507       orntNew[2] = -2;
3508       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
3509       orntNew[3] = -2;
3510       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3511       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3512 #if 1
3513       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3514       for (p = 0; p < 4; ++p) {
3515         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);
3516       }
3517 #endif
3518       /* C-D face */
3519       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 1;
3520       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
3521       orntNew[0] = 0;
3522       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
3523       orntNew[1] = 0;
3524       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
3525       orntNew[2] = -2;
3526       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
3527       orntNew[3] = -2;
3528       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3529       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3530 #if 1
3531       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3532       for (p = 0; p < 4; ++p) {
3533         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);
3534       }
3535 #endif
3536       /* B-C face */
3537       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 2;
3538       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
3539       orntNew[0] = -2;
3540       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
3541       orntNew[1] = 0;
3542       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
3543       orntNew[2] = 0;
3544       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
3545       orntNew[3] = -2;
3546       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3547       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3548 #if 1
3549       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3550       for (p = 0; p < 4; ++p) {
3551         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);
3552       }
3553 #endif
3554       /* A-B face */
3555       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 3;
3556       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
3557       orntNew[0] = -2;
3558       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
3559       orntNew[1] = 0;
3560       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
3561       orntNew[2] = 0;
3562       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
3563       orntNew[3] = -2;
3564       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3565       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3566 #if 1
3567       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3568       for (p = 0; p < 4; ++p) {
3569         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);
3570       }
3571 #endif
3572       /* E-F face */
3573       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 4;
3574       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
3575       orntNew[0] = -2;
3576       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
3577       orntNew[1] = -2;
3578       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
3579       orntNew[2] = 0;
3580       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
3581       orntNew[3] = 0;
3582       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3583       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3584 #if 1
3585       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3586       for (p = 0; p < 4; ++p) {
3587         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);
3588       }
3589 #endif
3590       /* F-G face */
3591       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 5;
3592       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
3593       orntNew[0] = -2;
3594       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
3595       orntNew[1] = -2;
3596       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
3597       orntNew[2] = 0;
3598       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
3599       orntNew[3] = 0;
3600       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3601       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3602 #if 1
3603       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3604       for (p = 0; p < 4; ++p) {
3605         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);
3606       }
3607 #endif
3608       /* G-H face */
3609       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 6;
3610       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
3611       orntNew[0] = -2;
3612       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
3613       orntNew[1] = 0;
3614       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
3615       orntNew[2] = 0;
3616       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
3617       orntNew[3] = -2;
3618       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3619       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3620 #if 1
3621       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3622       for (p = 0; p < 4; ++p) {
3623         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);
3624       }
3625 #endif
3626       /* E-H face */
3627       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 7;
3628       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
3629       orntNew[0] = -2;
3630       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
3631       orntNew[1] = -2;
3632       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
3633       orntNew[2] = 0;
3634       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
3635       orntNew[3] = 0;
3636       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3637       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3638 #if 1
3639       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3640       for (p = 0; p < 4; ++p) {
3641         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);
3642       }
3643 #endif
3644       /* A-E face */
3645       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 8;
3646       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
3647       orntNew[0] = 0;
3648       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
3649       orntNew[1] = 0;
3650       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
3651       orntNew[2] = -2;
3652       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
3653       orntNew[3] = -2;
3654       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3655       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3656 #if 1
3657       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3658       for (p = 0; p < 4; ++p) {
3659         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);
3660       }
3661 #endif
3662       /* D-F face */
3663       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 9;
3664       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
3665       orntNew[0] = -2;
3666       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
3667       orntNew[1] = 0;
3668       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
3669       orntNew[2] = 0;
3670       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
3671       orntNew[3] = -2;
3672       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3673       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3674 #if 1
3675       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3676       for (p = 0; p < 4; ++p) {
3677         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);
3678       }
3679 #endif
3680       /* C-G face */
3681       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 10;
3682       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
3683       orntNew[0] = -2;
3684       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
3685       orntNew[1] = -2;
3686       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
3687       orntNew[2] = 0;
3688       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
3689       orntNew[3] = 0;
3690       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3691       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3692 #if 1
3693       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3694       for (p = 0; p < 4; ++p) {
3695         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);
3696       }
3697 #endif
3698       /* B-H face */
3699       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 11;
3700       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
3701       orntNew[0] = 0;
3702       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
3703       orntNew[1] = -2;
3704       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
3705       orntNew[2] = -2;
3706       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
3707       orntNew[3] = 0;
3708       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3709       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3710 #if 1
3711       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3712       for (p = 0; p < 4; ++p) {
3713         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);
3714       }
3715 #endif
3716       for (r = 0; r < 12; ++r) {
3717         newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
3718         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
3719         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
3720         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3721 #if 1
3722         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3723         for (p = 0; p < 2; ++p) {
3724           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);
3725         }
3726 #endif
3727       }
3728     }
3729     /* Split edges have 2 vertices and the same faces as the parent */
3730     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3731     for (e = eStart; e < eEnd; ++e) {
3732       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
3733 
3734       for (r = 0; r < 2; ++r) {
3735         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
3736         const PetscInt *cone, *ornt, *support;
3737         PetscInt        coneNew[2], coneSize, c, supportSize, s;
3738 
3739         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3740         coneNew[0]       = vStartNew + (cone[0] - vStart);
3741         coneNew[1]       = vStartNew + (cone[1] - vStart);
3742         coneNew[(r+1)%2] = newv;
3743         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3744 #if 1
3745         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3746         for (p = 0; p < 2; ++p) {
3747           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);
3748         }
3749 #endif
3750         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
3751         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3752         for (s = 0; s < supportSize; ++s) {
3753           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3754           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3755           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3756           for (c = 0; c < coneSize; ++c) {
3757             if (cone[c] == e) break;
3758           }
3759           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
3760         }
3761         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3762 #if 1
3763         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3764         for (p = 0; p < supportSize; ++p) {
3765           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);
3766         }
3767 #endif
3768       }
3769     }
3770     /* Face edges have 2 vertices and 2+cells faces */
3771     for (f = fStart; f < fEnd; ++f) {
3772       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};
3773       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
3774       const PetscInt *cone, *coneCell, *orntCell, *support;
3775       PetscInt        coneNew[2], coneSize, c, supportSize, s;
3776 
3777       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3778       for (r = 0; r < 4; ++r) {
3779         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
3780 
3781         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
3782         coneNew[1] = newv;
3783         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3784 #if 1
3785         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3786         for (p = 0; p < 2; ++p) {
3787           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);
3788         }
3789 #endif
3790         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3791         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3792         supportRef[0] = fStartNew + (f - fStart)*4 + r;
3793         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
3794         for (s = 0; s < supportSize; ++s) {
3795           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3796           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
3797           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
3798           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
3799           supportRef[2+s] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
3800         }
3801         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3802 #if 1
3803         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3804         for (p = 0; p < 2+supportSize; ++p) {
3805           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);
3806         }
3807 #endif
3808       }
3809     }
3810     /* Cell edges have 2 vertices and 4 faces */
3811     for (c = cStart; c < cEnd; ++c) {
3812       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};
3813       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
3814       const PetscInt *cone;
3815       PetscInt        coneNew[2], supportNew[4];
3816 
3817       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3818       for (r = 0; r < 6; ++r) {
3819         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
3820 
3821         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
3822         coneNew[1] = newv;
3823         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3824 #if 1
3825         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3826         for (p = 0; p < 2; ++p) {
3827           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);
3828         }
3829 #endif
3830         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
3831         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3832 #if 1
3833         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3834         for (p = 0; p < 4; ++p) {
3835           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);
3836         }
3837 #endif
3838       }
3839     }
3840     /* Old vertices have identical supports */
3841     for (v = vStart; v < vEnd; ++v) {
3842       const PetscInt  newp = vStartNew + (v - vStart);
3843       const PetscInt *support, *cone;
3844       PetscInt        size, s;
3845 
3846       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
3847       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
3848       for (s = 0; s < size; ++s) {
3849         PetscInt r = 0;
3850 
3851         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3852         if (cone[1] == v) r = 1;
3853         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
3854       }
3855       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3856 #if 1
3857       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3858       for (p = 0; p < size; ++p) {
3859         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);
3860       }
3861 #endif
3862     }
3863     /* Edge vertices have 2 + faces supports */
3864     for (e = eStart; e < eEnd; ++e) {
3865       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
3866       const PetscInt *cone, *support;
3867       PetscInt        size, s;
3868 
3869       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
3870       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3871       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
3872       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
3873       for (s = 0; s < size; ++s) {
3874         PetscInt r;
3875 
3876         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3877         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
3878         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*4 + r;
3879       }
3880       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3881 #if 1
3882       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3883       for (p = 0; p < 2+size; ++p) {
3884         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);
3885       }
3886 #endif
3887     }
3888     /* Face vertices have 4 + cells supports */
3889     for (f = fStart; f < fEnd; ++f) {
3890       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
3891       const PetscInt *cone, *support;
3892       PetscInt        size, s;
3893 
3894       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3895       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3896       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eEnd - eStart)*2 +  (f - fStart)*4 + r;
3897       for (s = 0; s < size; ++s) {
3898         PetscInt r;
3899 
3900         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3901         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
3902         supportRef[4+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (support[s] - cStart)*6 + r;
3903       }
3904       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3905 #if 1
3906       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3907       for (p = 0; p < 4+size; ++p) {
3908         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);
3909       }
3910 #endif
3911     }
3912     /* Cell vertices have 6 supports */
3913     for (c = cStart; c < cEnd; ++c) {
3914       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
3915       PetscInt       supportNew[6];
3916 
3917       for (r = 0; r < 6; ++r) {
3918         supportNew[r] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
3919       }
3920       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3921     }
3922     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3923     break;
3924   case 8:
3925     /* Hybrid Hex 3D */
3926     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
3927     /*
3928      Bottom (viewed from top)    Top
3929      1---------2---------2       7---------2---------6
3930      |         |         |       |         |         |
3931      |    B    2    C    |       |    H    2    G    |
3932      |         |         |       |         |         |
3933      3----3----0----1----1       3----3----0----1----1
3934      |         |         |       |         |         |
3935      |    A    0    D    |       |    E    0    F    |
3936      |         |         |       |         |         |
3937      0---------0---------3       4---------0---------5
3938      */
3939     /* Interior cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
3940     for (c = cStart; c < cMax; ++c) {
3941       const PetscInt  newp = (c - cStart)*8;
3942       const PetscInt *cone, *ornt;
3943       PetscInt        coneNew[6], orntNew[6];
3944 
3945       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3946       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3947       /* A hex */
3948       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
3949       orntNew[0] = ornt[0];
3950       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
3951       orntNew[1] = 0;
3952       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
3953       orntNew[2] = ornt[2];
3954       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
3955       orntNew[3] = 0;
3956       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
3957       orntNew[4] = 0;
3958       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
3959       orntNew[5] = ornt[5];
3960       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3961       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3962 #if 1
3963       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);
3964       for (p = 0; p < 6; ++p) {
3965         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);
3966       }
3967 #endif
3968       /* B hex */
3969       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
3970       orntNew[0] = ornt[0];
3971       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
3972       orntNew[1] = 0;
3973       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
3974       orntNew[2] = -1;
3975       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
3976       orntNew[3] = ornt[3];
3977       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
3978       orntNew[4] = 0;
3979       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
3980       orntNew[5] = ornt[5];
3981       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3982       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3983 #if 1
3984       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);
3985       for (p = 0; p < 6; ++p) {
3986         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);
3987       }
3988 #endif
3989       /* C hex */
3990       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
3991       orntNew[0] = ornt[0];
3992       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
3993       orntNew[1] = 0;
3994       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
3995       orntNew[2] = -1;
3996       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
3997       orntNew[3] = ornt[3];
3998       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
3999       orntNew[4] = ornt[4];
4000       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
4001       orntNew[5] = -4;
4002       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4003       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4004 #if 1
4005       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);
4006       for (p = 0; p < 6; ++p) {
4007         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);
4008       }
4009 #endif
4010       /* D hex */
4011       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
4012       orntNew[0] = ornt[0];
4013       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
4014       orntNew[1] = 0;
4015       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
4016       orntNew[2] = ornt[2];
4017       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
4018       orntNew[3] = 0;
4019       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
4020       orntNew[4] = ornt[4];
4021       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
4022       orntNew[5] = -4;
4023       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4024       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4025 #if 1
4026       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);
4027       for (p = 0; p < 6; ++p) {
4028         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);
4029       }
4030 #endif
4031       /* E hex */
4032       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
4033       orntNew[0] = -4;
4034       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
4035       orntNew[1] = ornt[1];
4036       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
4037       orntNew[2] = ornt[2];
4038       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
4039       orntNew[3] = 0;
4040       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
4041       orntNew[4] = -1;
4042       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
4043       orntNew[5] = ornt[5];
4044       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
4045       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
4046 #if 1
4047       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);
4048       for (p = 0; p < 6; ++p) {
4049         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);
4050       }
4051 #endif
4052       /* F hex */
4053       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
4054       orntNew[0] = -4;
4055       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
4056       orntNew[1] = ornt[1];
4057       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
4058       orntNew[2] = ornt[2];
4059       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4060       orntNew[3] = -1;
4061       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
4062       orntNew[4] = ornt[4];
4063       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
4064       orntNew[5] = 1;
4065       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
4066       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
4067 #if 1
4068       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);
4069       for (p = 0; p < 6; ++p) {
4070         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);
4071       }
4072 #endif
4073       /* G hex */
4074       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
4075       orntNew[0] = -4;
4076       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
4077       orntNew[1] = ornt[1];
4078       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4079       orntNew[2] = 0;
4080       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
4081       orntNew[3] = ornt[3];
4082       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
4083       orntNew[4] = ornt[4];
4084       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
4085       orntNew[5] = -3;
4086       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
4087       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
4088 #if 1
4089       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);
4090       for (p = 0; p < 6; ++p) {
4091         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);
4092       }
4093 #endif
4094       /* H hex */
4095       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
4096       orntNew[0] = -4;
4097       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
4098       orntNew[1] = ornt[1];
4099       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
4100       orntNew[2] = -1;
4101       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
4102       orntNew[3] = ornt[3];
4103       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
4104       orntNew[4] = 3;
4105       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
4106       orntNew[5] = ornt[5];
4107       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
4108       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
4109 #if 1
4110       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);
4111       for (p = 0; p < 6; ++p) {
4112         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);
4113       }
4114 #endif
4115     }
4116     /* Hybrid cells have 6 faces: Front, Back, Sides */
4117     /*
4118      3---------2---------2
4119      |         |         |
4120      |    D    2    C    |
4121      |         |         |
4122      3----3----0----1----1
4123      |         |         |
4124      |    A    0    B    |
4125      |         |         |
4126      0---------0---------1
4127      */
4128     for (c = cMax; c < cEnd; ++c) {
4129       const PetscInt  newp = (cMax - cStart)*8 + (c - cMax)*4;
4130       const PetscInt *cone, *ornt, *fornt;
4131       PetscInt        coneNew[6], orntNew[6];
4132 
4133       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4134       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4135       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
4136       for (r = 0; r < 4; ++r) {
4137         PetscInt subfA = GetQuadSubface_Static(ornt[0], r);
4138         PetscInt edgeA = GetQuadEdge_Static(ornt[0], r);
4139         PetscInt edgeB = (edgeA+3)%4;
4140         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]);
4141         coneNew[0]         = fStartNew + (cone[0] - fStart)*4 + subfA;
4142         orntNew[0]         = ornt[0];
4143         coneNew[1]         = fStartNew + (cone[1] - fStart)*4 + subfA;
4144         orntNew[1]         = ornt[0];
4145         coneNew[(r+0)%4+2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[edgeA+2] - fMax)*2 + (fornt[edgeA] < 0 ? 1 : 0);
4146         orntNew[(r+0)%4+2] = ornt[edgeA];
4147         coneNew[(r+1)%4+2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeA;
4148         orntNew[(r+1)%4+2] = 0;
4149         coneNew[(r+2)%4+2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeB;
4150         orntNew[(r+2)%4+2] = -2;
4151         coneNew[(r+3)%4+2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[edgeB+2] - fMax)*2 + (fornt[edgeB] < 0 ? 0 : 1);
4152         orntNew[(r+3)%4+2] = ornt[edgeB];
4153         ierr       = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
4154         ierr       = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
4155 #if 1
4156         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);
4157         for (p = 0; p < 2; ++p) {
4158           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);
4159         }
4160         for (p = 2; p < 6; ++p) {
4161           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);
4162         }
4163 #endif
4164       }
4165     }
4166     /* Interior split faces have 4 edges and the same cells as the parent */
4167     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4168     ierr = PetscMalloc1((4 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
4169     for (f = fStart; f < fMax; ++f) {
4170       for (r = 0; r < 4; ++r) {
4171         /* TODO: This can come from GetFaces_Internal() */
4172         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};
4173         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
4174         const PetscInt *cone, *ornt, *support;
4175         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
4176 
4177         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4178         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4179         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
4180         orntNew[(r+3)%4] = ornt[(r+3)%4];
4181         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
4182         orntNew[(r+0)%4] = ornt[r];
4183         coneNew[(r+1)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
4184         orntNew[(r+1)%4] = 0;
4185         coneNew[(r+2)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + (r+3)%4;
4186         orntNew[(r+2)%4] = -2;
4187         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4188         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4189 #if 1
4190         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4191         for (p = 0; p < 4; ++p) {
4192           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);
4193         }
4194 #endif
4195         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4196         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4197         for (s = 0; s < supportSize; ++s) {
4198           PetscInt subf;
4199           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4200           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4201           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4202           for (c = 0; c < coneSize; ++c) {
4203             if (cone[c] == f) break;
4204           }
4205           subf = GetQuadSubfaceInverse_Static(ornt[c], r);
4206           if (support[s] < cMax) {
4207             supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+subf];
4208           } else {
4209             supportRef[s] = cStartNew + (cMax       - cStart)*8 + (support[s] - cMax)*4 + subf;
4210           }
4211         }
4212         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4213 #if 1
4214         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4215         for (p = 0; p < supportSize; ++p) {
4216           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);
4217         }
4218 #endif
4219       }
4220     }
4221     /* Interior faces have 4 edges and 2 cells */
4222     for (c = cStart; c < cMax; ++c) {
4223       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};
4224       const PetscInt *cone, *ornt;
4225       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
4226 
4227       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4228       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4229       /* A-D face */
4230       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 0;
4231       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
4232       orntNew[0] = 0;
4233       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4234       orntNew[1] = 0;
4235       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4236       orntNew[2] = -2;
4237       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
4238       orntNew[3] = -2;
4239       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4240       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4241 #if 1
4242       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4243       for (p = 0; p < 4; ++p) {
4244         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);
4245       }
4246 #endif
4247       /* C-D face */
4248       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 1;
4249       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
4250       orntNew[0] = 0;
4251       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4252       orntNew[1] = 0;
4253       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4254       orntNew[2] = -2;
4255       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
4256       orntNew[3] = -2;
4257       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4258       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4259 #if 1
4260       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4261       for (p = 0; p < 4; ++p) {
4262         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);
4263       }
4264 #endif
4265       /* B-C face */
4266       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 2;
4267       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
4268       orntNew[0] = -2;
4269       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
4270       orntNew[1] = 0;
4271       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4272       orntNew[2] = 0;
4273       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4274       orntNew[3] = -2;
4275       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4276       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4277 #if 1
4278       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4279       for (p = 0; p < 4; ++p) {
4280         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);
4281       }
4282 #endif
4283       /* A-B face */
4284       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 3;
4285       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
4286       orntNew[0] = -2;
4287       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
4288       orntNew[1] = 0;
4289       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4290       orntNew[2] = 0;
4291       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4292       orntNew[3] = -2;
4293       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4294       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4295 #if 1
4296       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4297       for (p = 0; p < 4; ++p) {
4298         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);
4299       }
4300 #endif
4301       /* E-F face */
4302       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 4;
4303       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4304       orntNew[0] = -2;
4305       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
4306       orntNew[1] = -2;
4307       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
4308       orntNew[2] = 0;
4309       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4310       orntNew[3] = 0;
4311       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4312       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4313 #if 1
4314       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4315       for (p = 0; p < 4; ++p) {
4316         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);
4317       }
4318 #endif
4319       /* F-G face */
4320       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 5;
4321       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4322       orntNew[0] = -2;
4323       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
4324       orntNew[1] = -2;
4325       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
4326       orntNew[2] = 0;
4327       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4328       orntNew[3] = 0;
4329       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4330       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4331 #if 1
4332       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4333       for (p = 0; p < 4; ++p) {
4334         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);
4335       }
4336 #endif
4337       /* G-H face */
4338       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 6;
4339       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
4340       orntNew[0] = -2;
4341       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
4342       orntNew[1] = 0;
4343       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4344       orntNew[2] = 0;
4345       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4346       orntNew[3] = -2;
4347       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4348       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4349 #if 1
4350       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4351       for (p = 0; p < 4; ++p) {
4352         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);
4353       }
4354 #endif
4355       /* E-H face */
4356       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 7;
4357       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4358       orntNew[0] = -2;
4359       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
4360       orntNew[1] = -2;
4361       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
4362       orntNew[2] = 0;
4363       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4364       orntNew[3] = 0;
4365       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4366       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4367 #if 1
4368       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4369       for (p = 0; p < 4; ++p) {
4370         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);
4371       }
4372 #endif
4373       /* A-E face */
4374       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 8;
4375       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
4376       orntNew[0] = 0;
4377       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4378       orntNew[1] = 0;
4379       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4380       orntNew[2] = -2;
4381       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
4382       orntNew[3] = -2;
4383       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4384       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4385 #if 1
4386       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4387       for (p = 0; p < 4; ++p) {
4388         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);
4389       }
4390 #endif
4391       /* D-F face */
4392       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 9;
4393       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
4394       orntNew[0] = -2;
4395       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
4396       orntNew[1] = 0;
4397       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4398       orntNew[2] = 0;
4399       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4400       orntNew[3] = -2;
4401       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4402       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4403 #if 1
4404       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4405       for (p = 0; p < 4; ++p) {
4406         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);
4407       }
4408 #endif
4409       /* C-G face */
4410       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 10;
4411       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4412       orntNew[0] = -2;
4413       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
4414       orntNew[1] = -2;
4415       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
4416       orntNew[2] = 0;
4417       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4418       orntNew[3] = 0;
4419       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4420       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4421 #if 1
4422       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4423       for (p = 0; p < 4; ++p) {
4424         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);
4425       }
4426 #endif
4427       /* B-H face */
4428       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 11;
4429       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4430       orntNew[0] = 0;
4431       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4432       orntNew[1] = -2;
4433       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
4434       orntNew[2] = -2;
4435       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
4436       orntNew[3] = 0;
4437       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4438       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4439 #if 1
4440       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4441       for (p = 0; p < 4; ++p) {
4442         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);
4443       }
4444 #endif
4445       for (r = 0; r < 12; ++r) {
4446         newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
4447         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
4448         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
4449         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4450 #if 1
4451         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4452         for (p = 0; p < 2; ++p) {
4453           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);
4454         }
4455 #endif
4456       }
4457     }
4458     /* Hybrid split faces have 4 edges and same cells */
4459     for (f = fMax; f < fEnd; ++f) {
4460       const PetscInt *cone, *ornt, *support;
4461       PetscInt        coneNew[4], orntNew[4];
4462       PetscInt        supportNew[2], size, s, c;
4463 
4464       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4465       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4466       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4467       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4468       for (r = 0; r < 2; ++r) {
4469         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
4470 
4471         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
4472         orntNew[0]   = ornt[0];
4473         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
4474         orntNew[1]   = ornt[1];
4475         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (cone[2+r] - eMax);
4476         orntNew[2+r] = 0;
4477         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd      - eMax) + (f - fMax);
4478         orntNew[3-r] = 0;
4479         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4480         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4481 #if 1
4482         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
4483         for (p = 0; p < 2; ++p) {
4484           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);
4485         }
4486         for (p = 2; p < 4; ++p) {
4487           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);
4488         }
4489 #endif
4490         for (s = 0; s < size; ++s) {
4491           const PetscInt *coneCell, *orntCell, *fornt;
4492 
4493           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
4494           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
4495           for (c = 2; c < 6; ++c) if (coneCell[c] == f) break;
4496           if (c >= 6) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
4497           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
4498           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetQuadEdgeInverse_Static(orntCell[0], c-2) + (fornt[c-2] < 0 ? 1-r : r))%4;
4499         }
4500         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4501 #if 1
4502         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
4503         for (p = 0; p < size; ++p) {
4504           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);
4505         }
4506 #endif
4507       }
4508     }
4509     /* Hybrid cell faces have 4 edges and 2 cells */
4510     for (c = cMax; c < cEnd; ++c) {
4511       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4;
4512       const PetscInt *cone, *ornt;
4513       PetscInt        coneNew[4], orntNew[4];
4514       PetscInt        supportNew[2];
4515 
4516       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4517       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4518       for (r = 0; r < 4; ++r) {
4519         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], r);
4520         orntNew[0] = 0;
4521         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], r);
4522         orntNew[1] = 0;
4523         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+GetQuadEdge_Static(ornt[0], r)] - fMax);
4524         orntNew[2] = 0;
4525         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd                                   - fMax) + (c - cMax);
4526         orntNew[3] = 0;
4527         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
4528         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
4529 #if 1
4530         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);
4531         for (p = 0; p < 2; ++p) {
4532           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);
4533         }
4534         for (p = 2; p < 4; ++p) {
4535           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);
4536         }
4537 #endif
4538         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], r);
4539         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], (r+1)%4);
4540         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
4541 #if 1
4542         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);
4543         for (p = 0; p < 2; ++p) {
4544           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);
4545         }
4546 #endif
4547       }
4548     }
4549     /* Interior split edges have 2 vertices and the same faces as the parent */
4550     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4551     for (e = eStart; e < eMax; ++e) {
4552       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
4553 
4554       for (r = 0; r < 2; ++r) {
4555         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
4556         const PetscInt *cone, *ornt, *support;
4557         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4558 
4559         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4560         coneNew[0]       = vStartNew + (cone[0] - vStart);
4561         coneNew[1]       = vStartNew + (cone[1] - vStart);
4562         coneNew[(r+1)%2] = newv;
4563         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4564 #if 1
4565         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4566         for (p = 0; p < 2; ++p) {
4567           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);
4568         }
4569 #endif
4570         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
4571         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4572         for (s = 0; s < supportSize; ++s) {
4573           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4574           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4575           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4576           for (c = 0; c < coneSize; ++c) {
4577             if (cone[c] == e) break;
4578           }
4579           if (support[s] < fMax) {
4580             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%4;
4581           } else {
4582             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
4583           }
4584         }
4585         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4586 #if 1
4587         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4588         for (p = 0; p < supportSize; ++p) {
4589           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);
4590         }
4591 #endif
4592       }
4593     }
4594     /* Interior face edges have 2 vertices and 2+cells faces */
4595     for (f = fStart; f < fMax; ++f) {
4596       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};
4597       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
4598       const PetscInt *cone, *coneCell, *orntCell, *support;
4599       PetscInt        coneNew[2], coneSize, c, supportSize, s;
4600 
4601       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4602       for (r = 0; r < 4; ++r) {
4603         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
4604 
4605         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
4606         coneNew[1] = newv;
4607         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4608 #if 1
4609         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4610         for (p = 0; p < 2; ++p) {
4611           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);
4612         }
4613 #endif
4614         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4615         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4616         supportRef[0] = fStartNew + (f - fStart)*4 + r;
4617         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
4618         for (s = 0; s < supportSize; ++s) {
4619           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4620           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
4621           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
4622           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
4623           if (support[s] < cMax) {
4624             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
4625           } else {
4626             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + GetQuadEdgeInverse_Static(orntCell[c], r);
4627           }
4628         }
4629         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4630 #if 1
4631         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4632         for (p = 0; p < 2+supportSize; ++p) {
4633           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);
4634         }
4635 #endif
4636       }
4637     }
4638     /* Interior cell edges have 2 vertices and 4 faces */
4639     for (c = cStart; c < cMax; ++c) {
4640       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};
4641       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
4642       const PetscInt *cone;
4643       PetscInt        coneNew[2], supportNew[4];
4644 
4645       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4646       for (r = 0; r < 6; ++r) {
4647         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
4648 
4649         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
4650         coneNew[1] = newv;
4651         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4652 #if 1
4653         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4654         for (p = 0; p < 2; ++p) {
4655           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);
4656         }
4657 #endif
4658         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
4659         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4660 #if 1
4661         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4662         for (p = 0; p < 4; ++p) {
4663           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);
4664         }
4665 #endif
4666       }
4667     }
4668     /* Hybrid edges have two vertices and the same faces */
4669     for (e = eMax; e < eEnd; ++e) {
4670       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
4671       const PetscInt *cone, *support, *fcone;
4672       PetscInt        coneNew[2], size, fsize, s;
4673 
4674       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4675       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4676       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4677       coneNew[0] = vStartNew + (cone[0] - vStart);
4678       coneNew[1] = vStartNew + (cone[1] - vStart);
4679       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4680 #if 1
4681       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4682       for (p = 0; p < 2; ++p) {
4683         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);
4684       }
4685 #endif
4686       for (s = 0; s < size; ++s) {
4687         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
4688         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
4689         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
4690         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
4691         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + c-2;
4692       }
4693       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4694 #if 1
4695       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4696       for (p = 0; p < size; ++p) {
4697         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);
4698       }
4699 #endif
4700     }
4701     /* Hybrid face edges have 2 vertices and 2+cells faces */
4702     for (f = fMax; f < fEnd; ++f) {
4703       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
4704       const PetscInt *cone, *support, *ccone, *cornt;
4705       PetscInt        coneNew[2], size, csize, s;
4706 
4707       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4708       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4709       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4710       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
4711       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
4712       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4713 #if 1
4714       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4715       for (p = 0; p < 2; ++p) {
4716         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);
4717       }
4718 #endif
4719       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 0;
4720       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 1;
4721       for (s = 0; s < size; ++s) {
4722         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
4723         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
4724         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
4725         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
4726         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]);
4727         supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + GetQuadSubfaceInverse_Static(cornt[0], c-2);
4728       }
4729       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4730 #if 1
4731       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4732       for (p = 0; p < 2+size; ++p) {
4733         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);
4734       }
4735 #endif
4736     }
4737     /* Hybrid cell edges have 2 vertices and 4 faces */
4738     for (c = cMax; c < cEnd; ++c) {
4739       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
4740       const PetscInt *cone, *support;
4741       PetscInt        coneNew[2], size;
4742 
4743       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4744       ierr = DMPlexGetSupportSize(dm, c, &size);CHKERRQ(ierr);
4745       ierr = DMPlexGetSupport(dm, c, &support);CHKERRQ(ierr);
4746       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
4747       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
4748       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4749 #if 1
4750       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4751       for (p = 0; p < 2; ++p) {
4752         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);
4753       }
4754 #endif
4755       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 0;
4756       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 1;
4757       supportRef[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 2;
4758       supportRef[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 3;
4759       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4760 #if 1
4761       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4762       for (p = 0; p < 4; ++p) {
4763         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);
4764       }
4765 #endif
4766     }
4767     /* Interior vertices have identical supports */
4768     for (v = vStart; v < vEnd; ++v) {
4769       const PetscInt  newp = vStartNew + (v - vStart);
4770       const PetscInt *support, *cone;
4771       PetscInt        size, s;
4772 
4773       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4774       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4775       for (s = 0; s < size; ++s) {
4776         PetscInt r = 0;
4777 
4778         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4779         if (cone[1] == v) r = 1;
4780         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4781         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (support[s] - eMax);
4782       }
4783       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4784 #if 1
4785       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4786       for (p = 0; p < size; ++p) {
4787         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);
4788       }
4789 #endif
4790     }
4791     /* Interior edge vertices have 2 + faces supports */
4792     for (e = eStart; e < eMax; ++e) {
4793       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4794       const PetscInt *cone, *support;
4795       PetscInt        size, s;
4796 
4797       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4798       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4799       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4800       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4801       for (s = 0; s < size; ++s) {
4802         PetscInt r;
4803 
4804         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4805         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
4806         if (support[s] < fMax) {
4807           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*4 + r;
4808         } else {
4809           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (support[s] - fMax);
4810         }
4811       }
4812       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4813 #if 1
4814       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4815       for (p = 0; p < 2+size; ++p) {
4816         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);
4817       }
4818 #endif
4819     }
4820     /* Interior face vertices have 4 + cells supports */
4821     for (f = fStart; f < fMax; ++f) {
4822       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
4823       const PetscInt *cone, *support;
4824       PetscInt        size, s;
4825 
4826       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4827       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4828       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eMax - eStart)*2 +  (f - fStart)*4 + r;
4829       for (s = 0; s < size; ++s) {
4830         PetscInt r;
4831 
4832         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4833         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
4834         if (support[s] < cMax) {
4835           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (support[s] - cStart)*6 + r;
4836         } else {
4837           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax       - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (support[s] - cMax);
4838         }
4839       }
4840       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4841 #if 1
4842       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4843       for (p = 0; p < 4+size; ++p) {
4844         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);
4845       }
4846 #endif
4847     }
4848     /* Cell vertices have 6 supports */
4849     for (c = cStart; c < cMax; ++c) {
4850       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
4851       PetscInt       supportNew[6];
4852 
4853       for (r = 0; r < 6; ++r) {
4854         supportNew[r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
4855       }
4856       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4857     }
4858     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4859     break;
4860   default:
4861     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
4862   }
4863   PetscFunctionReturn(0);
4864 }
4865 
4866 #undef __FUNCT__
4867 #define __FUNCT__ "CellRefinerSetCoordinates"
4868 static PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
4869 {
4870   PetscSection   coordSection, coordSectionNew;
4871   Vec            coordinates, coordinatesNew;
4872   PetscScalar   *coords, *coordsNew;
4873   const PetscInt numVertices = depthSize ? depthSize[0] : 0;
4874   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, cMax, c, vStart, vStartNew, vEnd, v, eStart, eEnd, eMax, e, fStart, fEnd, fMax, f;
4875   PetscErrorCode ierr;
4876 
4877   PetscFunctionBegin;
4878   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4879   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4880   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4881   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
4882   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4883   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
4884   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, NULL);CHKERRQ(ierr);
4885   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);}
4886   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
4887   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4888   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
4889   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
4890   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
4891   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+numVertices);CHKERRQ(ierr);
4892   if (cMax < 0) cMax = cEnd;
4893   if (fMax < 0) fMax = fEnd;
4894   if (eMax < 0) eMax = eEnd;
4895   /* All vertices have the dim coordinates */
4896   for (v = vStartNew; v < vStartNew+numVertices; ++v) {
4897     ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
4898     ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
4899   }
4900   ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
4901   ierr = DMSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
4902   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4903   ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
4904   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);CHKERRQ(ierr);
4905   ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
4906   ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
4907   ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
4908   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4909   ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
4910   switch (refiner) {
4911   case 0: break;
4912   case 6: /* Hex 3D */
4913   case 8: /* Hybrid Hex 3D */
4914     /* Face vertices have the average of corner coordinates */
4915     for (f = fStart; f < fMax; ++f) {
4916       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
4917       PetscInt      *cone = NULL;
4918       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
4919 
4920       ierr = DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
4921       for (p = 0; p < closureSize*2; p += 2) {
4922         const PetscInt point = cone[p];
4923         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
4924       }
4925       for (v = 0; v < coneSize; ++v) {
4926         ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
4927       }
4928       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
4929       for (d = 0; d < dim; ++d) {
4930         coordsNew[offnew+d] = 0.0;
4931         for (v = 0; v < coneSize; ++v) coordsNew[offnew+d] += coords[off[v]+d];
4932         coordsNew[offnew+d] /= coneSize;
4933       }
4934       ierr = DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
4935     }
4936   case 2: /* Hex 2D */
4937     /* Cell vertices have the average of corner coordinates */
4938     for (c = cStart; c < cMax; ++c) {
4939       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (c - cStart) + (dim > 2 ? (fMax - fStart) : 0);
4940       PetscInt      *cone = NULL;
4941       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
4942 
4943       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
4944       for (p = 0; p < closureSize*2; p += 2) {
4945         const PetscInt point = cone[p];
4946         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
4947       }
4948       for (v = 0; v < coneSize; ++v) {
4949         ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
4950       }
4951       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
4952       for (d = 0; d < dim; ++d) {
4953         coordsNew[offnew+d] = 0.0;
4954         for (v = 0; v < coneSize; ++v) coordsNew[offnew+d] += coords[off[v]+d];
4955         coordsNew[offnew+d] /= coneSize;
4956       }
4957       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
4958     }
4959   case 1: /* Simplicial 2D */
4960   case 3: /* Hybrid Simplicial 2D */
4961   case 5: /* Simplicial 3D */
4962   case 7: /* Hybrid Simplicial 3D */
4963     /* Edge vertices have the average of endpoint coordinates */
4964     for (e = eStart; e < eMax; ++e) {
4965       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
4966       const PetscInt *cone;
4967       PetscInt        coneSize, offA, offB, offnew, d;
4968 
4969       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
4970       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
4971       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4972       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
4973       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
4974       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
4975       for (d = 0; d < dim; ++d) {
4976         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
4977       }
4978     }
4979     /* Old vertices have the same coordinates */
4980     for (v = vStart; v < vEnd; ++v) {
4981       const PetscInt newv = vStartNew + (v - vStart);
4982       PetscInt       off, offnew, d;
4983 
4984       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4985       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
4986       for (d = 0; d < dim; ++d) {
4987         coordsNew[offnew+d] = coords[off+d];
4988       }
4989     }
4990     break;
4991   default:
4992     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
4993   }
4994   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4995   ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
4996   ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
4997   ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
4998   ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
4999   PetscFunctionReturn(0);
5000 }
5001 
5002 #undef __FUNCT__
5003 #define __FUNCT__ "DMPlexCreateProcessSF"
5004 static PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
5005 {
5006   PetscInt           numRoots, numLeaves, l;
5007   const PetscInt    *localPoints;
5008   const PetscSFNode *remotePoints;
5009   PetscInt          *localPointsNew;
5010   PetscSFNode       *remotePointsNew;
5011   PetscInt          *ranks, *ranksNew;
5012   PetscErrorCode     ierr;
5013 
5014   PetscFunctionBegin;
5015   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5016   ierr = PetscMalloc1(numLeaves, &ranks);CHKERRQ(ierr);
5017   for (l = 0; l < numLeaves; ++l) {
5018     ranks[l] = remotePoints[l].rank;
5019   }
5020   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
5021   ierr = PetscMalloc1(numLeaves,    &ranksNew);CHKERRQ(ierr);
5022   ierr = PetscMalloc1(numLeaves,    &localPointsNew);CHKERRQ(ierr);
5023   ierr = PetscMalloc1(numLeaves, &remotePointsNew);CHKERRQ(ierr);
5024   for (l = 0; l < numLeaves; ++l) {
5025     ranksNew[l]              = ranks[l];
5026     localPointsNew[l]        = l;
5027     remotePointsNew[l].index = 0;
5028     remotePointsNew[l].rank  = ranksNew[l];
5029   }
5030   ierr = PetscFree(ranks);CHKERRQ(ierr);
5031   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
5032   ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
5033   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
5034   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
5035   PetscFunctionReturn(0);
5036 }
5037 
5038 #undef __FUNCT__
5039 #define __FUNCT__ "CellRefinerCreateSF"
5040 static PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5041 {
5042   PetscSF            sf, sfNew, sfProcess;
5043   IS                 processRanks;
5044   MPI_Datatype       depthType;
5045   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
5046   const PetscInt    *localPoints, *neighbors;
5047   const PetscSFNode *remotePoints;
5048   PetscInt          *localPointsNew;
5049   PetscSFNode       *remotePointsNew;
5050   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
5051   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r, n;
5052   PetscInt           cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
5053   PetscErrorCode     ierr;
5054 
5055   PetscFunctionBegin;
5056   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
5057   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5058   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5059   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5060   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5061   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5062   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5063   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
5064   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
5065   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
5066   /* Caculate size of new SF */
5067   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5068   if (numRoots < 0) PetscFunctionReturn(0);
5069   for (l = 0; l < numLeaves; ++l) {
5070     const PetscInt p = localPoints[l];
5071 
5072     switch (refiner) {
5073     case 1:
5074       /* Simplicial 2D */
5075       if ((p >= vStart) && (p < vEnd)) {
5076         /* Old vertices stay the same */
5077         ++numLeavesNew;
5078       } else if ((p >= fStart) && (p < fEnd)) {
5079         /* Old faces add new faces and vertex */
5080         numLeavesNew += 2 + 1;
5081       } else if ((p >= cStart) && (p < cEnd)) {
5082         /* Old cells add new cells and interior faces */
5083         numLeavesNew += 4 + 3;
5084       }
5085       break;
5086     case 2:
5087       /* Hex 2D */
5088       if ((p >= vStart) && (p < vEnd)) {
5089         /* Old vertices stay the same */
5090         ++numLeavesNew;
5091       } else if ((p >= fStart) && (p < fEnd)) {
5092         /* Old faces add new faces and vertex */
5093         numLeavesNew += 2 + 1;
5094       } else if ((p >= cStart) && (p < cEnd)) {
5095         /* Old cells add new cells, interior faces, and vertex */
5096         numLeavesNew += 4 + 4 + 1;
5097       }
5098       break;
5099     case 5:
5100       /* Simplicial 3D */
5101       if ((p >= vStart) && (p < vEnd)) {
5102         /* Old vertices stay the same */
5103         ++numLeavesNew;
5104       } else if ((p >= eStart) && (p < eEnd)) {
5105         /* Old edges add new edges and vertex */
5106         numLeavesNew += 2 + 1;
5107       } else if ((p >= fStart) && (p < fEnd)) {
5108         /* Old faces add new faces and face edges */
5109         numLeavesNew += 4 + 3;
5110       } else if ((p >= cStart) && (p < cEnd)) {
5111         /* Old cells add new cells and interior faces and edges */
5112         numLeavesNew += 8 + 8 + 1;
5113       }
5114       break;
5115     case 7:
5116       /* Hybrid Simplicial 3D */
5117       if ((p >= vStart) && (p < vEnd)) {
5118         /* Interior vertices stay the same */
5119         ++numLeavesNew;
5120       } else if ((p >= eStart) && (p < eMax)) {
5121         /* Interior edges add new edges and vertex */
5122         numLeavesNew += 2 + 1;
5123       } else if ((p >= eMax) && (p < eEnd)) {
5124         /* Hybrid edges stay the same */
5125         ++numLeavesNew;
5126       } else if ((p >= fStart) && (p < fMax)) {
5127         /* Interior faces add new faces and edges */
5128         numLeavesNew += 4 + 3;
5129       } else if ((p >= fMax) && (p < fEnd)) {
5130         /* Hybrid faces add new faces and edges */
5131         numLeavesNew += 2 + 1;
5132       } else if ((p >= cStart) && (p < cMax)) {
5133         /* Interior cells add new cells, faces, and edges */
5134         numLeavesNew += 8 + 8 + 1;
5135       } else if ((p >= cMax) && (p < cEnd)) {
5136         /* Hybrid cells add new cells and faces */
5137         numLeavesNew += 4 + 3;
5138       }
5139       break;
5140     case 6:
5141       /* Hex 3D */
5142       if ((p >= vStart) && (p < vEnd)) {
5143         /* Old vertices stay the same */
5144         ++numLeavesNew;
5145       } else if ((p >= eStart) && (p < eEnd)) {
5146         /* Old edges add new edges, and vertex */
5147         numLeavesNew += 2 + 1;
5148       } else if ((p >= fStart) && (p < fEnd)) {
5149         /* Old faces add new faces, edges, and vertex */
5150         numLeavesNew += 4 + 4 + 1;
5151       } else if ((p >= cStart) && (p < cEnd)) {
5152         /* Old cells add new cells, faces, edges, and vertex */
5153         numLeavesNew += 8 + 12 + 6 + 1;
5154       }
5155       break;
5156     case 8:
5157       /* Hybrid Hex 3D */
5158       if ((p >= vStart) && (p < vEnd)) {
5159         /* Old vertices stay the same */
5160         ++numLeavesNew;
5161       } else if ((p >= eStart) && (p < eMax)) {
5162         /* Interior edges add new edges, and vertex */
5163         numLeavesNew += 2 + 1;
5164       } else if ((p >= eMax) && (p < eEnd)) {
5165         /* Hybrid edges stay the same */
5166         ++numLeavesNew;
5167       } else if ((p >= fStart) && (p < fMax)) {
5168         /* Interior faces add new faces, edges, and vertex */
5169         numLeavesNew += 4 + 4 + 1;
5170       } else if ((p >= fMax) && (p < fEnd)) {
5171         /* Hybrid faces add new faces and edges */
5172         numLeavesNew += 2 + 1;
5173       } else if ((p >= cStart) && (p < cMax)) {
5174         /* Interior cells add new cells, faces, edges, and vertex */
5175         numLeavesNew += 8 + 12 + 6 + 1;
5176       } else if ((p >= cStart) && (p < cEnd)) {
5177         /* Hybrid cells add new cells, faces, and edges */
5178         numLeavesNew += 4 + 4 + 1;
5179       }
5180       break;
5181     default:
5182       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5183     }
5184   }
5185   /* Communicate depthSizes for each remote rank */
5186   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
5187   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
5188   ierr = PetscMalloc5((depth+1)*numNeighbors,&rdepthSize,numNeighbors,&rvStartNew,numNeighbors,&reStartNew,numNeighbors,&rfStartNew,numNeighbors,&rcStartNew);CHKERRQ(ierr);
5189   ierr = PetscMalloc7(depth+1,&depthSizeOld,(depth+1)*numNeighbors,&rdepthSizeOld,(depth+1)*numNeighbors,&rdepthMaxOld,numNeighbors,&rvStart,numNeighbors,&reStart,numNeighbors,&rfStart,numNeighbors,&rcStart);CHKERRQ(ierr);
5190   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
5191   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
5192   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5193   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5194   for (n = 0; n < numNeighbors; ++n) {
5195     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
5196   }
5197   depthSizeOld[depth]   = cMax;
5198   depthSizeOld[0]       = vMax;
5199   depthSizeOld[depth-1] = fMax;
5200   depthSizeOld[1]       = eMax;
5201 
5202   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5203   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5204 
5205   depthSizeOld[depth]   = cEnd - cStart;
5206   depthSizeOld[0]       = vEnd - vStart;
5207   depthSizeOld[depth-1] = fEnd - fStart;
5208   depthSizeOld[1]       = eEnd - eStart;
5209 
5210   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5211   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5212   for (n = 0; n < numNeighbors; ++n) {
5213     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
5214   }
5215   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
5216   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
5217   /* Calculate new point SF */
5218   ierr = PetscMalloc1(numLeavesNew,    &localPointsNew);CHKERRQ(ierr);
5219   ierr = PetscMalloc1(numLeavesNew, &remotePointsNew);CHKERRQ(ierr);
5220   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
5221   for (l = 0, m = 0; l < numLeaves; ++l) {
5222     PetscInt    p     = localPoints[l];
5223     PetscInt    rp    = remotePoints[l].index, n;
5224     PetscMPIInt rrank = remotePoints[l].rank;
5225 
5226     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
5227     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
5228     switch (refiner) {
5229     case 1:
5230       /* Simplicial 2D */
5231       if ((p >= vStart) && (p < vEnd)) {
5232         /* Old vertices stay the same */
5233         localPointsNew[m]        = vStartNew     + (p  - vStart);
5234         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5235         remotePointsNew[m].rank  = rrank;
5236         ++m;
5237       } else if ((p >= fStart) && (p < fEnd)) {
5238         /* Old faces add new faces and vertex */
5239         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5240         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5241         remotePointsNew[m].rank  = rrank;
5242         ++m;
5243         for (r = 0; r < 2; ++r, ++m) {
5244           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5245           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5246           remotePointsNew[m].rank  = rrank;
5247         }
5248       } else if ((p >= cStart) && (p < cEnd)) {
5249         /* Old cells add new cells and interior faces */
5250         for (r = 0; r < 4; ++r, ++m) {
5251           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5252           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5253           remotePointsNew[m].rank  = rrank;
5254         }
5255         for (r = 0; r < 3; ++r, ++m) {
5256           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
5257           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
5258           remotePointsNew[m].rank  = rrank;
5259         }
5260       }
5261       break;
5262     case 2:
5263       /* Hex 2D */
5264       if ((p >= vStart) && (p < vEnd)) {
5265         /* Old vertices stay the same */
5266         localPointsNew[m]        = vStartNew     + (p  - vStart);
5267         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5268         remotePointsNew[m].rank  = rrank;
5269         ++m;
5270       } else if ((p >= fStart) && (p < fEnd)) {
5271         /* Old faces add new faces and vertex */
5272         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5273         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5274         remotePointsNew[m].rank  = rrank;
5275         ++m;
5276         for (r = 0; r < 2; ++r, ++m) {
5277           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5278           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5279           remotePointsNew[m].rank  = rrank;
5280         }
5281       } else if ((p >= cStart) && (p < cEnd)) {
5282         /* Old cells add new cells, interior faces, and vertex */
5283         for (r = 0; r < 4; ++r, ++m) {
5284           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5285           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5286           remotePointsNew[m].rank  = rrank;
5287         }
5288         for (r = 0; r < 4; ++r, ++m) {
5289           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
5290           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
5291           remotePointsNew[m].rank  = rrank;
5292         }
5293         for (r = 0; r < 1; ++r, ++m) {
5294           localPointsNew[m]        = vStartNew     + (fEnd - fStart)                    + (p  - cStart)     + r;
5295           remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]) + r;
5296           remotePointsNew[m].rank  = rrank;
5297         }
5298       }
5299       break;
5300     case 3:
5301       /* Hybrid simplicial 2D */
5302       if ((p >= vStart) && (p < vEnd)) {
5303         /* Old vertices stay the same */
5304         localPointsNew[m]        = vStartNew     + (p  - vStart);
5305         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5306         remotePointsNew[m].rank  = rrank;
5307         ++m;
5308       } else if ((p >= fStart) && (p < fMax)) {
5309         /* Old interior faces add new faces and vertex */
5310         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5311         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5312         remotePointsNew[m].rank  = rrank;
5313         ++m;
5314         for (r = 0; r < 2; ++r, ++m) {
5315           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5316           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5317           remotePointsNew[m].rank  = rrank;
5318         }
5319       } else if ((p >= fMax) && (p < fEnd)) {
5320         /* Old hybrid faces stay the same */
5321         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
5322         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
5323         remotePointsNew[m].rank  = rrank;
5324         ++m;
5325       } else if ((p >= cStart) && (p < cMax)) {
5326         /* Old interior cells add new cells and interior faces */
5327         for (r = 0; r < 4; ++r, ++m) {
5328           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5329           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5330           remotePointsNew[m].rank  = rrank;
5331         }
5332         for (r = 0; r < 3; ++r, ++m) {
5333           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
5334           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
5335           remotePointsNew[m].rank  = rrank;
5336         }
5337       } else if ((p >= cStart) && (p < cMax)) {
5338         /* Old hybrid cells add new cells and hybrid face */
5339         for (r = 0; r < 2; ++r, ++m) {
5340           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5341           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5342           remotePointsNew[m].rank  = rrank;
5343         }
5344         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
5345         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]);
5346         remotePointsNew[m].rank  = rrank;
5347         ++m;
5348       }
5349       break;
5350     case 5:
5351       /* Simplicial 3D */
5352       if ((p >= vStart) && (p < vEnd)) {
5353         /* Old vertices stay the same */
5354         localPointsNew[m]        = vStartNew     + (p  - vStart);
5355         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5356         remotePointsNew[m].rank  = rrank;
5357         ++m;
5358       } else if ((p >= eStart) && (p < eEnd)) {
5359         /* Old edges add new edges and vertex */
5360         for (r = 0; r < 2; ++r, ++m) {
5361           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
5362           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
5363           remotePointsNew[m].rank  = rrank;
5364         }
5365         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
5366         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
5367         remotePointsNew[m].rank  = rrank;
5368         ++m;
5369       } else if ((p >= fStart) && (p < fEnd)) {
5370         /* Old faces add new faces and face edges */
5371         for (r = 0; r < 4; ++r, ++m) {
5372           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
5373           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
5374           remotePointsNew[m].rank  = rrank;
5375         }
5376         for (r = 0; r < 3; ++r, ++m) {
5377           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (p  - fStart)*3     + r;
5378           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + (rp - rfStart[n])*3 + r;
5379           remotePointsNew[m].rank  = rrank;
5380         }
5381       } else if ((p >= cStart) && (p < cEnd)) {
5382         /* Old cells add new cells and interior faces and edges */
5383         for (r = 0; r < 8; ++r, ++m) {
5384           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
5385           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
5386           remotePointsNew[m].rank  = rrank;
5387         }
5388         for (r = 0; r < 8; ++r, ++m) {
5389           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*4                    + (p  - cStart)*8     + r;
5390           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*4 + (rp - rcStart[n])*8 + r;
5391           remotePointsNew[m].rank  = rrank;
5392         }
5393         for (r = 0; r < 1; ++r, ++m) {
5394           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (fEnd - fStart)*3                    + (p  - cStart)*1     + r;
5395           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + rdepthSizeOld[n*(depth+1)+depth-1]*3 + (rp - rcStart[n])*1 + r;
5396           remotePointsNew[m].rank  = rrank;
5397         }
5398       }
5399       break;
5400     case 7:
5401       /* Hybrid Simplicial 3D */
5402       if ((p >= vStart) && (p < vEnd)) {
5403         /* Interior vertices stay the same */
5404         localPointsNew[m]        = vStartNew     + (p  - vStart);
5405         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5406         remotePointsNew[m].rank  = rrank;
5407         ++m;
5408       } else if ((p >= eStart) && (p < eMax)) {
5409         /* Interior edges add new edges and vertex */
5410         for (r = 0; r < 2; ++r, ++m) {
5411           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
5412           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
5413           remotePointsNew[m].rank  = rrank;
5414         }
5415         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
5416         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
5417         remotePointsNew[m].rank  = rrank;
5418         ++m;
5419       } else if ((p >= eMax) && (p < eEnd)) {
5420         /* Hybrid edges stay the same */
5421         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - eMax);
5422         remotePointsNew[m].index = rvStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*3 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n]) + (rp - rdepthMaxOld[n*(depth+1)+1]);
5423         remotePointsNew[m].rank  = rrank;
5424         ++m;
5425       } else if ((p >= fStart) && (p < fMax)) {
5426         /* Interior faces add new faces and edges */
5427         for (r = 0; r < 4; ++r, ++m) {
5428           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
5429           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
5430           remotePointsNew[m].rank  = rrank;
5431         }
5432         for (r = 0; r < 3; ++r, ++m) {
5433           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*3     + r;
5434           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
5435           remotePointsNew[m].rank  = rrank;
5436         }
5437       } else if ((p >= fMax) && (p < fEnd)) {
5438         /* Hybrid faces add new faces and edges */
5439         for (r = 0; r < 2; ++r, ++m) {
5440           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fMax)*2                              + r;
5441           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;
5442           remotePointsNew[m].rank  = rrank;
5443         }
5444         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - fMax);
5445         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)+depth-1]);
5446         remotePointsNew[m].rank  = rrank;
5447         ++m;
5448       } else if ((p >= cStart) && (p < cMax)) {
5449         /* Interior cells add new cells, faces, and edges */
5450         for (r = 0; r < 8; ++r, ++m) {
5451           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
5452           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
5453           remotePointsNew[m].rank  = rrank;
5454         }
5455         for (r = 0; r < 8; ++r, ++m) {
5456           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*8     + r;
5457           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*8 + r;
5458           remotePointsNew[m].rank  = rrank;
5459         }
5460         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (p  - cStart)*1     + r;
5461         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;
5462         remotePointsNew[m].rank  = rrank;
5463         ++m;
5464       } else if ((p >= cMax) && (p < cEnd)) {
5465         /* Hybrid cells add new cells and faces */
5466         for (r = 0; r < 4; ++r, ++m) {
5467           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
5468           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
5469           remotePointsNew[m].rank  = rrank;
5470         }
5471         for (r = 0; r < 3; ++r, ++m) {
5472           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*2                              + (p  - cMax)*3                            + r;
5473           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;
5474           remotePointsNew[m].rank  = rrank;
5475         }
5476       }
5477       break;
5478     case 6:
5479       /* Hex 3D */
5480       if ((p >= vStart) && (p < vEnd)) {
5481         /* Old vertices stay the same */
5482         localPointsNew[m]        = vStartNew     + (p  - vStart);
5483         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5484         remotePointsNew[m].rank  = rrank;
5485         ++m;
5486       } else if ((p >= eStart) && (p < eEnd)) {
5487         /* Old edges add new edges and vertex */
5488         for (r = 0; r < 2; ++r, ++m) {
5489           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
5490           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
5491           remotePointsNew[m].rank  = rrank;
5492         }
5493         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
5494         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
5495         remotePointsNew[m].rank  = rrank;
5496         ++m;
5497       } else if ((p >= fStart) && (p < fEnd)) {
5498         /* Old faces add new faces, edges, and vertex */
5499         for (r = 0; r < 4; ++r, ++m) {
5500           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
5501           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
5502           remotePointsNew[m].rank  = rrank;
5503         }
5504         for (r = 0; r < 4; ++r, ++m) {
5505           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (p  - fStart)*4     + r;
5506           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + (rp - rfStart[n])*4 + r;
5507           remotePointsNew[m].rank  = rrank;
5508         }
5509         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eEnd - eStart)              + (p  - fStart);
5510         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+1] + (rp - rfStart[n]);
5511         remotePointsNew[m].rank  = rrank;
5512         ++m;
5513       } else if ((p >= cStart) && (p < cEnd)) {
5514         /* Old cells add new cells, faces, edges, and vertex */
5515         for (r = 0; r < 8; ++r, ++m) {
5516           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
5517           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
5518           remotePointsNew[m].rank  = rrank;
5519         }
5520         for (r = 0; r < 12; ++r, ++m) {
5521           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*4                    + (p  - cStart)*12     + r;
5522           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*4 + (rp - rcStart[n])*12 + r;
5523           remotePointsNew[m].rank  = rrank;
5524         }
5525         for (r = 0; r < 6; ++r, ++m) {
5526           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (fEnd - fStart)*4                    + (p  - cStart)*6     + r;
5527           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + rdepthSizeOld[n*(depth+1)+depth-1]*4 + (rp - rcStart[n])*6 + r;
5528           remotePointsNew[m].rank  = rrank;
5529         }
5530         for (r = 0; r < 1; ++r, ++m) {
5531           localPointsNew[m]        = vStartNew     + (eEnd - eStart)              + (fEnd - fStart)                    + (p  - cStart)     + r;
5532           remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+1] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]) + r;
5533           remotePointsNew[m].rank  = rrank;
5534         }
5535       }
5536       break;
5537     case 8:
5538       /* Hybrid Hex 3D */
5539       if ((p >= vStart) && (p < vEnd)) {
5540         /* Interior vertices stay the same */
5541         localPointsNew[m]        = vStartNew     + (p  - vStart);
5542         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5543         remotePointsNew[m].rank  = rrank;
5544         ++m;
5545       } else if ((p >= eStart) && (p < eMax)) {
5546         /* Interior edges add new edges and vertex */
5547         for (r = 0; r < 2; ++r, ++m) {
5548           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
5549           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
5550           remotePointsNew[m].rank  = rrank;
5551         }
5552         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
5553         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
5554         remotePointsNew[m].rank  = rrank;
5555         ++m;
5556       } else if ((p >= eMax) && (p < eEnd)) {
5557         /* Hybrid edges stay the same */
5558         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (p  - eMax);
5559         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]);
5560         remotePointsNew[m].rank  = rrank;
5561         ++m;
5562       } else if ((p >= fStart) && (p < fMax)) {
5563         /* Interior faces add new faces, edges, and vertex */
5564         for (r = 0; r < 4; ++r, ++m) {
5565           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
5566           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
5567           remotePointsNew[m].rank  = rrank;
5568         }
5569         for (r = 0; r < 4; ++r, ++m) {
5570           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*4     + r;
5571           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*4 + r;
5572           remotePointsNew[m].rank  = rrank;
5573         }
5574         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax                        - eStart)     + (p  - fStart);
5575         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
5576         remotePointsNew[m].rank  = rrank;
5577         ++m;
5578       } else if ((p >= fMax) && (p < fEnd)) {
5579         /* Hybrid faces add new faces and edges */
5580         for (r = 0; r < 2; ++r, ++m) {
5581           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fMax)*2                              + r;
5582           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;
5583           remotePointsNew[m].rank  = rrank;
5584         }
5585         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (fEnd                                          - fMax);
5586         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]);
5587         remotePointsNew[m].rank  = rrank;
5588         ++m;
5589       } else if ((p >= cStart) && (p < cMax)) {
5590         /* Interior cells add new cells, faces, edges, and vertex */
5591         for (r = 0; r < 8; ++r, ++m) {
5592           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
5593           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
5594           remotePointsNew[m].rank  = rrank;
5595         }
5596         for (r = 0; r < 12; ++r, ++m) {
5597           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*12     + r;
5598           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*12 + r;
5599           remotePointsNew[m].rank  = rrank;
5600         }
5601         for (r = 0; r < 6; ++r, ++m) {
5602           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (p  - cStart)*6     + r;
5603           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;
5604           remotePointsNew[m].rank  = rrank;
5605         }
5606         for (r = 0; r < 1; ++r, ++m) {
5607           localPointsNew[m]        = vStartNew     + (eMax                        - eStart)     + (fMax                              - fStart)     + (p  - cStart)     + r;
5608           remotePointsNew[m].index = rvStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]) + r;
5609           remotePointsNew[m].rank  = rrank;
5610         }
5611       } else if ((p >= cMax) && (p < cEnd)) {
5612         /* Hybrid cells add new cells, faces, and edges */
5613         for (r = 0; r < 4; ++r, ++m) {
5614           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
5615           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
5616           remotePointsNew[m].rank  = rrank;
5617         }
5618         for (r = 0; r < 4; ++r, ++m) {
5619           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*2                              + (p  - cMax)*4                            + r;
5620           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;
5621           remotePointsNew[m].rank  = rrank;
5622         }
5623         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (fEnd                                          - fMax)                              + (p  - cMax);
5624         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]);
5625         remotePointsNew[m].rank  = rrank;
5626         ++m;
5627       }
5628       break;
5629     default:
5630       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5631     }
5632   }
5633   if (m != numLeavesNew) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of leaf point %d should be %d", m, numLeavesNew);
5634   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
5635   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
5636   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
5637   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
5638   ierr = PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
5639   PetscFunctionReturn(0);
5640 }
5641 
5642 #undef __FUNCT__
5643 #define __FUNCT__ "CellRefinerCreateLabels"
5644 static PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5645 {
5646   PetscInt       numLabels, l;
5647   PetscInt       depth, newp, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r;
5648   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
5649   PetscErrorCode ierr;
5650 
5651   PetscFunctionBegin;
5652   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5653   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5654   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5655   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5656   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5657   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
5658   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
5659   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5660   switch (refiner) {
5661   case 0: break;
5662   case 7:
5663   case 8:
5664     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
5665   case 3:
5666   case 4:
5667     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5668     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5669   }
5670   for (l = 0; l < numLabels; ++l) {
5671     DMLabel         label, labelNew;
5672     const char     *lname;
5673     PetscBool       isDepth;
5674     IS              valueIS;
5675     const PetscInt *values;
5676     PetscInt        numValues, val;
5677 
5678     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
5679     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
5680     if (isDepth) continue;
5681     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
5682     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
5683     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
5684     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
5685     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
5686     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
5687     for (val = 0; val < numValues; ++val) {
5688       IS              pointIS;
5689       const PetscInt *points;
5690       PetscInt        numPoints, n;
5691 
5692       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
5693       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
5694       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
5695       for (n = 0; n < numPoints; ++n) {
5696         const PetscInt p = points[n];
5697         switch (refiner) {
5698         case 1:
5699           /* Simplicial 2D */
5700           if ((p >= vStart) && (p < vEnd)) {
5701             /* Old vertices stay the same */
5702             newp = vStartNew + (p - vStart);
5703             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5704           } else if ((p >= fStart) && (p < fEnd)) {
5705             /* Old faces add new faces and vertex */
5706             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5707             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5708             for (r = 0; r < 2; ++r) {
5709               newp = fStartNew + (p - fStart)*2 + r;
5710               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5711             }
5712           } else if ((p >= cStart) && (p < cEnd)) {
5713             /* Old cells add new cells and interior faces */
5714             for (r = 0; r < 4; ++r) {
5715               newp = cStartNew + (p - cStart)*4 + r;
5716               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5717             }
5718             for (r = 0; r < 3; ++r) {
5719               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
5720               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5721             }
5722           }
5723           break;
5724         case 2:
5725           /* Hex 2D */
5726           if ((p >= vStart) && (p < vEnd)) {
5727             /* Old vertices stay the same */
5728             newp = vStartNew + (p - vStart);
5729             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5730           } else if ((p >= fStart) && (p < fEnd)) {
5731             /* Old faces add new faces and vertex */
5732             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5733             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5734             for (r = 0; r < 2; ++r) {
5735               newp = fStartNew + (p - fStart)*2 + r;
5736               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5737             }
5738           } else if ((p >= cStart) && (p < cEnd)) {
5739             /* Old cells add new cells and interior faces and vertex */
5740             for (r = 0; r < 4; ++r) {
5741               newp = cStartNew + (p - cStart)*4 + r;
5742               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5743             }
5744             for (r = 0; r < 4; ++r) {
5745               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
5746               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5747             }
5748             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
5749             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5750           }
5751           break;
5752         case 3:
5753           /* Hybrid simplicial 2D */
5754           if ((p >= vStart) && (p < vEnd)) {
5755             /* Old vertices stay the same */
5756             newp = vStartNew + (p - vStart);
5757             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5758           } else if ((p >= fStart) && (p < fMax)) {
5759             /* Old interior faces add new faces and vertex */
5760             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5761             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5762             for (r = 0; r < 2; ++r) {
5763               newp = fStartNew + (p - fStart)*2 + r;
5764               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5765             }
5766           } else if ((p >= fMax) && (p < fEnd)) {
5767             /* Old hybrid faces stay the same */
5768             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
5769             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5770           } else if ((p >= cStart) && (p < cMax)) {
5771             /* Old interior cells add new cells and interior faces */
5772             for (r = 0; r < 4; ++r) {
5773               newp = cStartNew + (p - cStart)*4 + r;
5774               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5775             }
5776             for (r = 0; r < 3; ++r) {
5777               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
5778               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5779             }
5780           } else if ((p >= cMax) && (p < cEnd)) {
5781             /* Old hybrid cells add new cells and hybrid face */
5782             for (r = 0; r < 2; ++r) {
5783               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
5784               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5785             }
5786             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
5787             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5788           }
5789           break;
5790         case 5:
5791           /* Simplicial 3D */
5792           if ((p >= vStart) && (p < vEnd)) {
5793             /* Old vertices stay the same */
5794             newp = vStartNew + (p - vStart);
5795             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5796           } else if ((p >= eStart) && (p < eEnd)) {
5797             /* Old edges add new edges and vertex */
5798             for (r = 0; r < 2; ++r) {
5799               newp = eStartNew + (p - eStart)*2 + r;
5800               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5801             }
5802             newp = vStartNew + (vEnd - vStart) + (p - eStart);
5803             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5804           } else if ((p >= fStart) && (p < fEnd)) {
5805             /* Old faces add new faces and edges */
5806             for (r = 0; r < 4; ++r) {
5807               newp = fStartNew + (p - fStart)*4 + r;
5808               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5809             }
5810             for (r = 0; r < 3; ++r) {
5811               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
5812               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5813             }
5814           } else if ((p >= cStart) && (p < cEnd)) {
5815             /* Old cells add new cells and interior faces and edges */
5816             for (r = 0; r < 8; ++r) {
5817               newp = cStartNew + (p - cStart)*8 + r;
5818               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5819             }
5820             for (r = 0; r < 8; ++r) {
5821               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*8 + r;
5822               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5823             }
5824             for (r = 0; r < 1; ++r) {
5825               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*1 + r;
5826               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5827             }
5828           }
5829           break;
5830         case 7:
5831           /* Hybrid Simplicial 3D */
5832           if ((p >= vStart) && (p < vEnd)) {
5833             /* Interior vertices stay the same */
5834             newp = vStartNew + (p - vStart);
5835             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5836           } else if ((p >= eStart) && (p < eMax)) {
5837             /* Interior edges add new edges and vertex */
5838             for (r = 0; r < 2; ++r) {
5839               newp = eStartNew + (p - eStart)*2 + r;
5840               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5841             }
5842             newp = vStartNew + (vEnd - vStart) + (p - eStart);
5843             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5844           } else if ((p >= eMax) && (p < eEnd)) {
5845             /* Hybrid edges stay the same */
5846             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - eMax);
5847             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5848           } else if ((p >= fStart) && (p < fMax)) {
5849             /* Interior faces add new faces and edges */
5850             for (r = 0; r < 4; ++r) {
5851               newp = fStartNew + (p - fStart)*4 + r;
5852               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5853             }
5854             for (r = 0; r < 3; ++r) {
5855               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
5856               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5857             }
5858           } else if ((p >= fMax) && (p < fEnd)) {
5859             /* Hybrid faces add new faces and edges */
5860             for (r = 0; r < 2; ++r) {
5861               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (p - fMax)*2 + r;
5862               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5863             }
5864             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - fMax);
5865             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5866           } else if ((p >= cStart) && (p < cMax)) {
5867             /* Interior cells add new cells, faces, and edges */
5868             for (r = 0; r < 8; ++r) {
5869               newp = cStartNew + (p - cStart)*8 + r;
5870               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5871             }
5872             for (r = 0; r < 8; ++r) {
5873               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*8 + r;
5874               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5875             }
5876             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart);
5877             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5878           } else if ((p >= cMax) && (p < cEnd)) {
5879             /* Hybrid cells add new cells and faces */
5880             for (r = 0; r < 4; ++r) {
5881               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
5882               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5883             }
5884             for (r = 0; r < 3; ++r) {
5885               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
5886               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5887             }
5888           }
5889           break;
5890         case 6:
5891           /* Hex 3D */
5892           if ((p >= vStart) && (p < vEnd)) {
5893             /* Old vertices stay the same */
5894             newp = vStartNew + (p - vStart);
5895             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5896           } else if ((p >= eStart) && (p < eEnd)) {
5897             /* Old edges add new edges and vertex */
5898             for (r = 0; r < 2; ++r) {
5899               newp = eStartNew + (p - eStart)*2 + r;
5900               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5901             }
5902             newp = vStartNew + (vEnd - vStart) + (p - eStart);
5903             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5904           } else if ((p >= fStart) && (p < fEnd)) {
5905             /* Old faces add new faces, edges, and vertex */
5906             for (r = 0; r < 4; ++r) {
5907               newp = fStartNew + (p - fStart)*4 + r;
5908               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5909             }
5910             for (r = 0; r < 4; ++r) {
5911               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*4 + r;
5912               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5913             }
5914             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (p - fStart);
5915             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5916           } else if ((p >= cStart) && (p < cEnd)) {
5917             /* Old cells add new cells, faces, edges, and vertex */
5918             for (r = 0; r < 8; ++r) {
5919               newp = cStartNew + (p - cStart)*8 + r;
5920               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5921             }
5922             for (r = 0; r < 12; ++r) {
5923               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*12 + r;
5924               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5925             }
5926             for (r = 0; r < 6; ++r) {
5927               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (p - cStart)*6 + r;
5928               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5929             }
5930             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (p - cStart);
5931             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5932           }
5933           break;
5934         case 8:
5935           /* Hybrid Hex 3D */
5936           if ((p >= vStart) && (p < vEnd)) {
5937             /* Interior vertices stay the same */
5938             newp = vStartNew + (p - vStart);
5939             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5940           } else if ((p >= eStart) && (p < eMax)) {
5941             /* Interior edges add new edges and vertex */
5942             for (r = 0; r < 2; ++r) {
5943               newp = eStartNew + (p - eStart)*2 + r;
5944               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5945             }
5946             newp = vStartNew + (vEnd - vStart) + (p - eStart);
5947             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5948           } else if ((p >= eMax) && (p < eEnd)) {
5949             /* Hybrid edges stay the same */
5950             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - eMax);
5951             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5952           } else if ((p >= fStart) && (p < fMax)) {
5953             /* Interior faces add new faces, edges, and vertex */
5954             for (r = 0; r < 4; ++r) {
5955               newp = fStartNew + (p - fStart)*4 + r;
5956               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5957             }
5958             for (r = 0; r < 4; ++r) {
5959               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*4 + r;
5960               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5961             }
5962             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (p - fStart);
5963             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5964           } else if ((p >= fMax) && (p < fEnd)) {
5965             /* Hybrid faces add new faces and edges */
5966             for (r = 0; r < 2; ++r) {
5967               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (p - fMax)*2 + r;
5968               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5969             }
5970             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - fMax);
5971             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5972           } else if ((p >= cStart) && (p < cMax)) {
5973             /* Interior cells add new cells, faces, edges, and vertex */
5974             for (r = 0; r < 8; ++r) {
5975               newp = cStartNew + (p - cStart)*8 + r;
5976               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5977             }
5978             for (r = 0; r < 12; ++r) {
5979               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*12 + r;
5980               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5981             }
5982             for (r = 0; r < 6; ++r) {
5983               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (p - cStart)*6 + r;
5984               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5985             }
5986             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (p - cStart);
5987             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5988           } else if ((p >= cMax) && (p < cEnd)) {
5989             /* Hybrid cells add new cells, faces, and edges */
5990             for (r = 0; r < 4; ++r) {
5991               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
5992               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5993             }
5994             for (r = 0; r < 4; ++r) {
5995               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (p - cMax)*4 + r;
5996               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5997             }
5998             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (fEnd - fMax) + (p - cMax);
5999             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6000           }
6001           break;
6002         default:
6003           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6004         }
6005       }
6006       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
6007       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
6008     }
6009     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
6010     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
6011     if (0) {
6012       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
6013       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
6014       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
6015     }
6016   }
6017   PetscFunctionReturn(0);
6018 }
6019 
6020 #undef __FUNCT__
6021 #define __FUNCT__ "DMPlexRefineUniform_Internal"
6022 /* This will only work for interpolated meshes */
6023 PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
6024 {
6025   DM             rdm;
6026   PetscInt      *depthSize;
6027   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
6028   PetscErrorCode ierr;
6029 
6030   PetscFunctionBegin;
6031   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
6032   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
6033   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6034   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
6035   /* Calculate number of new points of each depth */
6036   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6037   ierr = PetscMalloc1((depth+1), &depthSize);CHKERRQ(ierr);
6038   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
6039   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
6040   /* Step 1: Set chart */
6041   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
6042   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
6043   /* Step 2: Set cone/support sizes */
6044   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6045   /* Step 3: Setup refined DM */
6046   ierr = DMSetUp(rdm);CHKERRQ(ierr);
6047   /* Step 4: Set cones and supports */
6048   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6049   /* Step 5: Stratify */
6050   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
6051   /* Step 6: Set coordinates for vertices */
6052   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6053   /* Step 7: Create pointSF */
6054   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6055   /* Step 8: Create labels */
6056   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6057   ierr = PetscFree(depthSize);CHKERRQ(ierr);
6058 
6059   *dmRefined = rdm;
6060   PetscFunctionReturn(0);
6061 }
6062 
6063 #undef __FUNCT__
6064 #define __FUNCT__ "DMPlexSetRefinementUniform"
6065 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
6066 {
6067   DM_Plex *mesh = (DM_Plex*) dm->data;
6068 
6069   PetscFunctionBegin;
6070   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6071   mesh->refinementUniform = refinementUniform;
6072   PetscFunctionReturn(0);
6073 }
6074 
6075 #undef __FUNCT__
6076 #define __FUNCT__ "DMPlexGetRefinementUniform"
6077 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
6078 {
6079   DM_Plex *mesh = (DM_Plex*) dm->data;
6080 
6081   PetscFunctionBegin;
6082   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6083   PetscValidPointer(refinementUniform,  2);
6084   *refinementUniform = mesh->refinementUniform;
6085   PetscFunctionReturn(0);
6086 }
6087 
6088 #undef __FUNCT__
6089 #define __FUNCT__ "DMPlexSetRefinementLimit"
6090 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
6091 {
6092   DM_Plex *mesh = (DM_Plex*) dm->data;
6093 
6094   PetscFunctionBegin;
6095   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6096   mesh->refinementLimit = refinementLimit;
6097   PetscFunctionReturn(0);
6098 }
6099 
6100 #undef __FUNCT__
6101 #define __FUNCT__ "DMPlexGetRefinementLimit"
6102 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
6103 {
6104   DM_Plex *mesh = (DM_Plex*) dm->data;
6105 
6106   PetscFunctionBegin;
6107   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6108   PetscValidPointer(refinementLimit,  2);
6109   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
6110   *refinementLimit = mesh->refinementLimit;
6111   PetscFunctionReturn(0);
6112 }
6113 
6114 #undef __FUNCT__
6115 #define __FUNCT__ "DMPlexGetCellRefiner_Internal"
6116 PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
6117 {
6118   PetscInt       dim, cStart, cEnd, coneSize, cMax;
6119   PetscErrorCode ierr;
6120 
6121   PetscFunctionBegin;
6122   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6123   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6124   if (cEnd <= cStart) {*cellRefiner = 0; PetscFunctionReturn(0);}
6125   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
6126   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
6127   switch (dim) {
6128   case 2:
6129     switch (coneSize) {
6130     case 3:
6131       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
6132       else *cellRefiner = 1; /* Triangular */
6133       break;
6134     case 4:
6135       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
6136       else *cellRefiner = 2; /* Quadrilateral */
6137       break;
6138     default:
6139       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
6140     }
6141     break;
6142   case 3:
6143     switch (coneSize) {
6144     case 4:
6145       if (cMax >= 0) *cellRefiner = 7; /* Hybrid */
6146       else *cellRefiner = 5; /* Tetrahedral */
6147       break;
6148     case 6:
6149       if (cMax >= 0) *cellRefiner = 8; /* Hybrid */
6150       else *cellRefiner = 6; /* hexahedral */
6151       break;
6152     default:
6153       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
6154     }
6155     break;
6156   default:
6157     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
6158   }
6159   PetscFunctionReturn(0);
6160 }
6161