xref: /petsc/src/dm/impls/plex/plexrefine.c (revision 6187e55b7be868de3dab288e5aecadaea4c1b258)
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 = depth < 0 ? 0 : depthSize[depth];
11   if (fStart) *fStart = depth < 0 ? 0 : depthSize[depth] + depthSize[0];
12   if (eStart) *eStart = depth < 0 ? 0 : 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 = depth < 0 ? 0 : depthSize[depth];
22   if (vEnd) *vEnd = depth < 0 ? 0 : depthSize[depth] + depthSize[0];
23   if (fEnd) *fEnd = depth < 0 ? 0 : depthSize[depth] + depthSize[0] + depthSize[depth-1];
24   if (eEnd) *eEnd = depth < 0 ? 0 : 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     /*
42      2
43      |\
44      | \
45      |  \
46      |   \
47      | C  \
48      |     \
49      |      \
50      2---1---1
51      |\  D  / \
52      | 2   0   \
53      |A \ /  B  \
54      0---0-------1
55      */
56     dim = 2;
57     if (numSubcells) *numSubcells = 4;
58     if (v0) {
59       ierr = PetscMalloc3(4*dim,&v,4*dim*dim,&j,4*dim*dim,&invj);CHKERRQ(ierr);
60       /* A */
61       v[0+0] = -1.0; v[0+1] = -1.0;
62       j[0+0] =  0.5; j[0+1] =  0.0;
63       j[0+2] =  0.0; j[0+3] =  0.5;
64       /* B */
65       v[2+0] =  0.0; v[2+1] = -1.0;
66       j[4+0] =  0.5; j[4+1] =  0.0;
67       j[4+2] =  0.0; j[4+3] =  0.5;
68       /* C */
69       v[4+0] = -1.0; v[4+1] =  0.0;
70       j[8+0] =  0.5; j[8+1] =  0.0;
71       j[8+2] =  0.0; j[8+3] =  0.5;
72       /* D */
73       v[6+0]  =  0.0; v[6+1]  = -1.0;
74       j[12+0] =  0.0; j[12+1] = -0.5;
75       j[12+2] =  0.5; j[12+3] =  0.5;
76       for (s = 0; s < 4; ++s) {
77         DMPlex_Det2D_Internal(&detJ, &j[s*dim*dim]);
78         DMPlex_Invert2D_Internal(&invj[s*dim*dim], &j[s*dim*dim], detJ);
79       }
80     }
81     break;
82   case 2:
83     /*
84      3---------2---------2
85      |         |         |
86      |    D    2    C    |
87      |         |         |
88      3----3----0----1----1
89      |         |         |
90      |    A    0    B    |
91      |         |         |
92      0---------0---------1
93      */
94     dim = 2;
95     if (numSubcells) *numSubcells = 4;
96     if (v0) {
97       ierr = PetscMalloc3(4*dim,&v,4*dim*dim,&j,4*dim*dim,&invj);CHKERRQ(ierr);
98       /* A */
99       v[0+0] = -1.0; v[0+1] = -1.0;
100       j[0+0] =  0.5; j[0+1] =  0.0;
101       j[0+2] =  0.0; j[0+3] =  0.5;
102       /* B */
103       v[2+0] =  0.0; v[2+1] = -1.0;
104       j[4+0] =  0.5; j[4+1] =  0.0;
105       j[4+2] =  0.0; j[4+3] =  0.5;
106       /* C */
107       v[4+0] =  0.0; v[4+1] =  0.0;
108       j[8+0] =  0.5; j[8+1] =  0.0;
109       j[8+2] =  0.0; j[8+3] =  0.5;
110       /* D */
111       v[6+0]  = -1.0; v[6+1]  =  0.0;
112       j[12+0] =  0.5; j[12+1] =  0.0;
113       j[12+2] =  0.0; j[12+3] =  0.5;
114       for (s = 0; s < 4; ++s) {
115         DMPlex_Det2D_Internal(&detJ, &j[s*dim*dim]);
116         DMPlex_Invert2D_Internal(&invj[s*dim*dim], &j[s*dim*dim], detJ);
117       }
118     }
119     break;
120   default:
121     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
122   }
123   if (v0) {*v0 = v; *jac = j; *invjac = invj;}
124   PetscFunctionReturn(0);
125 }
126 
127 #undef __FUNCT__
128 #define __FUNCT__ "CellRefinerRestoreAffineTransforms_Internal"
129 PetscErrorCode CellRefinerRestoreAffineTransforms_Internal(CellRefiner refiner, PetscInt *numSubcells, PetscReal *v0[], PetscReal *jac[], PetscReal *invjac[])
130 {
131   PetscErrorCode ierr;
132 
133   PetscFunctionBegin;
134   ierr = PetscFree3(*v0,*jac,*invjac);CHKERRQ(ierr);
135   PetscFunctionReturn(0);
136 }
137 
138 #undef __FUNCT__
139 #define __FUNCT__ "CellRefinerInCellTest_Internal"
140 /* Should this be here or in the DualSpace somehow? */
141 PetscErrorCode CellRefinerInCellTest_Internal(CellRefiner refiner, const PetscReal point[], PetscBool *inside)
142 {
143   PetscReal sum = 0.0;
144   PetscInt  d;
145 
146   PetscFunctionBegin;
147   *inside = PETSC_TRUE;
148   switch (refiner) {
149   case 0: break;
150   case 1:
151     for (d = 0; d < 2; ++d) {
152       if (point[d] < -1.0) {*inside = PETSC_FALSE; break;}
153       sum += point[d];
154     }
155     if (sum > 0.0) {*inside = PETSC_FALSE; break;}
156     break;
157   case 2:
158     for (d = 0; d < 2; ++d) if ((point[d] < -1.0) || (point[d] > 1.0)) {*inside = PETSC_FALSE; break;}
159     break;
160   default:
161     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
162   }
163   PetscFunctionReturn(0);
164 }
165 
166 #undef __FUNCT__
167 #define __FUNCT__ "CellRefinerGetSizes"
168 static PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
169 {
170   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
171   PetscErrorCode ierr;
172 
173   PetscFunctionBegin;
174   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
175   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
176   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
177   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
178   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
179   switch (refiner) {
180   case 0:
181     break;
182   case 1:
183     /* Simplicial 2D */
184     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
185     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
186     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
187     break;
188   case 3:
189     /* Hybrid Simplicial 2D */
190     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
191     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
192     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
193     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 */
194     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
195     break;
196   case 2:
197     /* Hex 2D */
198     depthSize[0] = vEnd - vStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every face and cell */
199     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
200     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
201     break;
202   case 4:
203     /* Hybrid Hex 2D */
204     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
205     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
206     /* Quadrilateral */
207     depthSize[0] = vEnd - vStart + fMax - fStart + cMax - cStart;                 /* Add a vertex on every face and cell */
208     depthSize[1] = 2*(fMax - fStart) + 4*(cMax - cStart);                         /* Every face is split into 2 faces, and 4 faces are added for each cell */
209     depthSize[2] = 4*(cMax - cStart);                                             /* Every cell split into 4 cells */
210     /* Segment Prisms */
211     depthSize[0] += 0;                                                            /* No hybrid vertices */
212     depthSize[1] +=   (fEnd - fMax)  +   (cEnd - cMax);                           /* Every hybrid face remains and 1 faces is added for each hybrid cell */
213     depthSize[2] += 2*(cEnd - cMax);                                              /* Every hybrid cell split into 2 cells */
214     break;
215   case 5:
216     /* Simplicial 3D */
217     depthSize[0] =    vEnd - vStart  +    eEnd - eStart;                    /* Add a vertex on every edge */
218     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 */
219     depthSize[2] = 4*(fEnd - fStart) + 8*(cEnd - cStart);                   /* Every face split into 4 faces and 8 faces are added for each cell */
220     depthSize[3] = 8*(cEnd - cStart);                                       /* Every cell split into 8 cells */
221     break;
222   case 7:
223     /* Hybrid Simplicial 3D */
224     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
225     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
226     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
227     /* Tetrahedra */
228     depthSize[0]  =    vEnd - vStart  +    eMax - eStart;                    /* Add a vertex on every interior edge */
229     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 */
230     depthSize[2]  = 4*(fMax - fStart) + 8*(cMax - cStart);                   /* Every interior face split into 4 faces, 8 faces added for each interior cell */
231     depthSize[3]  = 8*(cMax - cStart);                                       /* Every interior cell split into 8 cells */
232     /* Triangular Prisms */
233     depthSize[0] += 0;                                                       /* No hybrid vertices */
234     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax);                     /* Every hybrid edge remains, 1 edge for every hybrid face */
235     depthSize[2] += 2*(fEnd - fMax)   + 3*(cEnd - cMax);                     /* Every hybrid face split into 2 faces and 3 faces are added for each hybrid cell */
236     depthSize[3] += 4*(cEnd - cMax);                                         /* Every hybrid cell split into 4 cells */
237     break;
238   case 6:
239     /* Hex 3D */
240     depthSize[0] = vEnd - vStart + eEnd - eStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every edge, face and cell */
241     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 */
242     depthSize[2] = 4*(fEnd - fStart) + 12*(cEnd - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
243     depthSize[3] = 8*(cEnd - cStart);                                             /* Every cell split into 8 cells */
244     break;
245   case 8:
246     /* Hybrid Hex 3D */
247     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
248     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
249     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
250     /* Hexahedra */
251     depthSize[0] = vEnd - vStart + eMax - eStart + fMax - fStart + cMax - cStart; /* Add a vertex on every edge, face and cell */
252     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 */
253     depthSize[2] = 4*(fMax - fStart) + 12*(cMax - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
254     depthSize[3] = 8*(cMax - cStart);                                             /* Every cell split into 8 cells */
255     /* Quadrilateral Prisms */
256     depthSize[0] += 0;                                                            /* No hybrid vertices */
257     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax)   +   (cEnd - cMax);      /* Every hybrid edge remains, 1 edge for every hybrid face and hybrid cell */
258     depthSize[2] += 2*(fEnd - fMax)   + 4*(cEnd - cMax);                          /* Every hybrid face split into 2 faces and 4 faces are added for each hybrid cell */
259     depthSize[3] += 4*(cEnd - cMax);                                              /* Every hybrid cell split into 4 cells */
260     break;
261   default:
262     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
263   }
264   PetscFunctionReturn(0);
265 }
266 
267 /* Return triangle edge for orientation o, if it is r for o == 0 */
268 PETSC_STATIC_INLINE PetscInt GetTriEdge_Static(PetscInt o, PetscInt r) {
269   return (o < 0 ? 2-(o+r) : o+r)%3;
270 }
271 PETSC_STATIC_INLINE PetscInt GetTriEdgeInverse_Static(PetscInt o, PetscInt s) {
272   return (o < 0 ? 2-(o+s) : 3+s-o)%3;
273 }
274 
275 /* Return triangle subface for orientation o, if it is r for o == 0 */
276 PETSC_STATIC_INLINE PetscInt GetTriSubface_Static(PetscInt o, PetscInt r) {
277   return (o < 0 ? 3-(o+r) : o+r)%3;
278 }
279 PETSC_STATIC_INLINE PetscInt GetTriSubfaceInverse_Static(PetscInt o, PetscInt s) {
280   return (o < 0 ? 3-(o+s) : 3+s-o)%3;
281 }
282 
283 /* I HAVE NO IDEA: Return ??? for orientation o, if it is r for o == 0 */
284 PETSC_STATIC_INLINE PetscInt GetTetSomething_Static(PetscInt o, PetscInt r) {
285   return (o < 0 ? 1-(o+r) : o+r)%3;
286 }
287 PETSC_STATIC_INLINE PetscInt GetTetSomethingInverse_Static(PetscInt o, PetscInt s) {
288   return (o < 0 ? 1-(o+s) : 3+s-o)%3;
289 }
290 
291 
292 /* Return quad edge for orientation o, if it is r for o == 0 */
293 PETSC_STATIC_INLINE PetscInt GetQuadEdge_Static(PetscInt o, PetscInt r) {
294   return (o < 0 ? 3-(o+r) : o+r)%4;
295 }
296 PETSC_STATIC_INLINE PetscInt GetQuadEdgeInverse_Static(PetscInt o, PetscInt s) {
297   return (o < 0 ? 3-(o+s) : 4+s-o)%4;
298 }
299 
300 /* Return quad subface for orientation o, if it is r for o == 0 */
301 PETSC_STATIC_INLINE PetscInt GetQuadSubface_Static(PetscInt o, PetscInt r) {
302   return (o < 0 ? 4-(o+r) : o+r)%4;
303 }
304 PETSC_STATIC_INLINE PetscInt GetQuadSubfaceInverse_Static(PetscInt o, PetscInt s) {
305   return (o < 0 ? 4-(o+s) : 4+s-o)%4;
306 }
307 
308 #undef __FUNCT__
309 #define __FUNCT__ "CellRefinerSetConeSizes"
310 static PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
311 {
312   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, e, r;
313   PetscErrorCode ierr;
314 
315   PetscFunctionBegin;
316   if (!refiner) PetscFunctionReturn(0);
317   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
318   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
319   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
320   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
321   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
322   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
323   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
324   switch (refiner) {
325   case 1:
326     /* Simplicial 2D */
327     /* All cells have 3 faces */
328     for (c = cStart; c < cEnd; ++c) {
329       for (r = 0; r < 4; ++r) {
330         const PetscInt newp = (c - cStart)*4 + r;
331 
332         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
333       }
334     }
335     /* Split faces have 2 vertices and the same cells as the parent */
336     for (f = fStart; f < fEnd; ++f) {
337       for (r = 0; r < 2; ++r) {
338         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
339         PetscInt       size;
340 
341         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
342         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
343         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
344       }
345     }
346     /* Interior faces have 2 vertices and 2 cells */
347     for (c = cStart; c < cEnd; ++c) {
348       for (r = 0; r < 3; ++r) {
349         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
350 
351         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
352         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
353       }
354     }
355     /* Old vertices have identical supports */
356     for (v = vStart; v < vEnd; ++v) {
357       const PetscInt newp = vStartNew + (v - vStart);
358       PetscInt       size;
359 
360       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
361       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
362     }
363     /* Face vertices have 2 + cells*2 supports */
364     for (f = fStart; f < fEnd; ++f) {
365       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
366       PetscInt       size;
367 
368       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
369       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
370     }
371     break;
372   case 2:
373     /* Hex 2D */
374     /* All cells have 4 faces */
375     for (c = cStart; c < cEnd; ++c) {
376       for (r = 0; r < 4; ++r) {
377         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
378 
379         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
380       }
381     }
382     /* Split faces have 2 vertices and the same cells as the parent */
383     for (f = fStart; f < fEnd; ++f) {
384       for (r = 0; r < 2; ++r) {
385         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
386         PetscInt       size;
387 
388         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
389         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
390         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
391       }
392     }
393     /* Interior faces have 2 vertices and 2 cells */
394     for (c = cStart; c < cEnd; ++c) {
395       for (r = 0; r < 4; ++r) {
396         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
397 
398         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
399         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
400       }
401     }
402     /* Old vertices have identical supports */
403     for (v = vStart; v < vEnd; ++v) {
404       const PetscInt newp = vStartNew + (v - vStart);
405       PetscInt       size;
406 
407       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
408       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
409     }
410     /* Face vertices have 2 + cells supports */
411     for (f = fStart; f < fEnd; ++f) {
412       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
413       PetscInt       size;
414 
415       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
416       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
417     }
418     /* Cell vertices have 4 supports */
419     for (c = cStart; c < cEnd; ++c) {
420       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
421 
422       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
423     }
424     break;
425   case 3:
426     /* Hybrid Simplicial 2D */
427     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
428     cMax = PetscMin(cEnd, cMax);
429     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
430     fMax = PetscMin(fEnd, fMax);
431     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
432     /* Interior cells have 3 faces */
433     for (c = cStart; c < cMax; ++c) {
434       for (r = 0; r < 4; ++r) {
435         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
436 
437         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
438       }
439     }
440     /* Hybrid cells have 4 faces */
441     for (c = cMax; c < cEnd; ++c) {
442       for (r = 0; r < 2; ++r) {
443         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
444 
445         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
446       }
447     }
448     /* Interior split faces have 2 vertices and the same cells as the parent */
449     for (f = fStart; f < fMax; ++f) {
450       for (r = 0; r < 2; ++r) {
451         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
452         PetscInt       size;
453 
454         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
455         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
456         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
457       }
458     }
459     /* Interior cell faces have 2 vertices and 2 cells */
460     for (c = cStart; c < cMax; ++c) {
461       for (r = 0; r < 3; ++r) {
462         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
463 
464         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
465         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
466       }
467     }
468     /* Hybrid faces have 2 vertices and the same cells */
469     for (f = fMax; f < fEnd; ++f) {
470       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
471       PetscInt       size;
472 
473       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
474       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
475       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
476     }
477     /* Hybrid cell faces have 2 vertices and 2 cells */
478     for (c = cMax; c < cEnd; ++c) {
479       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
480 
481       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
482       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
483     }
484     /* Old vertices have identical supports */
485     for (v = vStart; v < vEnd; ++v) {
486       const PetscInt newp = vStartNew + (v - vStart);
487       PetscInt       size;
488 
489       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
490       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
491     }
492     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
493     for (f = fStart; f < fMax; ++f) {
494       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
495       const PetscInt *support;
496       PetscInt       size, newSize = 2, s;
497 
498       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
499       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
500       for (s = 0; s < size; ++s) {
501         if (support[s] >= cMax) newSize += 1;
502         else newSize += 2;
503       }
504       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
505     }
506     break;
507   case 4:
508     /* Hybrid Hex 2D */
509     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
510     cMax = PetscMin(cEnd, cMax);
511     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
512     fMax = PetscMin(fEnd, fMax);
513     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
514     /* Interior cells have 4 faces */
515     for (c = cStart; c < cMax; ++c) {
516       for (r = 0; r < 4; ++r) {
517         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
518 
519         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
520       }
521     }
522     /* Hybrid cells have 4 faces */
523     for (c = cMax; c < cEnd; ++c) {
524       for (r = 0; r < 2; ++r) {
525         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
526 
527         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
528       }
529     }
530     /* Interior split faces have 2 vertices and the same cells as the parent */
531     for (f = fStart; f < fMax; ++f) {
532       for (r = 0; r < 2; ++r) {
533         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
534         PetscInt       size;
535 
536         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
537         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
538         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
539       }
540     }
541     /* Interior cell faces have 2 vertices and 2 cells */
542     for (c = cStart; c < cMax; ++c) {
543       for (r = 0; r < 4; ++r) {
544         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
545 
546         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
547         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
548       }
549     }
550     /* Hybrid faces have 2 vertices and the same cells */
551     for (f = fMax; f < fEnd; ++f) {
552       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
553       PetscInt       size;
554 
555       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
556       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
557       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
558     }
559     /* Hybrid cell faces have 2 vertices and 2 cells */
560     for (c = cMax; c < cEnd; ++c) {
561       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
562 
563       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
564       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
565     }
566     /* Old vertices have identical supports */
567     for (v = vStart; v < vEnd; ++v) {
568       const PetscInt newp = vStartNew + (v - vStart);
569       PetscInt       size;
570 
571       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
572       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
573     }
574     /* Face vertices have 2 + cells supports */
575     for (f = fStart; f < fMax; ++f) {
576       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
577       PetscInt       size;
578 
579       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
580       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
581     }
582     /* Cell vertices have 4 supports */
583     for (c = cStart; c < cMax; ++c) {
584       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
585 
586       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
587     }
588     break;
589   case 5:
590     /* Simplicial 3D */
591     /* All cells have 4 faces */
592     for (c = cStart; c < cEnd; ++c) {
593       for (r = 0; r < 8; ++r) {
594         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
595 
596         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
597       }
598     }
599     /* Split faces have 3 edges and the same cells as the parent */
600     for (f = fStart; f < fEnd; ++f) {
601       for (r = 0; r < 4; ++r) {
602         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
603         PetscInt       size;
604 
605         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
606         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
607         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
608       }
609     }
610     /* Interior cell faces have 3 edges and 2 cells */
611     for (c = cStart; c < cEnd; ++c) {
612       for (r = 0; r < 8; ++r) {
613         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + r;
614 
615         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
616         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
617       }
618     }
619     /* Split edges have 2 vertices and the same faces */
620     for (e = eStart; e < eEnd; ++e) {
621       for (r = 0; r < 2; ++r) {
622         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
623         PetscInt       size;
624 
625         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
626         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
627         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
628       }
629     }
630     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
631     for (f = fStart; f < fEnd; ++f) {
632       for (r = 0; r < 3; ++r) {
633         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
634         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
635         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;
636 
637         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
638         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
639         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
640         for (s = 0; s < supportSize; ++s) {
641           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
642           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
643           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
644           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
645           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
646           er = GetTetSomethingInverse_Static(ornt[c], r);
647           if (er == eint[c]) {
648             intFaces += 1;
649           } else {
650             intFaces += 2;
651           }
652         }
653         ierr = DMPlexSetSupportSize(rdm, newp, 2+intFaces);CHKERRQ(ierr);
654       }
655     }
656     /* Interior cell edges have 2 vertices and 4 faces */
657     for (c = cStart; c < cEnd; ++c) {
658       const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
659 
660       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
661       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
662     }
663     /* Old vertices have identical supports */
664     for (v = vStart; v < vEnd; ++v) {
665       const PetscInt newp = vStartNew + (v - vStart);
666       PetscInt       size;
667 
668       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
669       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
670     }
671     /* Edge vertices have 2 + faces*2 + cells*0/1 supports */
672     for (e = eStart; e < eEnd; ++e) {
673       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
674       PetscInt       size, *star = NULL, starSize, s, cellSize = 0;
675 
676       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
677       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
678       for (s = 0; s < starSize*2; s += 2) {
679         const PetscInt *cone, *ornt;
680         PetscInt        e01, e23;
681 
682         if ((star[s] >= cStart) && (star[s] < cEnd)) {
683           /* Check edge 0-1 */
684           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
685           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
686           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
687           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
688           /* Check edge 2-3 */
689           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
690           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
691           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
692           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
693           if ((e01 == e) || (e23 == e)) ++cellSize;
694         }
695       }
696       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
697       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2 + cellSize);CHKERRQ(ierr);
698     }
699     break;
700   case 7:
701     /* Hybrid Simplicial 3D */
702     ierr = DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 8*(cMax - cStart),
703                                  eStartNew + 2*(eMax - eStart) + 3*(fMax - fStart) + (cMax - cStart), PETSC_DETERMINE);CHKERRQ(ierr);
704     /* Interior cells have 4 faces */
705     for (c = cStart; c < cMax; ++c) {
706       for (r = 0; r < 8; ++r) {
707         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
708 
709         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
710       }
711     }
712     /* Hybrid cells have 5 faces */
713     for (c = cMax; c < cEnd; ++c) {
714       for (r = 0; r < 4; ++r) {
715         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;
716 
717         ierr = DMPlexSetConeSize(rdm, newp, 5);CHKERRQ(ierr);
718       }
719     }
720     /* Interior split faces have 3 edges and the same cells as the parent */
721     for (f = fStart; f < fMax; ++f) {
722       for (r = 0; r < 4; ++r) {
723         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
724         PetscInt       size;
725 
726         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
727         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
728         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
729       }
730     }
731     /* Interior cell faces have 3 edges and 2 cells */
732     for (c = cStart; c < cMax; ++c) {
733       for (r = 0; r < 8; ++r) {
734         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + r;
735 
736         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
737         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
738       }
739     }
740     /* Hybrid split faces have 4 edges and the same cells as the parent */
741     for (f = fMax; f < fEnd; ++f) {
742       for (r = 0; r < 2; ++r) {
743         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
744         PetscInt       size;
745 
746         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
747         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
748         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
749       }
750     }
751     /* Hybrid cells faces have 4 edges and 2 cells */
752     for (c = cMax; c < cEnd; ++c) {
753       for (r = 0; r < 3; ++r) {
754         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + r;
755 
756         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
757         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
758       }
759     }
760     /* Interior split edges have 2 vertices and the same faces */
761     for (e = eStart; e < eMax; ++e) {
762       for (r = 0; r < 2; ++r) {
763         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
764         PetscInt       size;
765 
766         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
767         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
768         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
769       }
770     }
771     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
772     for (f = fStart; f < fMax; ++f) {
773       for (r = 0; r < 3; ++r) {
774         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
775         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
776         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;
777 
778         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
779         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
780         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
781         for (s = 0; s < supportSize; ++s) {
782           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
783           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
784           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
785           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
786           if (support[s] < cMax) {
787             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
788             er = GetTetSomethingInverse_Static(ornt[c], r);
789             if (er == eint[c]) {
790               intFaces += 1;
791             } else {
792               intFaces += 2;
793             }
794           } else {
795             intFaces += 1;
796           }
797         }
798         ierr = DMPlexSetSupportSize(rdm, newp, 2+intFaces);CHKERRQ(ierr);
799       }
800     }
801     /* Interior cell edges have 2 vertices and 4 faces */
802     for (c = cStart; c < cMax; ++c) {
803       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
804 
805       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
806       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
807     }
808     /* Hybrid edges have 2 vertices and the same faces */
809     for (e = eMax; e < eEnd; ++e) {
810       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
811       PetscInt       size;
812 
813       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
814       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
815       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
816     }
817     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
818     for (f = fMax; f < fEnd; ++f) {
819       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
820       PetscInt       size;
821 
822       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
823       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
824       ierr = DMPlexSetSupportSize(rdm, newp, 2+2*size);CHKERRQ(ierr);
825     }
826     /* Interior vertices have identical supports */
827     for (v = vStart; v < vEnd; ++v) {
828       const PetscInt newp = vStartNew + (v - vStart);
829       PetscInt       size;
830 
831       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
832       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
833     }
834     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
835     for (e = eStart; e < eMax; ++e) {
836       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
837       const PetscInt *support;
838       PetscInt        size, *star = NULL, starSize, s, faceSize = 0, cellSize = 0;
839 
840       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
841       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
842       for (s = 0; s < size; ++s) {
843         if (support[s] < fMax) faceSize += 2;
844         else                   faceSize += 1;
845       }
846       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
847       for (s = 0; s < starSize*2; s += 2) {
848         const PetscInt *cone, *ornt;
849         PetscInt        e01, e23;
850 
851         if ((star[s] >= cStart) && (star[s] < cMax)) {
852           /* Check edge 0-1 */
853           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
854           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
855           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
856           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
857           /* Check edge 2-3 */
858           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
859           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
860           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
861           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
862           if ((e01 == e) || (e23 == e)) ++cellSize;
863         }
864       }
865       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
866       ierr = DMPlexSetSupportSize(rdm, newp, 2 + faceSize + cellSize);CHKERRQ(ierr);
867     }
868     break;
869   case 6:
870     /* Hex 3D */
871     /* All cells have 6 faces */
872     for (c = cStart; c < cEnd; ++c) {
873       for (r = 0; r < 8; ++r) {
874         const PetscInt newp = (c - cStart)*8 + r;
875 
876         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
877       }
878     }
879     /* Split faces have 4 edges and the same cells as the parent */
880     for (f = fStart; f < fEnd; ++f) {
881       for (r = 0; r < 4; ++r) {
882         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
883         PetscInt       size;
884 
885         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
886         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
887         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
888       }
889     }
890     /* Interior faces have 4 edges and 2 cells */
891     for (c = cStart; c < cEnd; ++c) {
892       for (r = 0; r < 12; ++r) {
893         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
894 
895         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
896         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
897       }
898     }
899     /* Split edges have 2 vertices and the same faces as the parent */
900     for (e = eStart; e < eEnd; ++e) {
901       for (r = 0; r < 2; ++r) {
902         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
903         PetscInt       size;
904 
905         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
906         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
907         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
908       }
909     }
910     /* Face edges have 2 vertices and 2+cells faces */
911     for (f = fStart; f < fEnd; ++f) {
912       for (r = 0; r < 4; ++r) {
913         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
914         PetscInt       size;
915 
916         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
917         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
918         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
919       }
920     }
921     /* Cell edges have 2 vertices and 4 faces */
922     for (c = cStart; c < cEnd; ++c) {
923       for (r = 0; r < 6; ++r) {
924         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
925 
926         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
927         ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
928       }
929     }
930     /* Old vertices have identical supports */
931     for (v = vStart; v < vEnd; ++v) {
932       const PetscInt newp = vStartNew + (v - vStart);
933       PetscInt       size;
934 
935       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
936       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
937     }
938     /* Edge vertices have 2 + faces supports */
939     for (e = eStart; e < eEnd; ++e) {
940       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
941       PetscInt       size;
942 
943       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
944       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
945     }
946     /* Face vertices have 4 + cells supports */
947     for (f = fStart; f < fEnd; ++f) {
948       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
949       PetscInt       size;
950 
951       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
952       ierr = DMPlexSetSupportSize(rdm, newp, 4 + size);CHKERRQ(ierr);
953     }
954     /* Cell vertices have 6 supports */
955     for (c = cStart; c < cEnd; ++c) {
956       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
957 
958       ierr = DMPlexSetSupportSize(rdm, newp, 6);CHKERRQ(ierr);
959     }
960     break;
961   case 8:
962     /* Hybrid Hex 3D */
963     ierr = DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 12*(cMax - cStart),
964                                  eStartNew + 2*(eMax - eStart) + 4*(fMax - fStart) + 6*(cMax - cStart), PETSC_DETERMINE);CHKERRQ(ierr);
965     /* Interior cells have 6 faces */
966     for (c = cStart; c < cMax; ++c) {
967       for (r = 0; r < 8; ++r) {
968         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
969 
970         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
971       }
972     }
973     /* Hybrid cells have 6 faces */
974     for (c = cMax; c < cEnd; ++c) {
975       for (r = 0; r < 4; ++r) {
976         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;
977 
978         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
979       }
980     }
981     /* Interior split faces have 4 edges and the same cells as the parent */
982     for (f = fStart; f < fMax; ++f) {
983       for (r = 0; r < 4; ++r) {
984         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
985         PetscInt       size;
986 
987         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
988         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
989         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
990       }
991     }
992     /* Interior cell faces have 4 edges and 2 cells */
993     for (c = cStart; c < cMax; ++c) {
994       for (r = 0; r < 12; ++r) {
995         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
996 
997         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
998         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
999       }
1000     }
1001     /* Hybrid split faces have 4 edges and the same cells as the parent */
1002     for (f = fMax; f < fEnd; ++f) {
1003       for (r = 0; r < 2; ++r) {
1004         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
1005         PetscInt       size;
1006 
1007         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1008         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1009         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1010       }
1011     }
1012     /* Hybrid cells faces have 4 edges and 2 cells */
1013     for (c = cMax; c < cEnd; ++c) {
1014       for (r = 0; r < 4; ++r) {
1015         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + r;
1016 
1017         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1018         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1019       }
1020     }
1021     /* Interior split edges have 2 vertices and the same faces as the parent */
1022     for (e = eStart; e < eMax; ++e) {
1023       for (r = 0; r < 2; ++r) {
1024         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1025         PetscInt       size;
1026 
1027         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1028         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1029         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1030       }
1031     }
1032     /* Interior face edges have 2 vertices and 2+cells faces */
1033     for (f = fStart; f < fMax; ++f) {
1034       for (r = 0; r < 4; ++r) {
1035         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
1036         PetscInt       size;
1037 
1038         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1039         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1040         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1041       }
1042     }
1043     /* Interior cell edges have 2 vertices and 4 faces */
1044     for (c = cStart; c < cMax; ++c) {
1045       for (r = 0; r < 6; ++r) {
1046         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
1047 
1048         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1049         ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1050       }
1051     }
1052     /* Hybrid edges have 2 vertices and the same faces */
1053     for (e = eMax; e < eEnd; ++e) {
1054       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
1055       PetscInt       size;
1056 
1057       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1058       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1059       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1060     }
1061     /* Hybrid face edges have 2 vertices and 2+cells faces */
1062     for (f = fMax; f < fEnd; ++f) {
1063       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
1064       PetscInt       size;
1065 
1066       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1067       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1068       ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1069     }
1070     /* Hybrid cell edges have 2 vertices and 4 faces */
1071     for (c = cMax; c < cEnd; ++c) {
1072       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
1073 
1074       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1075       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1076     }
1077     /* Interior vertices have identical supports */
1078     for (v = vStart; v < vEnd; ++v) {
1079       const PetscInt newp = vStartNew + (v - vStart);
1080       PetscInt       size;
1081 
1082       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1083       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1084     }
1085     /* Interior edge vertices have 2 + faces supports */
1086     for (e = eStart; e < eMax; ++e) {
1087       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1088       PetscInt       size;
1089 
1090       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1091       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1092     }
1093     /* Interior face vertices have 4 + cells supports */
1094     for (f = fStart; f < fMax; ++f) {
1095       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
1096       PetscInt       size;
1097 
1098       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1099       ierr = DMPlexSetSupportSize(rdm, newp, 4 + size);CHKERRQ(ierr);
1100     }
1101     /* Interior cell vertices have 6 supports */
1102     for (c = cStart; c < cMax; ++c) {
1103       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
1104 
1105       ierr = DMPlexSetSupportSize(rdm, newp, 6);CHKERRQ(ierr);
1106     }
1107     break;
1108   default:
1109     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
1110   }
1111   PetscFunctionReturn(0);
1112 }
1113 
1114 #undef __FUNCT__
1115 #define __FUNCT__ "CellRefinerSetCones"
1116 static PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
1117 {
1118   const PetscInt *faces, cellInd[4] = {0, 1, 2, 3};
1119   PetscInt        cStart,    cEnd,    cMax,    vStart,    vEnd, vMax, fStart,    fEnd,    fMax,    eStart,    eEnd,    eMax;
1120   PetscInt        cStartNew, cEndNew, cMaxNew, vStartNew, vEndNew,    fStartNew, fEndNew, fMaxNew, eStartNew, eEndNew, eMaxNew;
1121   PetscInt        depth, maxSupportSize, *supportRef, c, f, e, v, r, p;
1122   PetscErrorCode  ierr;
1123 
1124   PetscFunctionBegin;
1125   if (!refiner) PetscFunctionReturn(0);
1126   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1127   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
1128   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
1129   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1130   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
1131   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
1132   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
1133   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
1134   switch (refiner) {
1135   case 1:
1136     /* Simplicial 2D */
1137     /*
1138      2
1139      |\
1140      | \
1141      |  \
1142      |   \
1143      | C  \
1144      |     \
1145      |      \
1146      2---1---1
1147      |\  D  / \
1148      | 2   0   \
1149      |A \ /  B  \
1150      0---0-------1
1151      */
1152     /* All cells have 3 faces */
1153     for (c = cStart; c < cEnd; ++c) {
1154       const PetscInt  newp = cStartNew + (c - cStart)*4;
1155       const PetscInt *cone, *ornt;
1156       PetscInt        coneNew[3], orntNew[3];
1157 
1158       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1159       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1160       /* A triangle */
1161       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1162       orntNew[0] = ornt[0];
1163       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1164       orntNew[1] = -2;
1165       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1166       orntNew[2] = ornt[2];
1167       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1168       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1169 #if 1
1170       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);
1171       for (p = 0; p < 3; ++p) {
1172         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);
1173       }
1174 #endif
1175       /* B triangle */
1176       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1177       orntNew[0] = ornt[0];
1178       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1179       orntNew[1] = ornt[1];
1180       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1181       orntNew[2] = -2;
1182       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1183       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1184 #if 1
1185       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);
1186       for (p = 0; p < 3; ++p) {
1187         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);
1188       }
1189 #endif
1190       /* C triangle */
1191       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1192       orntNew[0] = -2;
1193       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1194       orntNew[1] = ornt[1];
1195       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1196       orntNew[2] = ornt[2];
1197       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1198       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1199 #if 1
1200       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);
1201       for (p = 0; p < 3; ++p) {
1202         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);
1203       }
1204 #endif
1205       /* D triangle */
1206       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1207       orntNew[0] = 0;
1208       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1209       orntNew[1] = 0;
1210       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1211       orntNew[2] = 0;
1212       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1213       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1214 #if 1
1215       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);
1216       for (p = 0; p < 3; ++p) {
1217         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);
1218       }
1219 #endif
1220     }
1221     /* Split faces have 2 vertices and the same cells as the parent */
1222     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1223     ierr = PetscMalloc1((2 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
1224     for (f = fStart; f < fEnd; ++f) {
1225       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1226 
1227       for (r = 0; r < 2; ++r) {
1228         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1229         const PetscInt *cone, *ornt, *support;
1230         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1231 
1232         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1233         coneNew[0]       = vStartNew + (cone[0] - vStart);
1234         coneNew[1]       = vStartNew + (cone[1] - vStart);
1235         coneNew[(r+1)%2] = newv;
1236         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1237 #if 1
1238         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1239         for (p = 0; p < 2; ++p) {
1240           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);
1241         }
1242 #endif
1243         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1244         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1245         for (s = 0; s < supportSize; ++s) {
1246           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1247           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1248           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1249           for (c = 0; c < coneSize; ++c) {
1250             if (cone[c] == f) break;
1251           }
1252           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1253         }
1254         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1255 #if 1
1256         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1257         for (p = 0; p < supportSize; ++p) {
1258           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);
1259         }
1260 #endif
1261       }
1262     }
1263     /* Interior faces have 2 vertices and 2 cells */
1264     for (c = cStart; c < cEnd; ++c) {
1265       const PetscInt *cone;
1266 
1267       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1268       for (r = 0; r < 3; ++r) {
1269         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
1270         PetscInt       coneNew[2];
1271         PetscInt       supportNew[2];
1272 
1273         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
1274         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
1275         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1276 #if 1
1277         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1278         for (p = 0; p < 2; ++p) {
1279           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);
1280         }
1281 #endif
1282         supportNew[0] = (c - cStart)*4 + (r+1)%3;
1283         supportNew[1] = (c - cStart)*4 + 3;
1284         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1285 #if 1
1286         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1287         for (p = 0; p < 2; ++p) {
1288           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);
1289         }
1290 #endif
1291       }
1292     }
1293     /* Old vertices have identical supports */
1294     for (v = vStart; v < vEnd; ++v) {
1295       const PetscInt  newp = vStartNew + (v - vStart);
1296       const PetscInt *support, *cone;
1297       PetscInt        size, s;
1298 
1299       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1300       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1301       for (s = 0; s < size; ++s) {
1302         PetscInt r = 0;
1303 
1304         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1305         if (cone[1] == v) r = 1;
1306         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1307       }
1308       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1309 #if 1
1310       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1311       for (p = 0; p < size; ++p) {
1312         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);
1313       }
1314 #endif
1315     }
1316     /* Face vertices have 2 + cells*2 supports */
1317     for (f = fStart; f < fEnd; ++f) {
1318       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1319       const PetscInt *cone, *support;
1320       PetscInt        size, s;
1321 
1322       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1323       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1324       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1325       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1326       for (s = 0; s < size; ++s) {
1327         PetscInt r = 0;
1328 
1329         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1330         if      (cone[1] == f) r = 1;
1331         else if (cone[2] == f) r = 2;
1332         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
1333         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
1334       }
1335       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1336 #if 1
1337       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1338       for (p = 0; p < 2+size*2; ++p) {
1339         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);
1340       }
1341 #endif
1342     }
1343     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1344     break;
1345   case 2:
1346     /* Hex 2D */
1347     /*
1348      3---------2---------2
1349      |         |         |
1350      |    D    2    C    |
1351      |         |         |
1352      3----3----0----1----1
1353      |         |         |
1354      |    A    0    B    |
1355      |         |         |
1356      0---------0---------1
1357      */
1358     /* All cells have 4 faces */
1359     for (c = cStart; c < cEnd; ++c) {
1360       const PetscInt  newp = (c - cStart)*4;
1361       const PetscInt *cone, *ornt;
1362       PetscInt        coneNew[4], orntNew[4];
1363 
1364       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1365       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1366       /* A quad */
1367       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1368       orntNew[0] = ornt[0];
1369       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
1370       orntNew[1] = 0;
1371       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
1372       orntNew[2] = -2;
1373       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
1374       orntNew[3] = ornt[3];
1375       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1376       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1377 #if 1
1378       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);
1379       for (p = 0; p < 4; ++p) {
1380         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);
1381       }
1382 #endif
1383       /* B quad */
1384       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1385       orntNew[0] = ornt[0];
1386       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1387       orntNew[1] = ornt[1];
1388       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
1389       orntNew[2] = 0;
1390       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
1391       orntNew[3] = -2;
1392       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1393       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1394 #if 1
1395       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);
1396       for (p = 0; p < 4; ++p) {
1397         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);
1398       }
1399 #endif
1400       /* C quad */
1401       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
1402       orntNew[0] = -2;
1403       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1404       orntNew[1] = ornt[1];
1405       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1406       orntNew[2] = ornt[2];
1407       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
1408       orntNew[3] = 0;
1409       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1410       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1411 #if 1
1412       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);
1413       for (p = 0; p < 4; ++p) {
1414         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);
1415       }
1416 #endif
1417       /* D quad */
1418       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
1419       orntNew[0] = 0;
1420       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
1421       orntNew[1] = -2;
1422       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1423       orntNew[2] = ornt[2];
1424       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
1425       orntNew[3] = ornt[3];
1426       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1427       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1428 #if 1
1429       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);
1430       for (p = 0; p < 4; ++p) {
1431         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);
1432       }
1433 #endif
1434     }
1435     /* Split faces have 2 vertices and the same cells as the parent */
1436     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1437     ierr = PetscMalloc1((2 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
1438     for (f = fStart; f < fEnd; ++f) {
1439       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1440 
1441       for (r = 0; r < 2; ++r) {
1442         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1443         const PetscInt *cone, *ornt, *support;
1444         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1445 
1446         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1447         coneNew[0]       = vStartNew + (cone[0] - vStart);
1448         coneNew[1]       = vStartNew + (cone[1] - vStart);
1449         coneNew[(r+1)%2] = newv;
1450         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1451 #if 1
1452         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1453         for (p = 0; p < 2; ++p) {
1454           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);
1455         }
1456 #endif
1457         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1458         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1459         for (s = 0; s < supportSize; ++s) {
1460           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1461           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1462           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1463           for (c = 0; c < coneSize; ++c) {
1464             if (cone[c] == f) break;
1465           }
1466           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
1467         }
1468         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1469 #if 1
1470         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1471         for (p = 0; p < supportSize; ++p) {
1472           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);
1473         }
1474 #endif
1475       }
1476     }
1477     /* Interior faces have 2 vertices and 2 cells */
1478     for (c = cStart; c < cEnd; ++c) {
1479       const PetscInt *cone;
1480       PetscInt        coneNew[2], supportNew[2];
1481 
1482       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1483       for (r = 0; r < 4; ++r) {
1484         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
1485 
1486         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
1487         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
1488         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1489 #if 1
1490         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1491         for (p = 0; p < 2; ++p) {
1492           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);
1493         }
1494 #endif
1495         supportNew[0] = (c - cStart)*4 + r;
1496         supportNew[1] = (c - cStart)*4 + (r+1)%4;
1497         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1498 #if 1
1499         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1500         for (p = 0; p < 2; ++p) {
1501           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);
1502         }
1503 #endif
1504       }
1505     }
1506     /* Old vertices have identical supports */
1507     for (v = vStart; v < vEnd; ++v) {
1508       const PetscInt  newp = vStartNew + (v - vStart);
1509       const PetscInt *support, *cone;
1510       PetscInt        size, s;
1511 
1512       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1513       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1514       for (s = 0; s < size; ++s) {
1515         PetscInt r = 0;
1516 
1517         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1518         if (cone[1] == v) r = 1;
1519         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1520       }
1521       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1522 #if 1
1523       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1524       for (p = 0; p < size; ++p) {
1525         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);
1526       }
1527 #endif
1528     }
1529     /* Face vertices have 2 + cells supports */
1530     for (f = fStart; f < fEnd; ++f) {
1531       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1532       const PetscInt *cone, *support;
1533       PetscInt        size, s;
1534 
1535       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1536       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1537       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1538       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1539       for (s = 0; s < size; ++s) {
1540         PetscInt r = 0;
1541 
1542         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1543         if      (cone[1] == f) r = 1;
1544         else if (cone[2] == f) r = 2;
1545         else if (cone[3] == f) r = 3;
1546         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
1547       }
1548       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1549 #if 1
1550       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1551       for (p = 0; p < 2+size; ++p) {
1552         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);
1553       }
1554 #endif
1555     }
1556     /* Cell vertices have 4 supports */
1557     for (c = cStart; c < cEnd; ++c) {
1558       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
1559       PetscInt       supportNew[4];
1560 
1561       for (r = 0; r < 4; ++r) {
1562         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
1563       }
1564       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1565     }
1566     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1567     break;
1568   case 3:
1569     /* Hybrid Simplicial 2D */
1570     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
1571     cMax = PetscMin(cEnd, cMax);
1572     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
1573     fMax = PetscMin(fEnd, fMax);
1574     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);CHKERRQ(ierr);
1575     /* Interior cells have 3 faces */
1576     for (c = cStart; c < cMax; ++c) {
1577       const PetscInt  newp = cStartNew + (c - cStart)*4;
1578       const PetscInt *cone, *ornt;
1579       PetscInt        coneNew[3], orntNew[3];
1580 
1581       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1582       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1583       /* A triangle */
1584       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1585       orntNew[0] = ornt[0];
1586       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
1587       orntNew[1] = -2;
1588       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1589       orntNew[2] = ornt[2];
1590       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1591       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1592 #if 1
1593       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+0, cStartNew, cMaxNew);
1594       for (p = 0; p < 3; ++p) {
1595         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
1596       }
1597 #endif
1598       /* B triangle */
1599       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1600       orntNew[0] = ornt[0];
1601       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1602       orntNew[1] = ornt[1];
1603       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
1604       orntNew[2] = -2;
1605       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1606       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1607 #if 1
1608       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+1, cStartNew, cMaxNew);
1609       for (p = 0; p < 3; ++p) {
1610         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
1611       }
1612 #endif
1613       /* C triangle */
1614       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
1615       orntNew[0] = -2;
1616       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1617       orntNew[1] = ornt[1];
1618       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1619       orntNew[2] = ornt[2];
1620       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1621       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1622 #if 1
1623       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+2, cStartNew, cMaxNew);
1624       for (p = 0; p < 3; ++p) {
1625         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
1626       }
1627 #endif
1628       /* D triangle */
1629       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
1630       orntNew[0] = 0;
1631       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
1632       orntNew[1] = 0;
1633       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
1634       orntNew[2] = 0;
1635       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1636       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1637 #if 1
1638       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+3, cStartNew, cMaxNew);
1639       for (p = 0; p < 3; ++p) {
1640         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
1641       }
1642 #endif
1643     }
1644     /*
1645      2----3----3
1646      |         |
1647      |    B    |
1648      |         |
1649      0----4--- 1
1650      |         |
1651      |    A    |
1652      |         |
1653      0----2----1
1654      */
1655     /* Hybrid cells have 4 faces */
1656     for (c = cMax; c < cEnd; ++c) {
1657       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
1658       const PetscInt *cone, *ornt;
1659       PetscInt        coneNew[4], orntNew[4], r;
1660 
1661       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1662       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1663       r    = (ornt[0] < 0 ? 1 : 0);
1664       /* A quad */
1665       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + r;
1666       orntNew[0]   = ornt[0];
1667       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + r;
1668       orntNew[1]   = ornt[1];
1669       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2+r] - fMax);
1670       orntNew[2+r] = 0;
1671       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
1672       orntNew[3-r] = 0;
1673       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1674       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1675 #if 1
1676       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);
1677       for (p = 0; p < 4; ++p) {
1678         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);
1679       }
1680 #endif
1681       /* B quad */
1682       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + 1-r;
1683       orntNew[0]   = ornt[0];
1684       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + 1-r;
1685       orntNew[1]   = ornt[1];
1686       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
1687       orntNew[2+r] = 0;
1688       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3-r] - fMax);
1689       orntNew[3-r] = 0;
1690       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1691       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1692 #if 1
1693       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);
1694       for (p = 0; p < 4; ++p) {
1695         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);
1696       }
1697 #endif
1698     }
1699     /* Interior split faces have 2 vertices and the same cells as the parent */
1700     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1701     ierr = PetscMalloc1((2 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
1702     for (f = fStart; f < fMax; ++f) {
1703       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1704 
1705       for (r = 0; r < 2; ++r) {
1706         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1707         const PetscInt *cone, *ornt, *support;
1708         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1709 
1710         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1711         coneNew[0]       = vStartNew + (cone[0] - vStart);
1712         coneNew[1]       = vStartNew + (cone[1] - vStart);
1713         coneNew[(r+1)%2] = newv;
1714         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1715 #if 1
1716         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1717         for (p = 0; p < 2; ++p) {
1718           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);
1719         }
1720 #endif
1721         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1722         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1723         for (s = 0; s < supportSize; ++s) {
1724           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1725           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1726           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1727           for (c = 0; c < coneSize; ++c) if (cone[c] == f) break;
1728           if (support[s] >= cMax) {
1729             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[c] < 0 ? 1-r : r);
1730           } else {
1731             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1732           }
1733         }
1734         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1735 #if 1
1736         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1737         for (p = 0; p < supportSize; ++p) {
1738           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);
1739         }
1740 #endif
1741       }
1742     }
1743     /* Interior cell faces have 2 vertices and 2 cells */
1744     for (c = cStart; c < cMax; ++c) {
1745       const PetscInt *cone;
1746 
1747       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1748       for (r = 0; r < 3; ++r) {
1749         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
1750         PetscInt       coneNew[2];
1751         PetscInt       supportNew[2];
1752 
1753         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
1754         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
1755         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1756 #if 1
1757         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1758         for (p = 0; p < 2; ++p) {
1759           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);
1760         }
1761 #endif
1762         supportNew[0] = (c - cStart)*4 + (r+1)%3;
1763         supportNew[1] = (c - cStart)*4 + 3;
1764         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1765 #if 1
1766         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1767         for (p = 0; p < 2; ++p) {
1768           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);
1769         }
1770 #endif
1771       }
1772     }
1773     /* Interior hybrid faces have 2 vertices and the same cells */
1774     for (f = fMax; f < fEnd; ++f) {
1775       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
1776       const PetscInt *cone, *ornt;
1777       const PetscInt *support;
1778       PetscInt        coneNew[2];
1779       PetscInt        supportNew[2];
1780       PetscInt        size, s, r;
1781 
1782       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1783       coneNew[0] = vStartNew + (cone[0] - vStart);
1784       coneNew[1] = vStartNew + (cone[1] - vStart);
1785       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1786 #if 1
1787       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1788       for (p = 0; p < 2; ++p) {
1789         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);
1790       }
1791 #endif
1792       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1793       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1794       for (s = 0; s < size; ++s) {
1795         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1796         ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1797         for (r = 0; r < 2; ++r) {
1798           if (cone[r+2] == f) break;
1799         }
1800         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[0] < 0 ? 1-r : r);
1801       }
1802       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1803 #if 1
1804       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1805       for (p = 0; p < size; ++p) {
1806         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);
1807       }
1808 #endif
1809     }
1810     /* Cell hybrid faces have 2 vertices and 2 cells */
1811     for (c = cMax; c < cEnd; ++c) {
1812       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
1813       const PetscInt *cone;
1814       PetscInt        coneNew[2];
1815       PetscInt        supportNew[2];
1816 
1817       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1818       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
1819       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
1820       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1821 #if 1
1822       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1823       for (p = 0; p < 2; ++p) {
1824         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);
1825       }
1826 #endif
1827       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
1828       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
1829       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1830 #if 1
1831       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1832       for (p = 0; p < 2; ++p) {
1833         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);
1834       }
1835 #endif
1836     }
1837     /* Old vertices have identical supports */
1838     for (v = vStart; v < vEnd; ++v) {
1839       const PetscInt  newp = vStartNew + (v - vStart);
1840       const PetscInt *support, *cone;
1841       PetscInt        size, s;
1842 
1843       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1844       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1845       for (s = 0; s < size; ++s) {
1846         if (support[s] >= fMax) {
1847           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
1848         } else {
1849           PetscInt r = 0;
1850 
1851           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1852           if (cone[1] == v) r = 1;
1853           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1854         }
1855       }
1856       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1857 #if 1
1858       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1859       for (p = 0; p < size; ++p) {
1860         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);
1861       }
1862 #endif
1863     }
1864     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
1865     for (f = fStart; f < fMax; ++f) {
1866       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1867       const PetscInt *cone, *support;
1868       PetscInt        size, newSize = 2, s;
1869 
1870       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1871       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1872       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1873       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1874       for (s = 0; s < size; ++s) {
1875         PetscInt r = 0;
1876 
1877         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1878         if (support[s] >= cMax) {
1879           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
1880 
1881           newSize += 1;
1882         } else {
1883           if      (cone[1] == f) r = 1;
1884           else if (cone[2] == f) r = 2;
1885           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
1886           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
1887 
1888           newSize += 2;
1889         }
1890       }
1891       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1892 #if 1
1893       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1894       for (p = 0; p < newSize; ++p) {
1895         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);
1896       }
1897 #endif
1898     }
1899     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1900     break;
1901   case 4:
1902     /* Hybrid Hex 2D */
1903     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
1904     cMax = PetscMin(cEnd, cMax);
1905     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
1906     fMax = PetscMin(fEnd, fMax);
1907     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);CHKERRQ(ierr);
1908     /* Interior cells have 4 faces */
1909     for (c = cStart; c < cMax; ++c) {
1910       const PetscInt  newp = cStartNew + (c - cStart)*4;
1911       const PetscInt *cone, *ornt;
1912       PetscInt        coneNew[4], orntNew[4];
1913 
1914       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1915       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1916       /* A quad */
1917       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1918       orntNew[0] = ornt[0];
1919       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
1920       orntNew[1] = 0;
1921       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
1922       orntNew[2] = -2;
1923       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
1924       orntNew[3] = ornt[3];
1925       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1926       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1927 #if 1
1928       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+0, cStartNew, cMaxNew);
1929       for (p = 0; p < 4; ++p) {
1930         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
1931       }
1932 #endif
1933       /* B quad */
1934       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1935       orntNew[0] = ornt[0];
1936       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1937       orntNew[1] = ornt[1];
1938       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
1939       orntNew[2] = 0;
1940       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
1941       orntNew[3] = -2;
1942       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1943       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1944 #if 1
1945       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+1, cStartNew, cMaxNew);
1946       for (p = 0; p < 4; ++p) {
1947         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
1948       }
1949 #endif
1950       /* C quad */
1951       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
1952       orntNew[0] = -2;
1953       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1954       orntNew[1] = ornt[1];
1955       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1956       orntNew[2] = ornt[2];
1957       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
1958       orntNew[3] = 0;
1959       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1960       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1961 #if 1
1962       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+2, cStartNew, cMaxNew);
1963       for (p = 0; p < 4; ++p) {
1964         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
1965       }
1966 #endif
1967       /* D quad */
1968       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
1969       orntNew[0] = 0;
1970       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
1971       orntNew[1] = -2;
1972       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1973       orntNew[2] = ornt[2];
1974       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
1975       orntNew[3] = ornt[3];
1976       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1977       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1978 #if 1
1979       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+3, cStartNew, cMaxNew);
1980       for (p = 0; p < 4; ++p) {
1981         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
1982       }
1983 #endif
1984     }
1985     /*
1986      2----3----3
1987      |         |
1988      |    B    |
1989      |         |
1990      0----4--- 1
1991      |         |
1992      |    A    |
1993      |         |
1994      0----2----1
1995      */
1996     /* Hybrid cells have 4 faces */
1997     for (c = cMax; c < cEnd; ++c) {
1998       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
1999       const PetscInt *cone, *ornt;
2000       PetscInt        coneNew[4], orntNew[4];
2001 
2002       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2003       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2004       /* A quad */
2005       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2006       orntNew[0] = ornt[0];
2007       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2008       orntNew[1] = ornt[1];
2009       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[2] - fMax);
2010       orntNew[2] = 0;
2011       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
2012       orntNew[3] = 0;
2013       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2014       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2015 #if 1
2016       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);
2017       for (p = 0; p < 4; ++p) {
2018         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);
2019       }
2020 #endif
2021       /* B quad */
2022       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2023       orntNew[0] = ornt[0];
2024       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2025       orntNew[1] = ornt[1];
2026       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
2027       orntNew[2] = 0;
2028       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[3] - fMax);
2029       orntNew[3] = 0;
2030       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2031       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2032 #if 1
2033       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);
2034       for (p = 0; p < 4; ++p) {
2035         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);
2036       }
2037 #endif
2038     }
2039     /* Interior split faces have 2 vertices and the same cells as the parent */
2040     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2041     ierr = PetscMalloc1((2 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
2042     for (f = fStart; f < fMax; ++f) {
2043       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
2044 
2045       for (r = 0; r < 2; ++r) {
2046         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2047         const PetscInt *cone, *ornt, *support;
2048         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2049 
2050         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2051         coneNew[0]       = vStartNew + (cone[0] - vStart);
2052         coneNew[1]       = vStartNew + (cone[1] - vStart);
2053         coneNew[(r+1)%2] = newv;
2054         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2055 #if 1
2056         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2057         for (p = 0; p < 2; ++p) {
2058           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);
2059         }
2060 #endif
2061         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2062         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2063         for (s = 0; s < supportSize; ++s) {
2064           if (support[s] >= cMax) {
2065             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
2066           } else {
2067             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2068             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2069             ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2070             for (c = 0; c < coneSize; ++c) {
2071               if (cone[c] == f) break;
2072             }
2073             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
2074           }
2075         }
2076         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2077 #if 1
2078         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2079         for (p = 0; p < supportSize; ++p) {
2080           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);
2081         }
2082 #endif
2083       }
2084     }
2085     /* Interior cell faces have 2 vertices and 2 cells */
2086     for (c = cStart; c < cMax; ++c) {
2087       const PetscInt *cone;
2088 
2089       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2090       for (r = 0; r < 4; ++r) {
2091         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
2092         PetscInt       coneNew[2], supportNew[2];
2093 
2094         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2095         coneNew[1] = vStartNew + (vEnd - vStart) + (fMax    - fStart) + (c - cStart);
2096         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2097 #if 1
2098         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2099         for (p = 0; p < 2; ++p) {
2100           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);
2101         }
2102 #endif
2103         supportNew[0] = (c - cStart)*4 + r;
2104         supportNew[1] = (c - cStart)*4 + (r+1)%4;
2105         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2106 #if 1
2107         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2108         for (p = 0; p < 2; ++p) {
2109           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);
2110         }
2111 #endif
2112       }
2113     }
2114     /* Hybrid faces have 2 vertices and the same cells */
2115     for (f = fMax; f < fEnd; ++f) {
2116       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
2117       const PetscInt *cone, *support;
2118       PetscInt        coneNew[2], supportNew[2];
2119       PetscInt        size, s, r;
2120 
2121       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2122       coneNew[0] = vStartNew + (cone[0] - vStart);
2123       coneNew[1] = vStartNew + (cone[1] - vStart);
2124       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2125 #if 1
2126       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2127       for (p = 0; p < 2; ++p) {
2128         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);
2129       }
2130 #endif
2131       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2132       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2133       for (s = 0; s < size; ++s) {
2134         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2135         for (r = 0; r < 2; ++r) {
2136           if (cone[r+2] == f) break;
2137         }
2138         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
2139       }
2140       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2141 #if 1
2142       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2143       for (p = 0; p < size; ++p) {
2144         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);
2145       }
2146 #endif
2147     }
2148     /* Cell hybrid faces have 2 vertices and 2 cells */
2149     for (c = cMax; c < cEnd; ++c) {
2150       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
2151       const PetscInt *cone;
2152       PetscInt        coneNew[2], supportNew[2];
2153 
2154       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2155       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
2156       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
2157       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2158 #if 1
2159       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2160       for (p = 0; p < 2; ++p) {
2161         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);
2162       }
2163 #endif
2164       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
2165       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
2166       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2167 #if 1
2168       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2169       for (p = 0; p < 2; ++p) {
2170         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);
2171       }
2172 #endif
2173     }
2174     /* Old vertices have identical supports */
2175     for (v = vStart; v < vEnd; ++v) {
2176       const PetscInt  newp = vStartNew + (v - vStart);
2177       const PetscInt *support, *cone;
2178       PetscInt        size, s;
2179 
2180       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2181       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2182       for (s = 0; s < size; ++s) {
2183         if (support[s] >= fMax) {
2184           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (support[s] - fMax);
2185         } else {
2186           PetscInt r = 0;
2187 
2188           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2189           if (cone[1] == v) r = 1;
2190           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2191         }
2192       }
2193       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2194 #if 1
2195       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2196       for (p = 0; p < size; ++p) {
2197         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);
2198       }
2199 #endif
2200     }
2201     /* Face vertices have 2 + cells supports */
2202     for (f = fStart; f < fMax; ++f) {
2203       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2204       const PetscInt *cone, *support;
2205       PetscInt        size, s;
2206 
2207       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2208       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2209       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2210       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2211       for (s = 0; s < size; ++s) {
2212         PetscInt r = 0;
2213 
2214         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2215         if (support[s] >= cMax) {
2216           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (support[s] - cMax);
2217         } else {
2218           if      (cone[1] == f) r = 1;
2219           else if (cone[2] == f) r = 2;
2220           else if (cone[3] == f) r = 3;
2221           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*4 + r;
2222         }
2223       }
2224       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2225 #if 1
2226       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2227       for (p = 0; p < 2+size; ++p) {
2228         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);
2229       }
2230 #endif
2231     }
2232     /* Cell vertices have 4 supports */
2233     for (c = cStart; c < cMax; ++c) {
2234       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
2235       PetscInt       supportNew[4];
2236 
2237       for (r = 0; r < 4; ++r) {
2238         supportNew[r] = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
2239       }
2240       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2241     }
2242     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2243     break;
2244   case 5:
2245     /* Simplicial 3D */
2246     /* All cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
2247     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
2248     for (c = cStart; c < cEnd; ++c) {
2249       const PetscInt  newp = cStartNew + (c - cStart)*8;
2250       const PetscInt *cone, *ornt;
2251       PetscInt        coneNew[4], orntNew[4];
2252 
2253       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2254       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2255       /* A tetrahedron: {0, a, c, d} */
2256       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
2257       orntNew[0] = ornt[0];
2258       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
2259       orntNew[1] = ornt[1];
2260       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
2261       orntNew[2] = ornt[2];
2262       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
2263       orntNew[3] = 0;
2264       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2265       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2266 #if 1
2267       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);
2268       for (p = 0; p < 4; ++p) {
2269         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);
2270       }
2271 #endif
2272       /* B tetrahedron: {a, 1, b, e} */
2273       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
2274       orntNew[0] = ornt[0];
2275       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
2276       orntNew[1] = ornt[1];
2277       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
2278       orntNew[2] = 0;
2279       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
2280       orntNew[3] = ornt[3];
2281       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2282       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2283 #if 1
2284       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);
2285       for (p = 0; p < 4; ++p) {
2286         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);
2287       }
2288 #endif
2289       /* C tetrahedron: {c, b, 2, f} */
2290       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
2291       orntNew[0] = ornt[0];
2292       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
2293       orntNew[1] = 0;
2294       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
2295       orntNew[2] = ornt[2];
2296       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
2297       orntNew[3] = ornt[3];
2298       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2299       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2300 #if 1
2301       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);
2302       for (p = 0; p < 4; ++p) {
2303         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);
2304       }
2305 #endif
2306       /* D tetrahedron: {d, e, f, 3} */
2307       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
2308       orntNew[0] = 0;
2309       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
2310       orntNew[1] = ornt[1];
2311       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
2312       orntNew[2] = ornt[2];
2313       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
2314       orntNew[3] = ornt[3];
2315       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2316       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2317 #if 1
2318       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);
2319       for (p = 0; p < 4; ++p) {
2320         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);
2321       }
2322 #endif
2323       /* A' tetrahedron: {d, a, c, f} */
2324       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
2325       orntNew[0] = -3;
2326       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
2327       orntNew[1] = ornt[2] < 0 ? -(GetTetSomething_Static(ornt[2], 0)+1) : GetTetSomething_Static(ornt[2], 0);
2328       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
2329       orntNew[2] = 0;
2330       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
2331       orntNew[3] = 2;
2332       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
2333       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
2334 #if 1
2335       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);
2336       for (p = 0; p < 4; ++p) {
2337         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);
2338       }
2339 #endif
2340       /* B' tetrahedron: {e, b, a, f} */
2341       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
2342       orntNew[0] = -3;
2343       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
2344       orntNew[1] = 1;
2345       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
2346       orntNew[2] = 0;
2347       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + 3;
2348       orntNew[3] = ornt[3] < 0 ? -(GetTetSomething_Static(ornt[3], 0)+1) : GetTetSomething_Static(ornt[3], 0);
2349       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
2350       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
2351 #if 1
2352       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);
2353       for (p = 0; p < 4; ++p) {
2354         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);
2355       }
2356 #endif
2357       /* C' tetrahedron: {b, f, c, a} */
2358       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
2359       orntNew[0] = -3;
2360       coneNew[1] = fStartNew + (cone[0] - fStart)*4 + 3;
2361       orntNew[1] = ornt[0] < 0 ? -(GetTetSomething_Static(ornt[0], 2)+1) : GetTetSomething_Static(ornt[0], 2);
2362       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
2363       orntNew[2] = -3;
2364       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
2365       orntNew[3] = -2;
2366       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
2367       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
2368 #if 1
2369       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);
2370       for (p = 0; p < 4; ++p) {
2371         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);
2372       }
2373 #endif
2374       /* D' tetrahedron: {f, e, d, a} */
2375       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
2376       orntNew[0] = -3;
2377       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
2378       orntNew[1] = -3;
2379       coneNew[2] = fStartNew + (cone[1] - fStart)*4 + 3;
2380       orntNew[2] = ornt[1] < 0 ? -(GetTetSomething_Static(ornt[1], 0)+1) : GetTetSomething_Static(ornt[1], 0);
2381       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
2382       orntNew[3] = -3;
2383       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
2384       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
2385 #if 1
2386       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);
2387       for (p = 0; p < 4; ++p) {
2388         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);
2389       }
2390 #endif
2391     }
2392     /* Split faces have 3 edges and the same cells as the parent */
2393     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2394     ierr = PetscMalloc1((2 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
2395     for (f = fStart; f < fEnd; ++f) {
2396       const PetscInt  newp = fStartNew + (f - fStart)*4;
2397       const PetscInt *cone, *ornt, *support;
2398       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
2399 
2400       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2401       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
2402       /* A triangle */
2403       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
2404       orntNew[0] = ornt[0];
2405       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
2406       orntNew[1] = -2;
2407       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
2408       orntNew[2] = ornt[2];
2409       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2410       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2411 #if 1
2412       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);
2413       for (p = 0; p < 3; ++p) {
2414         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);
2415       }
2416 #endif
2417       /* B triangle */
2418       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
2419       orntNew[0] = ornt[0];
2420       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
2421       orntNew[1] = ornt[1];
2422       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
2423       orntNew[2] = -2;
2424       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2425       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2426 #if 1
2427       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);
2428       for (p = 0; p < 3; ++p) {
2429         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);
2430       }
2431 #endif
2432       /* C triangle */
2433       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
2434       orntNew[0] = -2;
2435       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
2436       orntNew[1] = ornt[1];
2437       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
2438       orntNew[2] = ornt[2];
2439       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2440       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2441 #if 1
2442       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);
2443       for (p = 0; p < 3; ++p) {
2444         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);
2445       }
2446 #endif
2447       /* D triangle */
2448       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
2449       orntNew[0] = 0;
2450       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
2451       orntNew[1] = 0;
2452       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
2453       orntNew[2] = 0;
2454       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2455       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2456 #if 1
2457       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);
2458       for (p = 0; p < 3; ++p) {
2459         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);
2460       }
2461 #endif
2462       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2463       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2464       for (r = 0; r < 4; ++r) {
2465         for (s = 0; s < supportSize; ++s) {
2466           PetscInt subf;
2467           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2468           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2469           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2470           for (c = 0; c < coneSize; ++c) {
2471             if (cone[c] == f) break;
2472           }
2473           subf = GetTriSubfaceInverse_Static(ornt[c], r);
2474           supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
2475         }
2476         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
2477 #if 1
2478         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);
2479         for (p = 0; p < supportSize; ++p) {
2480           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);
2481         }
2482 #endif
2483       }
2484     }
2485     /* Interior faces have 3 edges and 2 cells */
2486     for (c = cStart; c < cEnd; ++c) {
2487       PetscInt        newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8;
2488       const PetscInt *cone, *ornt;
2489       PetscInt        coneNew[3], orntNew[3];
2490       PetscInt        supportNew[2];
2491 
2492       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2493       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2494       /* Face A: {c, a, d} */
2495       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
2496       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2497       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
2498       orntNew[1] = ornt[1] < 0 ? -2 : 0;
2499       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 2);
2500       orntNew[2] = ornt[2] < 0 ? -2 : 0;
2501       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2502       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2503 #if 1
2504       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2505       for (p = 0; p < 3; ++p) {
2506         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);
2507       }
2508 #endif
2509       supportNew[0] = (c - cStart)*8 + 0;
2510       supportNew[1] = (c - cStart)*8 + 0+4;
2511       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2512 #if 1
2513       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2514       for (p = 0; p < 2; ++p) {
2515         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);
2516       }
2517 #endif
2518       ++newp;
2519       /* Face B: {a, b, e} */
2520       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
2521       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2522       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 0);
2523       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2524       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
2525       orntNew[2] = ornt[1] < 0 ? -2 : 0;
2526       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2527       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2528 #if 1
2529       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2530       for (p = 0; p < 3; ++p) {
2531         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);
2532       }
2533 #endif
2534       supportNew[0] = (c - cStart)*8 + 1;
2535       supportNew[1] = (c - cStart)*8 + 1+4;
2536       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2537 #if 1
2538       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2539       for (p = 0; p < 2; ++p) {
2540         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);
2541       }
2542 #endif
2543       ++newp;
2544       /* Face C: {c, f, b} */
2545       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
2546       orntNew[0] = ornt[2] < 0 ? -2 : 0;
2547       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
2548       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2549       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 1);
2550       orntNew[2] = ornt[0] < 0 ? -2 : 0;
2551       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2552       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2553 #if 1
2554       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2555       for (p = 0; p < 3; ++p) {
2556         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);
2557       }
2558 #endif
2559       supportNew[0] = (c - cStart)*8 + 2;
2560       supportNew[1] = (c - cStart)*8 + 2+4;
2561       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2562 #if 1
2563       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2564       for (p = 0; p < 2; ++p) {
2565         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);
2566       }
2567 #endif
2568       ++newp;
2569       /* Face D: {d, e, f} */
2570       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 0);
2571       orntNew[0] = ornt[1] < 0 ? -2 : 0;
2572       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
2573       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2574       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
2575       orntNew[2] = ornt[2] < 0 ? -2 : 0;
2576       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2577       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2578 #if 1
2579       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2580       for (p = 0; p < 3; ++p) {
2581         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);
2582       }
2583 #endif
2584       supportNew[0] = (c - cStart)*8 + 3;
2585       supportNew[1] = (c - cStart)*8 + 3+4;
2586       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2587 #if 1
2588       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2589       for (p = 0; p < 2; ++p) {
2590         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);
2591       }
2592 #endif
2593       ++newp;
2594       /* Face E: {d, f, a} */
2595       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
2596       orntNew[0] = ornt[2] < 0 ? 0 : -2;
2597       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2598       orntNew[1] = -2;
2599       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
2600       orntNew[2] = ornt[1] < 0 ? -2 : 0;
2601       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2602       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2603 #if 1
2604       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2605       for (p = 0; p < 3; ++p) {
2606         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);
2607       }
2608 #endif
2609       supportNew[0] = (c - cStart)*8 + 0+4;
2610       supportNew[1] = (c - cStart)*8 + 3+4;
2611       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2612 #if 1
2613       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2614       for (p = 0; p < 2; ++p) {
2615         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);
2616       }
2617 #endif
2618       ++newp;
2619       /* Face F: {c, a, f} */
2620       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
2621       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2622       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2623       orntNew[1] = 0;
2624       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
2625       orntNew[2] = ornt[2] < 0 ? 0 : -2;
2626       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2627       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2628 #if 1
2629       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2630       for (p = 0; p < 3; ++p) {
2631         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);
2632       }
2633 #endif
2634       supportNew[0] = (c - cStart)*8 + 0+4;
2635       supportNew[1] = (c - cStart)*8 + 2+4;
2636       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2637 #if 1
2638       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2639       for (p = 0; p < 2; ++p) {
2640         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);
2641       }
2642 #endif
2643       ++newp;
2644       /* Face G: {e, a, f} */
2645       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
2646       orntNew[0] = ornt[1] < 0 ? -2 : 0;
2647       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2648       orntNew[1] = 0;
2649       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
2650       orntNew[2] = ornt[3] < 0 ? 0 : -2;
2651       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2652       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2653 #if 1
2654       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2655       for (p = 0; p < 3; ++p) {
2656         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);
2657       }
2658 #endif
2659       supportNew[0] = (c - cStart)*8 + 1+4;
2660       supportNew[1] = (c - cStart)*8 + 3+4;
2661       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2662 #if 1
2663       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2664       for (p = 0; p < 2; ++p) {
2665         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);
2666       }
2667 #endif
2668       ++newp;
2669       /* Face H: {a, b, f} */
2670       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
2671       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2672       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
2673       orntNew[1] = ornt[3] < 0 ? 0 : -2;
2674       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2675       orntNew[2] = -2;
2676       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2677       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2678 #if 1
2679       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2680       for (p = 0; p < 3; ++p) {
2681         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);
2682       }
2683 #endif
2684       supportNew[0] = (c - cStart)*8 + 1+4;
2685       supportNew[1] = (c - cStart)*8 + 2+4;
2686       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2687 #if 1
2688       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2689       for (p = 0; p < 2; ++p) {
2690         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);
2691       }
2692 #endif
2693       ++newp;
2694     }
2695     /* Split Edges have 2 vertices and the same faces as the parent */
2696     for (e = eStart; e < eEnd; ++e) {
2697       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
2698 
2699       for (r = 0; r < 2; ++r) {
2700         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
2701         const PetscInt *cone, *ornt, *support;
2702         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2703 
2704         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
2705         coneNew[0]       = vStartNew + (cone[0] - vStart);
2706         coneNew[1]       = vStartNew + (cone[1] - vStart);
2707         coneNew[(r+1)%2] = newv;
2708         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2709 #if 1
2710         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2711         for (p = 0; p < 2; ++p) {
2712           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);
2713         }
2714 #endif
2715         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
2716         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
2717         for (s = 0; s < supportSize; ++s) {
2718           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2719           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2720           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2721           for (c = 0; c < coneSize; ++c) {
2722             if (cone[c] == e) break;
2723           }
2724           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
2725         }
2726         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2727 #if 1
2728         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2729         for (p = 0; p < supportSize; ++p) {
2730           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);
2731         }
2732 #endif
2733       }
2734     }
2735     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
2736     for (f = fStart; f < fEnd; ++f) {
2737       const PetscInt *cone, *ornt, *support;
2738       PetscInt        coneSize, supportSize, s;
2739 
2740       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2741       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2742       for (r = 0; r < 3; ++r) {
2743         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
2744         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
2745         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
2746                                     -1, -1,  1,  6,  0,  4,
2747                                      2,  5,  3,  4, -1, -1,
2748                                     -1, -1,  3,  6,  2,  7};
2749 
2750         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2751         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
2752         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
2753         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2754 #if 1
2755         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2756         for (p = 0; p < 2; ++p) {
2757           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);
2758         }
2759 #endif
2760         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
2761         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
2762         for (s = 0; s < supportSize; ++s) {
2763           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2764           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2765           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2766           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
2767           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
2768           er = GetTetSomethingInverse_Static(ornt[c], r);
2769           if (er == eint[c]) {
2770             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
2771           } else {
2772             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
2773             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
2774           }
2775         }
2776         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2777 #if 1
2778         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2779         for (p = 0; p < intFaces; ++p) {
2780           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);
2781         }
2782 #endif
2783       }
2784     }
2785     /* Interior edges have 2 vertices and 4 faces */
2786     for (c = cStart; c < cEnd; ++c) {
2787       const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2788       const PetscInt *cone, *ornt, *fcone;
2789       PetscInt        coneNew[2], supportNew[4], find;
2790 
2791       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2792       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2793       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
2794       find = GetTriEdge_Static(ornt[0], 0);
2795       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
2796       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
2797       find = GetTriEdge_Static(ornt[2], 1);
2798       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
2799       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2800 #if 1
2801       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2802       for (p = 0; p < 2; ++p) {
2803         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);
2804       }
2805 #endif
2806       supportNew[0] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 4;
2807       supportNew[1] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 5;
2808       supportNew[2] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 6;
2809       supportNew[3] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 7;
2810       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2811 #if 1
2812       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2813       for (p = 0; p < 4; ++p) {
2814         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);
2815       }
2816 #endif
2817     }
2818     /* Old vertices have identical supports */
2819     for (v = vStart; v < vEnd; ++v) {
2820       const PetscInt  newp = vStartNew + (v - vStart);
2821       const PetscInt *support, *cone;
2822       PetscInt        size, s;
2823 
2824       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2825       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2826       for (s = 0; s < size; ++s) {
2827         PetscInt r = 0;
2828 
2829         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2830         if (cone[1] == v) r = 1;
2831         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
2832       }
2833       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2834 #if 1
2835       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2836       for (p = 0; p < size; ++p) {
2837         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);
2838       }
2839 #endif
2840     }
2841     /* Edge vertices have 2 + face*2 + 0/1 supports */
2842     for (e = eStart; e < eEnd; ++e) {
2843       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
2844       const PetscInt *cone, *support;
2845       PetscInt       *star = NULL, starSize, cellSize = 0, coneSize, size, s;
2846 
2847       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
2848       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
2849       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
2850       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
2851       for (s = 0; s < size; ++s) {
2852         PetscInt r = 0;
2853 
2854         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2855         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2856         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
2857         supportRef[2+s*2+0] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
2858         supportRef[2+s*2+1] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
2859       }
2860       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
2861       for (s = 0; s < starSize*2; s += 2) {
2862         const PetscInt *cone, *ornt;
2863         PetscInt        e01, e23;
2864 
2865         if ((star[s] >= cStart) && (star[s] < cEnd)) {
2866           /* Check edge 0-1 */
2867           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
2868           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
2869           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
2870           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
2871           /* Check edge 2-3 */
2872           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
2873           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
2874           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
2875           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
2876           if ((e01 == e) || (e23 == e)) {supportRef[2+size*2+cellSize++] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (star[s] - cStart);}
2877         }
2878       }
2879       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
2880       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2881 #if 1
2882       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2883       for (p = 0; p < 2+size*2+cellSize; ++p) {
2884         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);
2885       }
2886 #endif
2887     }
2888     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2889     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
2890     break;
2891   case 7:
2892     /* Hybrid Simplicial 3D */
2893     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
2894     /* Interior cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
2895     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
2896     for (c = cStart; c < cMax; ++c) {
2897       const PetscInt  newp = cStartNew + (c - cStart)*8;
2898       const PetscInt *cone, *ornt;
2899       PetscInt        coneNew[4], orntNew[4];
2900 
2901       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2902       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2903       /* A tetrahedron: {0, a, c, d} */
2904       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
2905       orntNew[0] = ornt[0];
2906       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
2907       orntNew[1] = ornt[1];
2908       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
2909       orntNew[2] = ornt[2];
2910       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
2911       orntNew[3] = 0;
2912       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2913       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2914 #if 1
2915       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);
2916       for (p = 0; p < 4; ++p) {
2917         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);
2918       }
2919 #endif
2920       /* B tetrahedron: {a, 1, b, e} */
2921       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
2922       orntNew[0] = ornt[0];
2923       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
2924       orntNew[1] = ornt[1];
2925       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
2926       orntNew[2] = 0;
2927       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
2928       orntNew[3] = ornt[3];
2929       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2930       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2931 #if 1
2932       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);
2933       for (p = 0; p < 4; ++p) {
2934         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);
2935       }
2936 #endif
2937       /* C tetrahedron: {c, b, 2, f} */
2938       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
2939       orntNew[0] = ornt[0];
2940       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
2941       orntNew[1] = 0;
2942       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
2943       orntNew[2] = ornt[2];
2944       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
2945       orntNew[3] = ornt[3];
2946       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2947       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2948 #if 1
2949       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);
2950       for (p = 0; p < 4; ++p) {
2951         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);
2952       }
2953 #endif
2954       /* D tetrahedron: {d, e, f, 3} */
2955       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
2956       orntNew[0] = 0;
2957       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
2958       orntNew[1] = ornt[1];
2959       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
2960       orntNew[2] = ornt[2];
2961       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
2962       orntNew[3] = ornt[3];
2963       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2964       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2965 #if 1
2966       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);
2967       for (p = 0; p < 4; ++p) {
2968         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);
2969       }
2970 #endif
2971       /* A' tetrahedron: {d, a, c, f} */
2972       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
2973       orntNew[0] = -3;
2974       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
2975       orntNew[1] = ornt[2] < 0 ? -(GetTetSomething_Static(ornt[2], 0)+1) : GetTetSomething_Static(ornt[2], 0);
2976       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
2977       orntNew[2] = 0;
2978       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
2979       orntNew[3] = 2;
2980       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
2981       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
2982 #if 1
2983       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);
2984       for (p = 0; p < 4; ++p) {
2985         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);
2986       }
2987 #endif
2988       /* B' tetrahedron: {e, b, a, f} */
2989       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
2990       orntNew[0] = -3;
2991       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
2992       orntNew[1] = 1;
2993       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
2994       orntNew[2] = 0;
2995       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + 3;
2996       orntNew[3] = ornt[3] < 0 ? -(GetTetSomething_Static(ornt[3], 0)+1) : GetTetSomething_Static(ornt[3], 0);
2997       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
2998       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
2999 #if 1
3000       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);
3001       for (p = 0; p < 4; ++p) {
3002         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);
3003       }
3004 #endif
3005       /* C' tetrahedron: {b, f, c, a} */
3006       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
3007       orntNew[0] = -3;
3008       coneNew[1] = fStartNew + (cone[0] - fStart)*4 + 3;
3009       orntNew[1] = ornt[0] < 0 ? -(GetTetSomething_Static(ornt[0], 2)+1) : GetTetSomething_Static(ornt[0], 2);
3010       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
3011       orntNew[2] = -3;
3012       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
3013       orntNew[3] = -2;
3014       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
3015       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
3016 #if 1
3017       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);
3018       for (p = 0; p < 4; ++p) {
3019         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);
3020       }
3021 #endif
3022       /* D' tetrahedron: {f, e, d, a} */
3023       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
3024       orntNew[0] = -3;
3025       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
3026       orntNew[1] = -3;
3027       coneNew[2] = fStartNew + (cone[1] - fStart)*4 + 3;
3028       orntNew[2] = ornt[1] < 0 ? -(GetTetSomething_Static(ornt[1], 0)+1) : GetTetSomething_Static(ornt[1], 0);
3029       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
3030       orntNew[3] = -3;
3031       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
3032       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
3033 #if 1
3034       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);
3035       for (p = 0; p < 4; ++p) {
3036         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);
3037       }
3038 #endif
3039     }
3040     /* Hybrid cells have 5 faces */
3041     for (c = cMax; c < cEnd; ++c) {
3042       const PetscInt  newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4;
3043       const PetscInt *cone, *ornt, *fornt;
3044       PetscInt        coneNew[5], orntNew[5], o, of, i;
3045 
3046       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3047       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3048       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
3049       o = ornt[0] < 0 ? -1 : 1;
3050       for (r = 0; r < 3; ++r) {
3051         coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], r);
3052         orntNew[0] = ornt[0];
3053         coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], r);
3054         orntNew[1] = ornt[1];
3055         of = fornt[GetTriEdge_Static(ornt[0], r)]       < 0 ? -1 : 1;
3056         i  = GetTriEdgeInverse_Static(ornt[0], r)       + 2;
3057         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], r)]       - fMax)*2 + (o*of < 0 ? 1 : 0);
3058         orntNew[i] = 0;
3059         i  = GetTriEdgeInverse_Static(ornt[0], (r+1)%3) + 2;
3060         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + GetTriSubface_Static(ornt[0], r);
3061         orntNew[i] = 0;
3062         of = fornt[GetTriEdge_Static(ornt[0], (r+2)%3)] < 0 ? -1 : 1;
3063         i  = GetTriEdgeInverse_Static(ornt[0], (r+2)%3) + 2;
3064         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], (r+2)%3)] - fMax)*2 + (o*of < 0 ? 0 : 1);
3065         orntNew[i] = 0;
3066         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
3067         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
3068 #if 1
3069         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);
3070         for (p = 0; p < 2; ++p) {
3071           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);
3072         }
3073         for (p = 2; p < 5; ++p) {
3074           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);
3075         }
3076 #endif
3077       }
3078       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + 3;
3079       orntNew[0] = 0;
3080       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + 3;
3081       orntNew[1] = 0;
3082       coneNew[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
3083       orntNew[2] = 0;
3084       coneNew[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
3085       orntNew[3] = 0;
3086       coneNew[4] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
3087       orntNew[4] = 0;
3088       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3089       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3090 #if 1
3091       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);
3092       for (p = 0; p < 2; ++p) {
3093         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);
3094       }
3095       for (p = 2; p < 5; ++p) {
3096         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);
3097       }
3098 #endif
3099     }
3100     /* Split faces have 3 edges and the same cells as the parent */
3101     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3102     ierr = PetscMalloc1((2 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
3103     for (f = fStart; f < fMax; ++f) {
3104       const PetscInt  newp = fStartNew + (f - fStart)*4;
3105       const PetscInt *cone, *ornt, *support;
3106       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
3107 
3108       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3109       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3110       /* A triangle */
3111       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
3112       orntNew[0] = ornt[0];
3113       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
3114       orntNew[1] = -2;
3115       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
3116       orntNew[2] = ornt[2];
3117       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3118       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3119 #if 1
3120       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);
3121       for (p = 0; p < 3; ++p) {
3122         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);
3123       }
3124 #endif
3125       /* B triangle */
3126       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
3127       orntNew[0] = ornt[0];
3128       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
3129       orntNew[1] = ornt[1];
3130       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
3131       orntNew[2] = -2;
3132       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3133       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3134 #if 1
3135       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);
3136       for (p = 0; p < 3; ++p) {
3137         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3138       }
3139 #endif
3140       /* C triangle */
3141       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
3142       orntNew[0] = -2;
3143       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
3144       orntNew[1] = ornt[1];
3145       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
3146       orntNew[2] = ornt[2];
3147       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3148       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3149 #if 1
3150       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);
3151       for (p = 0; p < 3; ++p) {
3152         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);
3153       }
3154 #endif
3155       /* D triangle */
3156       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
3157       orntNew[0] = 0;
3158       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
3159       orntNew[1] = 0;
3160       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
3161       orntNew[2] = 0;
3162       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3163       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3164 #if 1
3165       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);
3166       for (p = 0; p < 3; ++p) {
3167         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);
3168       }
3169 #endif
3170       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3171       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3172       for (r = 0; r < 4; ++r) {
3173         for (s = 0; s < supportSize; ++s) {
3174           PetscInt subf;
3175           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3176           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3177           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3178           for (c = 0; c < coneSize; ++c) {
3179             if (cone[c] == f) break;
3180           }
3181           subf = GetTriSubfaceInverse_Static(ornt[c], r);
3182           if (support[s] < cMax) {
3183             supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
3184           } else {
3185             supportRef[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (r==3 ? r : subf);
3186           }
3187         }
3188         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
3189 #if 1
3190         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);
3191         for (p = 0; p < supportSize; ++p) {
3192           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);
3193         }
3194 #endif
3195       }
3196     }
3197     /* Interior cell faces have 3 edges and 2 cells */
3198     for (c = cStart; c < cMax; ++c) {
3199       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8;
3200       const PetscInt *cone, *ornt;
3201       PetscInt        coneNew[3], orntNew[3];
3202       PetscInt        supportNew[2];
3203 
3204       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3205       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3206       /* Face A: {c, a, d} */
3207       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
3208       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3209       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
3210       orntNew[1] = ornt[1] < 0 ? -2 : 0;
3211       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 2);
3212       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3213       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3214       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3215 #if 1
3216       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3217       for (p = 0; p < 3; ++p) {
3218         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);
3219       }
3220 #endif
3221       supportNew[0] = (c - cStart)*8 + 0;
3222       supportNew[1] = (c - cStart)*8 + 0+4;
3223       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3224 #if 1
3225       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3226       for (p = 0; p < 2; ++p) {
3227         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);
3228       }
3229 #endif
3230       ++newp;
3231       /* Face B: {a, b, e} */
3232       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
3233       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3234       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 0);
3235       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3236       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
3237       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3238       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3239       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3240 #if 1
3241       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);
3242       for (p = 0; p < 3; ++p) {
3243         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);
3244       }
3245 #endif
3246       supportNew[0] = (c - cStart)*8 + 1;
3247       supportNew[1] = (c - cStart)*8 + 1+4;
3248       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3249 #if 1
3250       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3251       for (p = 0; p < 2; ++p) {
3252         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);
3253       }
3254 #endif
3255       ++newp;
3256       /* Face C: {c, f, b} */
3257       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
3258       orntNew[0] = ornt[2] < 0 ? -2 : 0;
3259       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
3260       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3261       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 1);
3262       orntNew[2] = ornt[0] < 0 ? -2 : 0;
3263       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3264       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3265 #if 1
3266       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3267       for (p = 0; p < 3; ++p) {
3268         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);
3269       }
3270 #endif
3271       supportNew[0] = (c - cStart)*8 + 2;
3272       supportNew[1] = (c - cStart)*8 + 2+4;
3273       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3274 #if 1
3275       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3276       for (p = 0; p < 2; ++p) {
3277         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);
3278       }
3279 #endif
3280       ++newp;
3281       /* Face D: {d, e, f} */
3282       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 0);
3283       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3284       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
3285       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3286       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
3287       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3288       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3289       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3290 #if 1
3291       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3292       for (p = 0; p < 3; ++p) {
3293         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);
3294       }
3295 #endif
3296       supportNew[0] = (c - cStart)*8 + 3;
3297       supportNew[1] = (c - cStart)*8 + 3+4;
3298       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3299 #if 1
3300       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3301       for (p = 0; p < 2; ++p) {
3302         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);
3303       }
3304 #endif
3305       ++newp;
3306       /* Face E: {d, f, a} */
3307       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
3308       orntNew[0] = ornt[2] < 0 ? 0 : -2;
3309       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3310       orntNew[1] = -2;
3311       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
3312       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3313       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3314       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3315 #if 1
3316       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3317       for (p = 0; p < 3; ++p) {
3318         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);
3319       }
3320 #endif
3321       supportNew[0] = (c - cStart)*8 + 0+4;
3322       supportNew[1] = (c - cStart)*8 + 3+4;
3323       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3324 #if 1
3325       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3326       for (p = 0; p < 2; ++p) {
3327         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);
3328       }
3329 #endif
3330       ++newp;
3331       /* Face F: {c, a, f} */
3332       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
3333       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3334       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3335       orntNew[1] = 0;
3336       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
3337       orntNew[2] = ornt[2] < 0 ? 0 : -2;
3338       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3339       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3340 #if 1
3341       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3342       for (p = 0; p < 3; ++p) {
3343         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);
3344       }
3345 #endif
3346       supportNew[0] = (c - cStart)*8 + 0+4;
3347       supportNew[1] = (c - cStart)*8 + 2+4;
3348       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3349 #if 1
3350       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3351       for (p = 0; p < 2; ++p) {
3352         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);
3353       }
3354 #endif
3355       ++newp;
3356       /* Face G: {e, a, f} */
3357       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
3358       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3359       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3360       orntNew[1] = 0;
3361       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
3362       orntNew[2] = ornt[3] < 0 ? 0 : -2;
3363       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3364       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3365 #if 1
3366       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3367       for (p = 0; p < 3; ++p) {
3368         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);
3369       }
3370 #endif
3371       supportNew[0] = (c - cStart)*8 + 1+4;
3372       supportNew[1] = (c - cStart)*8 + 3+4;
3373       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3374 #if 1
3375       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3376       for (p = 0; p < 2; ++p) {
3377         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);
3378       }
3379 #endif
3380       ++newp;
3381       /* Face H: {a, b, f} */
3382       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
3383       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3384       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
3385       orntNew[1] = ornt[3] < 0 ? 0 : -2;
3386       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3387       orntNew[2] = -2;
3388       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3389       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3390 #if 1
3391       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3392       for (p = 0; p < 3; ++p) {
3393         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);
3394       }
3395 #endif
3396       supportNew[0] = (c - cStart)*8 + 1+4;
3397       supportNew[1] = (c - cStart)*8 + 2+4;
3398       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3399 #if 1
3400       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3401       for (p = 0; p < 2; ++p) {
3402         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);
3403       }
3404 #endif
3405       ++newp;
3406     }
3407     /* Hybrid split faces have 4 edges and same cells */
3408     for (f = fMax; f < fEnd; ++f) {
3409       const PetscInt *cone, *ornt, *support;
3410       PetscInt        coneNew[4], orntNew[4];
3411       PetscInt        supportNew[2], size, s, c;
3412 
3413       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3414       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3415       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3416       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3417       for (r = 0; r < 2; ++r) {
3418         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
3419 
3420         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
3421         orntNew[0]   = ornt[0];
3422         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
3423         orntNew[1]   = ornt[1];
3424         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (cone[2+r] - eMax);
3425         orntNew[2+r] = 0;
3426         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd      - eMax) + (f - fMax);
3427         orntNew[3-r] = 0;
3428         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3429         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3430 #if 1
3431         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
3432         for (p = 0; p < 2; ++p) {
3433           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);
3434         }
3435         for (p = 2; p < 4; ++p) {
3436           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);
3437         }
3438 #endif
3439         for (s = 0; s < size; ++s) {
3440           const PetscInt *coneCell, *orntCell, *fornt;
3441           PetscInt        o, of;
3442 
3443           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
3444           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
3445           o = orntCell[0] < 0 ? -1 : 1;
3446           for (c = 2; c < 5; ++c) if (coneCell[c] == f) break;
3447           if (c >= 5) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
3448           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
3449           of = fornt[c-2] < 0 ? -1 : 1;
3450           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetTriEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%3;
3451         }
3452         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3453 #if 1
3454         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
3455         for (p = 0; p < size; ++p) {
3456           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);
3457         }
3458 #endif
3459       }
3460     }
3461     /* Hybrid cell faces have 4 edges and 2 cells */
3462     for (c = cMax; c < cEnd; ++c) {
3463       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3;
3464       const PetscInt *cone, *ornt;
3465       PetscInt        coneNew[4], orntNew[4];
3466       PetscInt        supportNew[2];
3467 
3468       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3469       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3470       for (r = 0; r < 3; ++r) {
3471         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + (r+2)%3;
3472         orntNew[0] = 0;
3473         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + (r+2)%3;
3474         orntNew[1] = 0;
3475         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+(r+2)%3] - fMax);
3476         orntNew[2] = 0;
3477         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+r]       - fMax);
3478         orntNew[3] = 0;
3479         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
3480         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
3481 #if 1
3482         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);
3483         for (p = 0; p < 2; ++p) {
3484           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);
3485         }
3486         for (p = 2; p < 4; ++p) {
3487           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);
3488         }
3489 #endif
3490         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetTriSubface_Static(ornt[0], r);
3491         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + 3;
3492         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
3493 #if 1
3494         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);
3495         for (p = 0; p < 2; ++p) {
3496           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);
3497         }
3498 #endif
3499       }
3500     }
3501     /* Interior split edges have 2 vertices and the same faces as the parent */
3502     for (e = eStart; e < eMax; ++e) {
3503       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
3504 
3505       for (r = 0; r < 2; ++r) {
3506         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
3507         const PetscInt *cone, *ornt, *support;
3508         PetscInt        coneNew[2], coneSize, c, supportSize, s;
3509 
3510         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3511         coneNew[0]       = vStartNew + (cone[0] - vStart);
3512         coneNew[1]       = vStartNew + (cone[1] - vStart);
3513         coneNew[(r+1)%2] = newv;
3514         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3515 #if 1
3516         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3517         for (p = 0; p < 2; ++p) {
3518           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);
3519         }
3520 #endif
3521         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
3522         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3523         for (s = 0; s < supportSize; ++s) {
3524           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3525           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3526           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3527           for (c = 0; c < coneSize; ++c) if (cone[c] == e) break;
3528           if (support[s] < fMax) {
3529             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
3530           } else {
3531             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
3532           }
3533         }
3534         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3535 #if 1
3536         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3537         for (p = 0; p < supportSize; ++p) {
3538           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);
3539         }
3540 #endif
3541       }
3542     }
3543     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
3544     for (f = fStart; f < fMax; ++f) {
3545       const PetscInt *cone, *ornt, *support;
3546       PetscInt        coneSize, supportSize, s;
3547 
3548       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3549       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3550       for (r = 0; r < 3; ++r) {
3551         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
3552         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
3553         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
3554                                     -1, -1,  1,  6,  0,  4,
3555                                      2,  5,  3,  4, -1, -1,
3556                                     -1, -1,  3,  6,  2,  7};
3557 
3558         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3559         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
3560         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
3561         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3562 #if 1
3563         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3564         for (p = 0; p < 2; ++p) {
3565           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
3566         }
3567 #endif
3568         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
3569         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
3570         for (s = 0; s < supportSize; ++s) {
3571           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3572           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3573           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3574           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
3575           if (support[s] < cMax) {
3576             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
3577             er = GetTetSomethingInverse_Static(ornt[c], r);
3578             if (er == eint[c]) {
3579               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
3580             } else {
3581               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
3582               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
3583             }
3584           } else {
3585             supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (r + 1)%3;
3586           }
3587         }
3588         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3589 #if 1
3590         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3591         for (p = 0; p < intFaces; ++p) {
3592           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);
3593         }
3594 #endif
3595       }
3596     }
3597     /* Interior cell edges have 2 vertices and 4 faces */
3598     for (c = cStart; c < cMax; ++c) {
3599       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3600       const PetscInt *cone, *ornt, *fcone;
3601       PetscInt        coneNew[2], supportNew[4], find;
3602 
3603       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3604       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3605       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
3606       find = GetTriEdge_Static(ornt[0], 0);
3607       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3608       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
3609       find = GetTriEdge_Static(ornt[2], 1);
3610       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3611       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3612 #if 1
3613       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3614       for (p = 0; p < 2; ++p) {
3615         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);
3616       }
3617 #endif
3618       supportNew[0] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 4;
3619       supportNew[1] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 5;
3620       supportNew[2] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 6;
3621       supportNew[3] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 7;
3622       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3623 #if 1
3624       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3625       for (p = 0; p < 4; ++p) {
3626         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);
3627       }
3628 #endif
3629     }
3630     /* Hybrid edges have two vertices and the same faces */
3631     for (e = eMax; e < eEnd; ++e) {
3632       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
3633       const PetscInt *cone, *support, *fcone;
3634       PetscInt        coneNew[2], size, fsize, s;
3635 
3636       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3637       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
3638       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3639       coneNew[0] = vStartNew + (cone[0] - vStart);
3640       coneNew[1] = vStartNew + (cone[1] - vStart);
3641       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3642 #if 1
3643       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3644       for (p = 0; p < 2; ++p) {
3645         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);
3646       }
3647 #endif
3648       for (s = 0; s < size; ++s) {
3649         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
3650         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
3651         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
3652         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
3653         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + c-2;
3654       }
3655       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3656 #if 1
3657       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3658       for (p = 0; p < size; ++p) {
3659         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);
3660       }
3661 #endif
3662     }
3663     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
3664     for (f = fMax; f < fEnd; ++f) {
3665       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
3666       const PetscInt *cone, *support, *ccone, *cornt;
3667       PetscInt        coneNew[2], size, csize, s;
3668 
3669       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3670       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3671       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3672       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
3673       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
3674       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3675 #if 1
3676       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3677       for (p = 0; p < 2; ++p) {
3678         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);
3679       }
3680 #endif
3681       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 0;
3682       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 1;
3683       for (s = 0; s < size; ++s) {
3684         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
3685         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
3686         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
3687         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
3688         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]);
3689         supportRef[2+s*2+0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + c-2;
3690         supportRef[2+s*2+1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (c-1)%3;
3691       }
3692       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3693 #if 1
3694       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3695       for (p = 0; p < 2+size*2; ++p) {
3696         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);
3697       }
3698 #endif
3699     }
3700     /* Interior vertices have identical supports */
3701     for (v = vStart; v < vEnd; ++v) {
3702       const PetscInt  newp = vStartNew + (v - vStart);
3703       const PetscInt *support, *cone;
3704       PetscInt        size, s;
3705 
3706       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
3707       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
3708       for (s = 0; s < size; ++s) {
3709         PetscInt r = 0;
3710 
3711         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3712         if (cone[1] == v) r = 1;
3713         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
3714         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (support[s] - eMax);
3715       }
3716       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3717 #if 1
3718       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3719       for (p = 0; p < size; ++p) {
3720         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);
3721       }
3722 #endif
3723     }
3724     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
3725     for (e = eStart; e < eMax; ++e) {
3726       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
3727       const PetscInt *cone, *support;
3728       PetscInt       *star = NULL, starSize, faceSize = 0, cellSize = 0, coneSize, size, s;
3729 
3730       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
3731       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3732       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
3733       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
3734       for (s = 0; s < size; ++s) {
3735         PetscInt r = 0;
3736 
3737         if (support[s] < fMax) {
3738           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3739           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3740           for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
3741           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
3742           supportRef[2+faceSize+1] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
3743           faceSize += 2;
3744         } else {
3745           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (support[s] - fMax);
3746           ++faceSize;
3747         }
3748       }
3749       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
3750       for (s = 0; s < starSize*2; s += 2) {
3751         const PetscInt *cone, *ornt;
3752         PetscInt        e01, e23;
3753 
3754         if ((star[s] >= cStart) && (star[s] < cMax)) {
3755           /* Check edge 0-1 */
3756           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
3757           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
3758           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
3759           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
3760           /* Check edge 2-3 */
3761           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
3762           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
3763           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
3764           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
3765           if ((e01 == e) || (e23 == e)) {supportRef[2+faceSize+cellSize++] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (star[s] - cStart);}
3766         }
3767       }
3768       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
3769       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3770 #if 1
3771       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3772       for (p = 0; p < 2+faceSize+cellSize; ++p) {
3773         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);
3774       }
3775 #endif
3776     }
3777     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3778     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
3779     break;
3780   case 6:
3781     /* Hex 3D */
3782     /*
3783      Bottom (viewed from top)    Top
3784      1---------2---------2       7---------2---------6
3785      |         |         |       |         |         |
3786      |    B    2    C    |       |    H    2    G    |
3787      |         |         |       |         |         |
3788      3----3----0----1----1       3----3----0----1----1
3789      |         |         |       |         |         |
3790      |    A    0    D    |       |    E    0    F    |
3791      |         |         |       |         |         |
3792      0---------0---------3       4---------0---------5
3793      */
3794     /* All cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
3795     for (c = cStart; c < cEnd; ++c) {
3796       const PetscInt  newp = (c - cStart)*8;
3797       const PetscInt *cone, *ornt;
3798       PetscInt        coneNew[6], orntNew[6];
3799 
3800       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3801       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3802       /* A hex */
3803       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
3804       orntNew[0] = ornt[0];
3805       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
3806       orntNew[1] = 0;
3807       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
3808       orntNew[2] = ornt[2];
3809       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
3810       orntNew[3] = 0;
3811       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
3812       orntNew[4] = 0;
3813       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
3814       orntNew[5] = ornt[5];
3815       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3816       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3817 #if 1
3818       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);
3819       for (p = 0; p < 6; ++p) {
3820         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);
3821       }
3822 #endif
3823       /* B hex */
3824       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
3825       orntNew[0] = ornt[0];
3826       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
3827       orntNew[1] = 0;
3828       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
3829       orntNew[2] = -1;
3830       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
3831       orntNew[3] = ornt[3];
3832       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
3833       orntNew[4] = 0;
3834       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
3835       orntNew[5] = ornt[5];
3836       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3837       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3838 #if 1
3839       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);
3840       for (p = 0; p < 6; ++p) {
3841         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);
3842       }
3843 #endif
3844       /* C hex */
3845       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
3846       orntNew[0] = ornt[0];
3847       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
3848       orntNew[1] = 0;
3849       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
3850       orntNew[2] = -1;
3851       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
3852       orntNew[3] = ornt[3];
3853       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
3854       orntNew[4] = ornt[4];
3855       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
3856       orntNew[5] = -4;
3857       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3858       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3859 #if 1
3860       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);
3861       for (p = 0; p < 6; ++p) {
3862         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);
3863       }
3864 #endif
3865       /* D hex */
3866       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
3867       orntNew[0] = ornt[0];
3868       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
3869       orntNew[1] = 0;
3870       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
3871       orntNew[2] = ornt[2];
3872       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
3873       orntNew[3] = 0;
3874       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
3875       orntNew[4] = ornt[4];
3876       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
3877       orntNew[5] = -4;
3878       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3879       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3880 #if 1
3881       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);
3882       for (p = 0; p < 6; ++p) {
3883         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);
3884       }
3885 #endif
3886       /* E hex */
3887       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
3888       orntNew[0] = -4;
3889       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
3890       orntNew[1] = ornt[1];
3891       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
3892       orntNew[2] = ornt[2];
3893       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
3894       orntNew[3] = 0;
3895       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
3896       orntNew[4] = -1;
3897       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
3898       orntNew[5] = ornt[5];
3899       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
3900       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
3901 #if 1
3902       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);
3903       for (p = 0; p < 6; ++p) {
3904         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);
3905       }
3906 #endif
3907       /* F hex */
3908       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
3909       orntNew[0] = -4;
3910       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
3911       orntNew[1] = ornt[1];
3912       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
3913       orntNew[2] = ornt[2];
3914       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
3915       orntNew[3] = -1;
3916       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
3917       orntNew[4] = ornt[4];
3918       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
3919       orntNew[5] = 1;
3920       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
3921       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
3922 #if 1
3923       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);
3924       for (p = 0; p < 6; ++p) {
3925         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);
3926       }
3927 #endif
3928       /* G hex */
3929       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
3930       orntNew[0] = -4;
3931       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
3932       orntNew[1] = ornt[1];
3933       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
3934       orntNew[2] = 0;
3935       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
3936       orntNew[3] = ornt[3];
3937       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
3938       orntNew[4] = ornt[4];
3939       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
3940       orntNew[5] = -3;
3941       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
3942       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
3943 #if 1
3944       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);
3945       for (p = 0; p < 6; ++p) {
3946         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);
3947       }
3948 #endif
3949       /* H hex */
3950       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
3951       orntNew[0] = -4;
3952       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
3953       orntNew[1] = ornt[1];
3954       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
3955       orntNew[2] = -1;
3956       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
3957       orntNew[3] = ornt[3];
3958       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
3959       orntNew[4] = 3;
3960       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
3961       orntNew[5] = ornt[5];
3962       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
3963       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
3964 #if 1
3965       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);
3966       for (p = 0; p < 6; ++p) {
3967         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);
3968       }
3969 #endif
3970     }
3971     /* Split faces have 4 edges and the same cells as the parent */
3972     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3973     ierr = PetscMalloc1((4 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
3974     for (f = fStart; f < fEnd; ++f) {
3975       for (r = 0; r < 4; ++r) {
3976         /* TODO: This can come from GetFaces_Internal() */
3977         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};
3978         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
3979         const PetscInt *cone, *ornt, *support;
3980         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
3981 
3982         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3983         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3984         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
3985         orntNew[(r+3)%4] = ornt[(r+3)%4];
3986         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
3987         orntNew[(r+0)%4] = ornt[r];
3988         coneNew[(r+1)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
3989         orntNew[(r+1)%4] = 0;
3990         coneNew[(r+2)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + (r+3)%4;
3991         orntNew[(r+2)%4] = -2;
3992         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3993         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3994 #if 1
3995         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3996         for (p = 0; p < 4; ++p) {
3997           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);
3998         }
3999 #endif
4000         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4001         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4002         for (s = 0; s < supportSize; ++s) {
4003           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4004           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4005           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4006           for (c = 0; c < coneSize; ++c) {
4007             if (cone[c] == f) break;
4008           }
4009           supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+GetQuadSubfaceInverse_Static(ornt[c], r)];
4010         }
4011         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4012 #if 1
4013         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4014         for (p = 0; p < supportSize; ++p) {
4015           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);
4016         }
4017 #endif
4018       }
4019     }
4020     /* Interior faces have 4 edges and 2 cells */
4021     for (c = cStart; c < cEnd; ++c) {
4022       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};
4023       const PetscInt *cone, *ornt;
4024       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
4025 
4026       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4027       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4028       /* A-D face */
4029       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 0;
4030       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
4031       orntNew[0] = 0;
4032       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
4033       orntNew[1] = 0;
4034       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
4035       orntNew[2] = -2;
4036       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
4037       orntNew[3] = -2;
4038       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4039       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4040 #if 1
4041       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4042       for (p = 0; p < 4; ++p) {
4043         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);
4044       }
4045 #endif
4046       /* C-D face */
4047       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 1;
4048       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
4049       orntNew[0] = 0;
4050       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
4051       orntNew[1] = 0;
4052       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
4053       orntNew[2] = -2;
4054       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
4055       orntNew[3] = -2;
4056       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4057       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4058 #if 1
4059       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4060       for (p = 0; p < 4; ++p) {
4061         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);
4062       }
4063 #endif
4064       /* B-C face */
4065       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 2;
4066       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
4067       orntNew[0] = -2;
4068       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
4069       orntNew[1] = 0;
4070       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
4071       orntNew[2] = 0;
4072       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
4073       orntNew[3] = -2;
4074       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4075       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4076 #if 1
4077       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4078       for (p = 0; p < 4; ++p) {
4079         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);
4080       }
4081 #endif
4082       /* A-B face */
4083       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 3;
4084       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
4085       orntNew[0] = -2;
4086       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
4087       orntNew[1] = 0;
4088       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
4089       orntNew[2] = 0;
4090       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
4091       orntNew[3] = -2;
4092       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4093       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4094 #if 1
4095       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4096       for (p = 0; p < 4; ++p) {
4097         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);
4098       }
4099 #endif
4100       /* E-F face */
4101       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 4;
4102       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
4103       orntNew[0] = -2;
4104       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
4105       orntNew[1] = -2;
4106       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
4107       orntNew[2] = 0;
4108       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
4109       orntNew[3] = 0;
4110       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4111       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4112 #if 1
4113       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4114       for (p = 0; p < 4; ++p) {
4115         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);
4116       }
4117 #endif
4118       /* F-G face */
4119       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 5;
4120       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
4121       orntNew[0] = -2;
4122       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
4123       orntNew[1] = -2;
4124       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
4125       orntNew[2] = 0;
4126       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
4127       orntNew[3] = 0;
4128       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4129       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4130 #if 1
4131       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4132       for (p = 0; p < 4; ++p) {
4133         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);
4134       }
4135 #endif
4136       /* G-H face */
4137       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 6;
4138       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
4139       orntNew[0] = -2;
4140       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
4141       orntNew[1] = 0;
4142       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
4143       orntNew[2] = 0;
4144       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
4145       orntNew[3] = -2;
4146       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4147       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4148 #if 1
4149       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4150       for (p = 0; p < 4; ++p) {
4151         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);
4152       }
4153 #endif
4154       /* E-H face */
4155       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 7;
4156       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
4157       orntNew[0] = -2;
4158       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
4159       orntNew[1] = -2;
4160       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
4161       orntNew[2] = 0;
4162       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
4163       orntNew[3] = 0;
4164       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4165       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4166 #if 1
4167       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4168       for (p = 0; p < 4; ++p) {
4169         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);
4170       }
4171 #endif
4172       /* A-E face */
4173       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 8;
4174       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
4175       orntNew[0] = 0;
4176       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
4177       orntNew[1] = 0;
4178       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
4179       orntNew[2] = -2;
4180       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
4181       orntNew[3] = -2;
4182       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4183       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4184 #if 1
4185       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4186       for (p = 0; p < 4; ++p) {
4187         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);
4188       }
4189 #endif
4190       /* D-F face */
4191       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 9;
4192       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
4193       orntNew[0] = -2;
4194       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
4195       orntNew[1] = 0;
4196       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
4197       orntNew[2] = 0;
4198       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
4199       orntNew[3] = -2;
4200       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4201       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4202 #if 1
4203       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4204       for (p = 0; p < 4; ++p) {
4205         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);
4206       }
4207 #endif
4208       /* C-G face */
4209       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 10;
4210       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
4211       orntNew[0] = -2;
4212       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
4213       orntNew[1] = -2;
4214       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
4215       orntNew[2] = 0;
4216       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
4217       orntNew[3] = 0;
4218       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4219       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4220 #if 1
4221       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4222       for (p = 0; p < 4; ++p) {
4223         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);
4224       }
4225 #endif
4226       /* B-H face */
4227       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 11;
4228       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
4229       orntNew[0] = 0;
4230       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
4231       orntNew[1] = -2;
4232       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
4233       orntNew[2] = -2;
4234       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
4235       orntNew[3] = 0;
4236       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4237       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4238 #if 1
4239       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4240       for (p = 0; p < 4; ++p) {
4241         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);
4242       }
4243 #endif
4244       for (r = 0; r < 12; ++r) {
4245         newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
4246         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
4247         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
4248         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4249 #if 1
4250         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4251         for (p = 0; p < 2; ++p) {
4252           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);
4253         }
4254 #endif
4255       }
4256     }
4257     /* Split edges have 2 vertices and the same faces as the parent */
4258     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4259     for (e = eStart; e < eEnd; ++e) {
4260       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
4261 
4262       for (r = 0; r < 2; ++r) {
4263         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
4264         const PetscInt *cone, *ornt, *support;
4265         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4266 
4267         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4268         coneNew[0]       = vStartNew + (cone[0] - vStart);
4269         coneNew[1]       = vStartNew + (cone[1] - vStart);
4270         coneNew[(r+1)%2] = newv;
4271         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4272 #if 1
4273         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4274         for (p = 0; p < 2; ++p) {
4275           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);
4276         }
4277 #endif
4278         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
4279         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4280         for (s = 0; s < supportSize; ++s) {
4281           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4282           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4283           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4284           for (c = 0; c < coneSize; ++c) {
4285             if (cone[c] == e) break;
4286           }
4287           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
4288         }
4289         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4290 #if 1
4291         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4292         for (p = 0; p < supportSize; ++p) {
4293           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);
4294         }
4295 #endif
4296       }
4297     }
4298     /* Face edges have 2 vertices and 2+cells faces */
4299     for (f = fStart; f < fEnd; ++f) {
4300       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};
4301       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
4302       const PetscInt *cone, *coneCell, *orntCell, *support;
4303       PetscInt        coneNew[2], coneSize, c, supportSize, s;
4304 
4305       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4306       for (r = 0; r < 4; ++r) {
4307         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
4308 
4309         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
4310         coneNew[1] = newv;
4311         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4312 #if 1
4313         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4314         for (p = 0; p < 2; ++p) {
4315           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);
4316         }
4317 #endif
4318         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4319         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4320         supportRef[0] = fStartNew + (f - fStart)*4 + r;
4321         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
4322         for (s = 0; s < supportSize; ++s) {
4323           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4324           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
4325           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
4326           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
4327           supportRef[2+s] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
4328         }
4329         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4330 #if 1
4331         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4332         for (p = 0; p < 2+supportSize; ++p) {
4333           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);
4334         }
4335 #endif
4336       }
4337     }
4338     /* Cell edges have 2 vertices and 4 faces */
4339     for (c = cStart; c < cEnd; ++c) {
4340       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};
4341       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
4342       const PetscInt *cone;
4343       PetscInt        coneNew[2], supportNew[4];
4344 
4345       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4346       for (r = 0; r < 6; ++r) {
4347         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
4348 
4349         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
4350         coneNew[1] = newv;
4351         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4352 #if 1
4353         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4354         for (p = 0; p < 2; ++p) {
4355           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);
4356         }
4357 #endif
4358         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
4359         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4360 #if 1
4361         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4362         for (p = 0; p < 4; ++p) {
4363           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);
4364         }
4365 #endif
4366       }
4367     }
4368     /* Old vertices have identical supports */
4369     for (v = vStart; v < vEnd; ++v) {
4370       const PetscInt  newp = vStartNew + (v - vStart);
4371       const PetscInt *support, *cone;
4372       PetscInt        size, s;
4373 
4374       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4375       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4376       for (s = 0; s < size; ++s) {
4377         PetscInt r = 0;
4378 
4379         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4380         if (cone[1] == v) r = 1;
4381         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4382       }
4383       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4384 #if 1
4385       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4386       for (p = 0; p < size; ++p) {
4387         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);
4388       }
4389 #endif
4390     }
4391     /* Edge vertices have 2 + faces supports */
4392     for (e = eStart; e < eEnd; ++e) {
4393       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4394       const PetscInt *cone, *support;
4395       PetscInt        size, s;
4396 
4397       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4398       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4399       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4400       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4401       for (s = 0; s < size; ++s) {
4402         PetscInt r;
4403 
4404         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4405         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
4406         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*4 + r;
4407       }
4408       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4409 #if 1
4410       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4411       for (p = 0; p < 2+size; ++p) {
4412         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);
4413       }
4414 #endif
4415     }
4416     /* Face vertices have 4 + cells supports */
4417     for (f = fStart; f < fEnd; ++f) {
4418       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
4419       const PetscInt *cone, *support;
4420       PetscInt        size, s;
4421 
4422       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4423       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4424       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eEnd - eStart)*2 +  (f - fStart)*4 + r;
4425       for (s = 0; s < size; ++s) {
4426         PetscInt r;
4427 
4428         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4429         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
4430         supportRef[4+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (support[s] - cStart)*6 + r;
4431       }
4432       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4433 #if 1
4434       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4435       for (p = 0; p < 4+size; ++p) {
4436         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);
4437       }
4438 #endif
4439     }
4440     /* Cell vertices have 6 supports */
4441     for (c = cStart; c < cEnd; ++c) {
4442       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
4443       PetscInt       supportNew[6];
4444 
4445       for (r = 0; r < 6; ++r) {
4446         supportNew[r] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
4447       }
4448       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4449     }
4450     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4451     break;
4452   case 8:
4453     /* Hybrid Hex 3D */
4454     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
4455     /*
4456      Bottom (viewed from top)    Top
4457      1---------2---------2       7---------2---------6
4458      |         |         |       |         |         |
4459      |    B    2    C    |       |    H    2    G    |
4460      |         |         |       |         |         |
4461      3----3----0----1----1       3----3----0----1----1
4462      |         |         |       |         |         |
4463      |    A    0    D    |       |    E    0    F    |
4464      |         |         |       |         |         |
4465      0---------0---------3       4---------0---------5
4466      */
4467     /* Interior cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
4468     for (c = cStart; c < cMax; ++c) {
4469       const PetscInt  newp = (c - cStart)*8;
4470       const PetscInt *cone, *ornt;
4471       PetscInt        coneNew[6], orntNew[6];
4472 
4473       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4474       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4475       /* A hex */
4476       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
4477       orntNew[0] = ornt[0];
4478       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
4479       orntNew[1] = 0;
4480       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
4481       orntNew[2] = ornt[2];
4482       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
4483       orntNew[3] = 0;
4484       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
4485       orntNew[4] = 0;
4486       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
4487       orntNew[5] = ornt[5];
4488       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4489       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4490 #if 1
4491       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);
4492       for (p = 0; p < 6; ++p) {
4493         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);
4494       }
4495 #endif
4496       /* B hex */
4497       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
4498       orntNew[0] = ornt[0];
4499       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
4500       orntNew[1] = 0;
4501       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
4502       orntNew[2] = -1;
4503       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
4504       orntNew[3] = ornt[3];
4505       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
4506       orntNew[4] = 0;
4507       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
4508       orntNew[5] = ornt[5];
4509       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4510       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4511 #if 1
4512       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);
4513       for (p = 0; p < 6; ++p) {
4514         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);
4515       }
4516 #endif
4517       /* C hex */
4518       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
4519       orntNew[0] = ornt[0];
4520       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
4521       orntNew[1] = 0;
4522       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
4523       orntNew[2] = -1;
4524       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
4525       orntNew[3] = ornt[3];
4526       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
4527       orntNew[4] = ornt[4];
4528       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
4529       orntNew[5] = -4;
4530       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4531       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4532 #if 1
4533       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);
4534       for (p = 0; p < 6; ++p) {
4535         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);
4536       }
4537 #endif
4538       /* D hex */
4539       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
4540       orntNew[0] = ornt[0];
4541       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
4542       orntNew[1] = 0;
4543       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
4544       orntNew[2] = ornt[2];
4545       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
4546       orntNew[3] = 0;
4547       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
4548       orntNew[4] = ornt[4];
4549       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
4550       orntNew[5] = -4;
4551       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4552       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4553 #if 1
4554       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);
4555       for (p = 0; p < 6; ++p) {
4556         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);
4557       }
4558 #endif
4559       /* E hex */
4560       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
4561       orntNew[0] = -4;
4562       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
4563       orntNew[1] = ornt[1];
4564       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
4565       orntNew[2] = ornt[2];
4566       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
4567       orntNew[3] = 0;
4568       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
4569       orntNew[4] = -1;
4570       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
4571       orntNew[5] = ornt[5];
4572       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
4573       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
4574 #if 1
4575       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);
4576       for (p = 0; p < 6; ++p) {
4577         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);
4578       }
4579 #endif
4580       /* F hex */
4581       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
4582       orntNew[0] = -4;
4583       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
4584       orntNew[1] = ornt[1];
4585       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
4586       orntNew[2] = ornt[2];
4587       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4588       orntNew[3] = -1;
4589       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
4590       orntNew[4] = ornt[4];
4591       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
4592       orntNew[5] = 1;
4593       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
4594       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
4595 #if 1
4596       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);
4597       for (p = 0; p < 6; ++p) {
4598         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);
4599       }
4600 #endif
4601       /* G hex */
4602       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
4603       orntNew[0] = -4;
4604       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
4605       orntNew[1] = ornt[1];
4606       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4607       orntNew[2] = 0;
4608       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
4609       orntNew[3] = ornt[3];
4610       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
4611       orntNew[4] = ornt[4];
4612       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
4613       orntNew[5] = -3;
4614       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
4615       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
4616 #if 1
4617       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);
4618       for (p = 0; p < 6; ++p) {
4619         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);
4620       }
4621 #endif
4622       /* H hex */
4623       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
4624       orntNew[0] = -4;
4625       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
4626       orntNew[1] = ornt[1];
4627       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
4628       orntNew[2] = -1;
4629       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
4630       orntNew[3] = ornt[3];
4631       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
4632       orntNew[4] = 3;
4633       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
4634       orntNew[5] = ornt[5];
4635       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
4636       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
4637 #if 1
4638       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);
4639       for (p = 0; p < 6; ++p) {
4640         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);
4641       }
4642 #endif
4643     }
4644     /* Hybrid cells have 6 faces: Front, Back, Sides */
4645     /*
4646      3---------2---------2
4647      |         |         |
4648      |    D    2    C    |
4649      |         |         |
4650      3----3----0----1----1
4651      |         |         |
4652      |    A    0    B    |
4653      |         |         |
4654      0---------0---------1
4655      */
4656     for (c = cMax; c < cEnd; ++c) {
4657       const PetscInt  newp = (cMax - cStart)*8 + (c - cMax)*4;
4658       const PetscInt *cone, *ornt, *fornt;
4659       PetscInt        coneNew[6], orntNew[6], o, of, i;
4660 
4661       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4662       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4663       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
4664       o = ornt[0] < 0 ? -1 : 1;
4665       for (r = 0; r < 4; ++r) {
4666         PetscInt subfA = GetQuadSubface_Static(ornt[0], r);
4667         PetscInt edgeA = GetQuadEdge_Static(ornt[0], r);
4668         PetscInt edgeB = GetQuadEdge_Static(ornt[0], (r+3)%4);
4669         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]);
4670         coneNew[0]         = fStartNew + (cone[0] - fStart)*4 + subfA;
4671         orntNew[0]         = ornt[0];
4672         coneNew[1]         = fStartNew + (cone[1] - fStart)*4 + subfA;
4673         orntNew[1]         = ornt[0];
4674         of = fornt[edgeA] < 0 ? -1 : 1;
4675         i  = GetQuadEdgeInverse_Static(ornt[0], r) + 2;
4676         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeA] - fMax)*2 + (o*of < 0 ? 1 : 0);
4677         orntNew[i] = ornt[edgeA];
4678         i  = GetQuadEdgeInverse_Static(ornt[0], (r+1)%4) + 2;
4679         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeA;
4680         orntNew[i] = 0;
4681         i  = GetQuadEdgeInverse_Static(ornt[0], (r+2)%4) + 2;
4682         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeB;
4683         orntNew[i] = -2;
4684         of = fornt[edgeB] < 0 ? -1 : 1;
4685         i  = GetQuadEdgeInverse_Static(ornt[0], (r+3)%4) + 2;
4686         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeB] - fMax)*2 + (o*of < 0 ? 0 : 1);
4687         orntNew[i] = ornt[edgeB];
4688         ierr       = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
4689         ierr       = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
4690 #if 1
4691         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);
4692         for (p = 0; p < 2; ++p) {
4693           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);
4694         }
4695         for (p = 2; p < 6; ++p) {
4696           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);
4697         }
4698 #endif
4699       }
4700     }
4701     /* Interior split faces have 4 edges and the same cells as the parent */
4702     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4703     ierr = PetscMalloc1((4 + maxSupportSize*2), &supportRef);CHKERRQ(ierr);
4704     for (f = fStart; f < fMax; ++f) {
4705       for (r = 0; r < 4; ++r) {
4706         /* TODO: This can come from GetFaces_Internal() */
4707         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};
4708         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
4709         const PetscInt *cone, *ornt, *support;
4710         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
4711 
4712         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4713         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4714         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
4715         orntNew[(r+3)%4] = ornt[(r+3)%4];
4716         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
4717         orntNew[(r+0)%4] = ornt[r];
4718         coneNew[(r+1)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
4719         orntNew[(r+1)%4] = 0;
4720         coneNew[(r+2)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + (r+3)%4;
4721         orntNew[(r+2)%4] = -2;
4722         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4723         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4724 #if 1
4725         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4726         for (p = 0; p < 4; ++p) {
4727           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
4728         }
4729 #endif
4730         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4731         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4732         for (s = 0; s < supportSize; ++s) {
4733           PetscInt subf;
4734           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4735           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4736           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4737           for (c = 0; c < coneSize; ++c) {
4738             if (cone[c] == f) break;
4739           }
4740           subf = GetQuadSubfaceInverse_Static(ornt[c], r);
4741           if (support[s] < cMax) {
4742             supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+subf];
4743           } else {
4744             supportRef[s] = cStartNew + (cMax       - cStart)*8 + (support[s] - cMax)*4 + subf;
4745           }
4746         }
4747         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4748 #if 1
4749         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4750         for (p = 0; p < supportSize; ++p) {
4751           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);
4752         }
4753 #endif
4754       }
4755     }
4756     /* Interior cell faces have 4 edges and 2 cells */
4757     for (c = cStart; c < cMax; ++c) {
4758       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};
4759       const PetscInt *cone, *ornt;
4760       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
4761 
4762       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4763       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4764       /* A-D face */
4765       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 0;
4766       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
4767       orntNew[0] = 0;
4768       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4769       orntNew[1] = 0;
4770       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4771       orntNew[2] = -2;
4772       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
4773       orntNew[3] = -2;
4774       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4775       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4776 #if 1
4777       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4778       for (p = 0; p < 4; ++p) {
4779         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);
4780       }
4781 #endif
4782       /* C-D face */
4783       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 1;
4784       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
4785       orntNew[0] = 0;
4786       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4787       orntNew[1] = 0;
4788       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4789       orntNew[2] = -2;
4790       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
4791       orntNew[3] = -2;
4792       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4793       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4794 #if 1
4795       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4796       for (p = 0; p < 4; ++p) {
4797         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);
4798       }
4799 #endif
4800       /* B-C face */
4801       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 2;
4802       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
4803       orntNew[0] = -2;
4804       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
4805       orntNew[1] = 0;
4806       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4807       orntNew[2] = 0;
4808       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4809       orntNew[3] = -2;
4810       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4811       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4812 #if 1
4813       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4814       for (p = 0; p < 4; ++p) {
4815         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);
4816       }
4817 #endif
4818       /* A-B face */
4819       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 3;
4820       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
4821       orntNew[0] = -2;
4822       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
4823       orntNew[1] = 0;
4824       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4825       orntNew[2] = 0;
4826       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4827       orntNew[3] = -2;
4828       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4829       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4830 #if 1
4831       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4832       for (p = 0; p < 4; ++p) {
4833         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);
4834       }
4835 #endif
4836       /* E-F face */
4837       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 4;
4838       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4839       orntNew[0] = -2;
4840       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
4841       orntNew[1] = -2;
4842       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
4843       orntNew[2] = 0;
4844       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4845       orntNew[3] = 0;
4846       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4847       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4848 #if 1
4849       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4850       for (p = 0; p < 4; ++p) {
4851         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);
4852       }
4853 #endif
4854       /* F-G face */
4855       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 5;
4856       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4857       orntNew[0] = -2;
4858       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
4859       orntNew[1] = -2;
4860       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
4861       orntNew[2] = 0;
4862       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4863       orntNew[3] = 0;
4864       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4865       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4866 #if 1
4867       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4868       for (p = 0; p < 4; ++p) {
4869         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);
4870       }
4871 #endif
4872       /* G-H face */
4873       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 6;
4874       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
4875       orntNew[0] = -2;
4876       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
4877       orntNew[1] = 0;
4878       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4879       orntNew[2] = 0;
4880       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4881       orntNew[3] = -2;
4882       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4883       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4884 #if 1
4885       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4886       for (p = 0; p < 4; ++p) {
4887         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);
4888       }
4889 #endif
4890       /* E-H face */
4891       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 7;
4892       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4893       orntNew[0] = -2;
4894       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
4895       orntNew[1] = -2;
4896       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
4897       orntNew[2] = 0;
4898       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4899       orntNew[3] = 0;
4900       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4901       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4902 #if 1
4903       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4904       for (p = 0; p < 4; ++p) {
4905         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);
4906       }
4907 #endif
4908       /* A-E face */
4909       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 8;
4910       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
4911       orntNew[0] = 0;
4912       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4913       orntNew[1] = 0;
4914       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4915       orntNew[2] = -2;
4916       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
4917       orntNew[3] = -2;
4918       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4919       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4920 #if 1
4921       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4922       for (p = 0; p < 4; ++p) {
4923         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);
4924       }
4925 #endif
4926       /* D-F face */
4927       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 9;
4928       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
4929       orntNew[0] = -2;
4930       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
4931       orntNew[1] = 0;
4932       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4933       orntNew[2] = 0;
4934       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4935       orntNew[3] = -2;
4936       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4937       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4938 #if 1
4939       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4940       for (p = 0; p < 4; ++p) {
4941         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);
4942       }
4943 #endif
4944       /* C-G face */
4945       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 10;
4946       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4947       orntNew[0] = -2;
4948       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
4949       orntNew[1] = -2;
4950       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
4951       orntNew[2] = 0;
4952       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4953       orntNew[3] = 0;
4954       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4955       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4956 #if 1
4957       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4958       for (p = 0; p < 4; ++p) {
4959         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);
4960       }
4961 #endif
4962       /* B-H face */
4963       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 11;
4964       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4965       orntNew[0] = 0;
4966       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4967       orntNew[1] = -2;
4968       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
4969       orntNew[2] = -2;
4970       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
4971       orntNew[3] = 0;
4972       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4973       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4974 #if 1
4975       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4976       for (p = 0; p < 4; ++p) {
4977         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);
4978       }
4979 #endif
4980       for (r = 0; r < 12; ++r) {
4981         newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
4982         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
4983         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
4984         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4985 #if 1
4986         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4987         for (p = 0; p < 2; ++p) {
4988           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);
4989         }
4990 #endif
4991       }
4992     }
4993     /* Hybrid split faces have 4 edges and same cells */
4994     for (f = fMax; f < fEnd; ++f) {
4995       const PetscInt *cone, *ornt, *support;
4996       PetscInt        coneNew[4], orntNew[4];
4997       PetscInt        supportNew[2], size, s, c;
4998 
4999       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5000       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
5001       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5002       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5003       for (r = 0; r < 2; ++r) {
5004         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
5005 
5006         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
5007         orntNew[0]   = ornt[0];
5008         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
5009         orntNew[1]   = ornt[1];
5010         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (cone[2+r] - eMax);
5011         orntNew[2+r] = 0;
5012         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd      - eMax) + (f - fMax);
5013         orntNew[3-r] = 0;
5014         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5015         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5016 #if 1
5017         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
5018         for (p = 0; p < 2; ++p) {
5019           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);
5020         }
5021         for (p = 2; p < 4; ++p) {
5022           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);
5023         }
5024 #endif
5025         for (s = 0; s < size; ++s) {
5026           const PetscInt *coneCell, *orntCell, *fornt;
5027           PetscInt        o, of;
5028 
5029           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
5030           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
5031           o = orntCell[0] < 0 ? -1 : 1;
5032           for (c = 2; c < 6; ++c) if (coneCell[c] == f) break;
5033           if (c >= 6) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
5034           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
5035           of = fornt[c-2] < 0 ? -1 : 1;
5036           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetQuadEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%4;
5037         }
5038         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5039 #if 1
5040         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
5041         for (p = 0; p < size; ++p) {
5042           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);
5043         }
5044 #endif
5045       }
5046     }
5047     /* Hybrid cell faces have 4 edges and 2 cells */
5048     for (c = cMax; c < cEnd; ++c) {
5049       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4;
5050       const PetscInt *cone, *ornt;
5051       PetscInt        coneNew[4], orntNew[4];
5052       PetscInt        supportNew[2];
5053 
5054       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5055       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5056       for (r = 0; r < 4; ++r) {
5057 #if 0
5058         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], r);
5059         orntNew[0] = 0;
5060         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], r);
5061         orntNew[1] = 0;
5062         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+GetQuadEdge_Static(ornt[0], r)] - fMax);
5063         orntNew[2] = 0;
5064         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd                                   - fMax) + (c - cMax);
5065         orntNew[3] = 0;
5066 #else
5067         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + r;
5068         orntNew[0] = 0;
5069         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + r;
5070         orntNew[1] = 0;
5071         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+r] - fMax);
5072         orntNew[2] = 0;
5073         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd      - fMax) + (c - cMax);
5074         orntNew[3] = 0;
5075 #endif
5076         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
5077         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
5078 #if 1
5079         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);
5080         for (p = 0; p < 2; ++p) {
5081           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);
5082         }
5083         for (p = 2; p < 4; ++p) {
5084           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);
5085         }
5086 #endif
5087         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], r);
5088         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], (r+1)%4);
5089         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
5090 #if 1
5091         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);
5092         for (p = 0; p < 2; ++p) {
5093           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);
5094         }
5095 #endif
5096       }
5097     }
5098     /* Interior split edges have 2 vertices and the same faces as the parent */
5099     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5100     for (e = eStart; e < eMax; ++e) {
5101       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
5102 
5103       for (r = 0; r < 2; ++r) {
5104         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
5105         const PetscInt *cone, *ornt, *support;
5106         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5107 
5108         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
5109         coneNew[0]       = vStartNew + (cone[0] - vStart);
5110         coneNew[1]       = vStartNew + (cone[1] - vStart);
5111         coneNew[(r+1)%2] = newv;
5112         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5113 #if 1
5114         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5115         for (p = 0; p < 2; ++p) {
5116           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);
5117         }
5118 #endif
5119         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
5120         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5121         for (s = 0; s < supportSize; ++s) {
5122           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5123           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5124           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5125           for (c = 0; c < coneSize; ++c) {
5126             if (cone[c] == e) break;
5127           }
5128           if (support[s] < fMax) {
5129             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%4;
5130           } else {
5131             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
5132           }
5133         }
5134         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5135 #if 1
5136         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5137         for (p = 0; p < supportSize; ++p) {
5138           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);
5139         }
5140 #endif
5141       }
5142     }
5143     /* Interior face edges have 2 vertices and 2+cells faces */
5144     for (f = fStart; f < fMax; ++f) {
5145       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};
5146       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
5147       const PetscInt *cone, *coneCell, *orntCell, *support;
5148       PetscInt        coneNew[2], coneSize, c, supportSize, s;
5149 
5150       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5151       for (r = 0; r < 4; ++r) {
5152         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
5153 
5154         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
5155         coneNew[1] = newv;
5156         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5157 #if 1
5158         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5159         for (p = 0; p < 2; ++p) {
5160           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);
5161         }
5162 #endif
5163         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5164         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5165         supportRef[0] = fStartNew + (f - fStart)*4 + r;
5166         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
5167         for (s = 0; s < supportSize; ++s) {
5168           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5169           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
5170           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
5171           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
5172           if (support[s] < cMax) {
5173             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
5174           } else {
5175             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + r;
5176           }
5177         }
5178         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5179 #if 1
5180         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5181         for (p = 0; p < 2+supportSize; ++p) {
5182           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);
5183         }
5184 #endif
5185       }
5186     }
5187     /* Interior cell edges have 2 vertices and 4 faces */
5188     for (c = cStart; c < cMax; ++c) {
5189       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};
5190       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
5191       const PetscInt *cone;
5192       PetscInt        coneNew[2], supportNew[4];
5193 
5194       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5195       for (r = 0; r < 6; ++r) {
5196         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
5197 
5198         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
5199         coneNew[1] = newv;
5200         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5201 #if 1
5202         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5203         for (p = 0; p < 2; ++p) {
5204           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);
5205         }
5206 #endif
5207         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
5208         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5209 #if 1
5210         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5211         for (p = 0; p < 4; ++p) {
5212           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);
5213         }
5214 #endif
5215       }
5216     }
5217     /* Hybrid edges have two vertices and the same faces */
5218     for (e = eMax; e < eEnd; ++e) {
5219       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
5220       const PetscInt *cone, *support, *fcone;
5221       PetscInt        coneNew[2], size, fsize, s;
5222 
5223       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
5224       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
5225       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5226       coneNew[0] = vStartNew + (cone[0] - vStart);
5227       coneNew[1] = vStartNew + (cone[1] - vStart);
5228       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5229 #if 1
5230       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5231       for (p = 0; p < 2; ++p) {
5232         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);
5233       }
5234 #endif
5235       for (s = 0; s < size; ++s) {
5236         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
5237         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
5238         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
5239         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
5240         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + c-2;
5241       }
5242       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5243 #if 1
5244       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5245       for (p = 0; p < size; ++p) {
5246         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);
5247       }
5248 #endif
5249     }
5250     /* Hybrid face edges have 2 vertices and 2+cells faces */
5251     for (f = fMax; f < fEnd; ++f) {
5252       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
5253       const PetscInt *cone, *support, *ccone, *cornt;
5254       PetscInt        coneNew[2], size, csize, s;
5255 
5256       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5257       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5258       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5259       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
5260       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
5261       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5262 #if 1
5263       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5264       for (p = 0; p < 2; ++p) {
5265         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);
5266       }
5267 #endif
5268       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 0;
5269       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 1;
5270       for (s = 0; s < size; ++s) {
5271         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
5272         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
5273         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
5274         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
5275         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]);
5276         supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + c-2;
5277       }
5278       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5279 #if 1
5280       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5281       for (p = 0; p < 2+size; ++p) {
5282         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);
5283       }
5284 #endif
5285     }
5286     /* Hybrid cell edges have 2 vertices and 4 faces */
5287     for (c = cMax; c < cEnd; ++c) {
5288       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
5289       const PetscInt *cone, *support;
5290       PetscInt        coneNew[2], size;
5291 
5292       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5293       ierr = DMPlexGetSupportSize(dm, c, &size);CHKERRQ(ierr);
5294       ierr = DMPlexGetSupport(dm, c, &support);CHKERRQ(ierr);
5295       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
5296       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
5297       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5298 #if 1
5299       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5300       for (p = 0; p < 2; ++p) {
5301         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);
5302       }
5303 #endif
5304       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 0;
5305       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 1;
5306       supportRef[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 2;
5307       supportRef[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 3;
5308       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5309 #if 1
5310       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5311       for (p = 0; p < 4; ++p) {
5312         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);
5313       }
5314 #endif
5315     }
5316     /* Interior vertices have identical supports */
5317     for (v = vStart; v < vEnd; ++v) {
5318       const PetscInt  newp = vStartNew + (v - vStart);
5319       const PetscInt *support, *cone;
5320       PetscInt        size, s;
5321 
5322       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5323       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5324       for (s = 0; s < size; ++s) {
5325         PetscInt r = 0;
5326 
5327         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5328         if (cone[1] == v) r = 1;
5329         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
5330         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (support[s] - eMax);
5331       }
5332       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5333 #if 1
5334       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5335       for (p = 0; p < size; ++p) {
5336         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);
5337       }
5338 #endif
5339     }
5340     /* Interior edge vertices have 2 + faces supports */
5341     for (e = eStart; e < eMax; ++e) {
5342       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
5343       const PetscInt *cone, *support;
5344       PetscInt        size, s;
5345 
5346       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
5347       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5348       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
5349       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
5350       for (s = 0; s < size; ++s) {
5351         PetscInt r;
5352 
5353         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5354         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
5355         if (support[s] < fMax) {
5356           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*4 + r;
5357         } else {
5358           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (support[s] - fMax);
5359         }
5360       }
5361       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5362 #if 1
5363       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5364       for (p = 0; p < 2+size; ++p) {
5365         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);
5366       }
5367 #endif
5368     }
5369     /* Interior face vertices have 4 + cells supports */
5370     for (f = fStart; f < fMax; ++f) {
5371       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
5372       const PetscInt *cone, *support;
5373       PetscInt        size, s;
5374 
5375       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5376       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5377       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eMax - eStart)*2 +  (f - fStart)*4 + r;
5378       for (s = 0; s < size; ++s) {
5379         PetscInt r;
5380 
5381         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5382         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
5383         if (support[s] < cMax) {
5384           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (support[s] - cStart)*6 + r;
5385         } else {
5386           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax       - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (support[s] - cMax);
5387         }
5388       }
5389       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5390 #if 1
5391       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5392       for (p = 0; p < 4+size; ++p) {
5393         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);
5394       }
5395 #endif
5396     }
5397     /* Cell vertices have 6 supports */
5398     for (c = cStart; c < cMax; ++c) {
5399       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
5400       PetscInt       supportNew[6];
5401 
5402       for (r = 0; r < 6; ++r) {
5403         supportNew[r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
5404       }
5405       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5406     }
5407     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5408     break;
5409   default:
5410     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5411   }
5412   PetscFunctionReturn(0);
5413 }
5414 
5415 #undef __FUNCT__
5416 #define __FUNCT__ "CellRefinerSetCoordinates"
5417 static PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5418 {
5419   PetscSection   coordSection, coordSectionNew;
5420   Vec            coordinates, coordinatesNew;
5421   PetscScalar   *coords, *coordsNew;
5422   const PetscInt numVertices = depthSize ? depthSize[0] : 0;
5423   PetscInt       spaceDim, depth, bs, coordSizeNew, cStart, cEnd, cMax, c, vStart, vStartNew, vEnd, v, eStart, eEnd, eMax, e, fStart, fEnd, fMax, f;
5424   PetscErrorCode ierr;
5425 
5426   PetscFunctionBegin;
5427   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5428   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5429   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5430   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5431   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5432   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, NULL);CHKERRQ(ierr);
5433   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);}
5434   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
5435   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5436   ierr = PetscSectionGetFieldComponents(coordSection, 0, &spaceDim);CHKERRQ(ierr);
5437   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
5438   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
5439   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, spaceDim);CHKERRQ(ierr);
5440   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+numVertices);CHKERRQ(ierr);
5441   if (cMax < 0) cMax = cEnd;
5442   if (fMax < 0) fMax = fEnd;
5443   if (eMax < 0) eMax = eEnd;
5444   /* All vertices have the spaceDim coordinates */
5445   for (v = vStartNew; v < vStartNew+numVertices; ++v) {
5446     ierr = PetscSectionSetDof(coordSectionNew, v, spaceDim);CHKERRQ(ierr);
5447     ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, spaceDim);CHKERRQ(ierr);
5448   }
5449   ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
5450   ierr = DMSetCoordinateSection(rdm, PETSC_DETERMINE, coordSectionNew);CHKERRQ(ierr);
5451   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5452   ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
5453   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);CHKERRQ(ierr);
5454   ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
5455   ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
5456   ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr);
5457   ierr = VecSetBlockSize(coordinatesNew, bs);CHKERRQ(ierr);
5458   ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
5459   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
5460   ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5461   switch (refiner) {
5462   case 0: break;
5463   case 6: /* Hex 3D */
5464   case 8: /* Hybrid Hex 3D */
5465     /* Face vertices have the average of corner coordinates */
5466     for (f = fStart; f < fMax; ++f) {
5467       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
5468       PetscInt      *cone = NULL;
5469       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
5470 
5471       ierr = DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5472       for (p = 0; p < closureSize*2; p += 2) {
5473         const PetscInt point = cone[p];
5474         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
5475       }
5476       for (v = 0; v < coneSize; ++v) {
5477         ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
5478       }
5479       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5480       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
5481       for (v = 0; v < coneSize; ++v) {ierr = DMPlexLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);CHKERRQ(ierr);}
5482       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
5483       ierr = DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5484     }
5485   case 2: /* Hex 2D */
5486   case 4: /* Hybrid Hex 2D */
5487     /* Cell vertices have the average of corner coordinates */
5488     for (c = cStart; c < cMax; ++c) {
5489       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (c - cStart) + (spaceDim > 2 ? (fMax - fStart) : 0);
5490       PetscInt      *cone = NULL;
5491       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
5492 
5493       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5494       for (p = 0; p < closureSize*2; p += 2) {
5495         const PetscInt point = cone[p];
5496         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
5497       }
5498       for (v = 0; v < coneSize; ++v) {
5499         ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
5500       }
5501       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5502       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
5503       for (v = 0; v < coneSize; ++v) {ierr = DMPlexLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);CHKERRQ(ierr);}
5504       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
5505       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5506     }
5507   case 1: /* Simplicial 2D */
5508   case 3: /* Hybrid Simplicial 2D */
5509   case 5: /* Simplicial 3D */
5510   case 7: /* Hybrid Simplicial 3D */
5511     /* Edge vertices have the average of endpoint coordinates */
5512     for (e = eStart; e < eMax; ++e) {
5513       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
5514       const PetscInt *cone;
5515       PetscInt        coneSize, offA, offB, offnew, d;
5516 
5517       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
5518       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
5519       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
5520       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
5521       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
5522       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5523       ierr = DMPlexLocalizeCoordinate_Internal(dm, spaceDim, &coords[offA], &coords[offB], &coordsNew[offnew]);CHKERRQ(ierr);
5524       for (d = 0; d < spaceDim; ++d) {
5525         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coordsNew[offnew+d]);
5526       }
5527     }
5528     /* Old vertices have the same coordinates */
5529     for (v = vStart; v < vEnd; ++v) {
5530       const PetscInt newv = vStartNew + (v - vStart);
5531       PetscInt       off, offnew, d;
5532 
5533       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5534       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5535       for (d = 0; d < spaceDim; ++d) {
5536         coordsNew[offnew+d] = coords[off+d];
5537       }
5538     }
5539     break;
5540   default:
5541     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5542   }
5543   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
5544   ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5545   ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
5546   ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
5547   ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
5548   if (dm->maxCell) {
5549     const PetscReal *maxCell, *L;
5550     ierr = DMGetPeriodicity(dm,  &maxCell, &L);CHKERRQ(ierr);
5551     ierr = DMSetPeriodicity(rdm,  maxCell,  L);CHKERRQ(ierr);
5552   }
5553   PetscFunctionReturn(0);
5554 }
5555 
5556 #undef __FUNCT__
5557 #define __FUNCT__ "DMPlexCreateProcessSF"
5558 /*@
5559   DMPlexCreateProcessSF - Create an SF which just has process connectivity
5560 
5561   Collective on DM
5562 
5563   Input Parameters:
5564 + dm      - The DM
5565 - sfPoint - The PetscSF which encodes point connectivity
5566 
5567   Output Parameters:
5568 + processRanks - A list of process neighbors, or NULL
5569 - sfProcess    - An SF encoding the process connectivity, or NULL
5570 
5571   Level: developer
5572 
5573 .seealso: PetscSFCreate(), DMPlexCreateTwoSidedProcessSF()
5574 @*/
5575 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
5576 {
5577   PetscInt           numRoots, numLeaves, l;
5578   const PetscInt    *localPoints;
5579   const PetscSFNode *remotePoints;
5580   PetscInt          *localPointsNew;
5581   PetscSFNode       *remotePointsNew;
5582   PetscInt          *ranks, *ranksNew;
5583   PetscMPIInt        numProcs;
5584   PetscErrorCode     ierr;
5585 
5586   PetscFunctionBegin;
5587   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5588   PetscValidHeaderSpecific(sfPoint, PETSCSF_CLASSID, 2);
5589   if (processRanks) {PetscValidPointer(processRanks, 3);}
5590   if (sfProcess)    {PetscValidPointer(sfProcess, 4);}
5591   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) dm), &numProcs);CHKERRQ(ierr);
5592   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5593   ierr = PetscMalloc1(numLeaves, &ranks);CHKERRQ(ierr);
5594   for (l = 0; l < numLeaves; ++l) {
5595     ranks[l] = remotePoints[l].rank;
5596   }
5597   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
5598   ierr = PetscMalloc1(numLeaves, &ranksNew);CHKERRQ(ierr);
5599   ierr = PetscMalloc1(numLeaves, &localPointsNew);CHKERRQ(ierr);
5600   ierr = PetscMalloc1(numLeaves, &remotePointsNew);CHKERRQ(ierr);
5601   for (l = 0; l < numLeaves; ++l) {
5602     ranksNew[l]              = ranks[l];
5603     localPointsNew[l]        = l;
5604     remotePointsNew[l].index = 0;
5605     remotePointsNew[l].rank  = ranksNew[l];
5606   }
5607   ierr = PetscFree(ranks);CHKERRQ(ierr);
5608   if (processRanks) {ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);}
5609   else              {ierr = PetscFree(ranksNew);CHKERRQ(ierr);}
5610   if (sfProcess) {
5611     ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
5612     ierr = PetscObjectSetName((PetscObject) *sfProcess, "Process SF");CHKERRQ(ierr);
5613     ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
5614     ierr = PetscSFSetGraph(*sfProcess, numProcs, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
5615   }
5616   PetscFunctionReturn(0);
5617 }
5618 
5619 #undef __FUNCT__
5620 #define __FUNCT__ "CellRefinerCreateSF"
5621 static PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5622 {
5623   PetscSF            sf, sfNew, sfProcess;
5624   IS                 processRanks;
5625   MPI_Datatype       depthType;
5626   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
5627   const PetscInt    *localPoints, *neighbors;
5628   const PetscSFNode *remotePoints;
5629   PetscInt          *localPointsNew;
5630   PetscSFNode       *remotePointsNew;
5631   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
5632   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r, n;
5633   PetscInt           cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
5634   PetscErrorCode     ierr;
5635 
5636   PetscFunctionBegin;
5637   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
5638   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5639   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5640   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5641   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5642   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5643   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5644   cMax = cMax < 0 ? cEnd : cMax;
5645   fMax = fMax < 0 ? fEnd : fMax;
5646   eMax = eMax < 0 ? eEnd : eMax;
5647   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
5648   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
5649   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
5650   /* Calculate size of new SF */
5651   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5652   if (numRoots < 0) PetscFunctionReturn(0);
5653   for (l = 0; l < numLeaves; ++l) {
5654     const PetscInt p = localPoints[l];
5655 
5656     switch (refiner) {
5657     case 1:
5658     case 3:
5659       /* Hybrid Simplicial 2D */
5660       if ((p >= vStart) && (p < vEnd)) {
5661         /* Interior vertices stay the same */
5662         ++numLeavesNew;
5663       } else if ((p >= fStart) && (p < fMax)) {
5664         /* Interior faces add new faces and vertex */
5665         numLeavesNew += 2 + 1;
5666       } else if ((p >= fMax) && (p < fEnd)) {
5667         /* Hybrid faces stay the same */
5668         ++numLeavesNew;
5669       } else if ((p >= cStart) && (p < cMax)) {
5670         /* Interior cells add new cells and interior faces */
5671         numLeavesNew += 4 + 3;
5672       } else if ((p >= cMax) && (p < cEnd)) {
5673         /* Hybrid cells add new cells and hybrid face */
5674         numLeavesNew += 2 + 1;
5675       }
5676       break;
5677     case 2:
5678     case 4:
5679       /* Hybrid Hex 2D */
5680       if ((p >= vStart) && (p < vEnd)) {
5681         /* Interior vertices stay the same */
5682         ++numLeavesNew;
5683       } else if ((p >= fStart) && (p < fMax)) {
5684         /* Interior faces add new faces and vertex */
5685         numLeavesNew += 2 + 1;
5686       } else if ((p >= fMax) && (p < fEnd)) {
5687         /* Hybrid faces stay the same */
5688         ++numLeavesNew;
5689       } else if ((p >= cStart) && (p < cMax)) {
5690         /* Interior cells add new cells, interior faces, and vertex */
5691         numLeavesNew += 4 + 4 + 1;
5692       } else if ((p >= cMax) && (p < cEnd)) {
5693         /* Hybrid cells add new cells and hybrid face */
5694         numLeavesNew += 2 + 1;
5695       }
5696       break;
5697     case 5:
5698     case 7:
5699       /* Hybrid Simplicial 3D */
5700       if ((p >= vStart) && (p < vEnd)) {
5701         /* Interior vertices stay the same */
5702         ++numLeavesNew;
5703       } else if ((p >= eStart) && (p < eMax)) {
5704         /* Interior edges add new edges and vertex */
5705         numLeavesNew += 2 + 1;
5706       } else if ((p >= eMax) && (p < eEnd)) {
5707         /* Hybrid edges stay the same */
5708         ++numLeavesNew;
5709       } else if ((p >= fStart) && (p < fMax)) {
5710         /* Interior faces add new faces and edges */
5711         numLeavesNew += 4 + 3;
5712       } else if ((p >= fMax) && (p < fEnd)) {
5713         /* Hybrid faces add new faces and edges */
5714         numLeavesNew += 2 + 1;
5715       } else if ((p >= cStart) && (p < cMax)) {
5716         /* Interior cells add new cells, faces, and edges */
5717         numLeavesNew += 8 + 8 + 1;
5718       } else if ((p >= cMax) && (p < cEnd)) {
5719         /* Hybrid cells add new cells and faces */
5720         numLeavesNew += 4 + 3;
5721       }
5722       break;
5723     case 6:
5724     case 8:
5725       /* Hybrid Hex 3D */
5726       if ((p >= vStart) && (p < vEnd)) {
5727         /* Old vertices stay the same */
5728         ++numLeavesNew;
5729       } else if ((p >= eStart) && (p < eMax)) {
5730         /* Interior edges add new edges, and vertex */
5731         numLeavesNew += 2 + 1;
5732       } else if ((p >= eMax) && (p < eEnd)) {
5733         /* Hybrid edges stay the same */
5734         ++numLeavesNew;
5735       } else if ((p >= fStart) && (p < fMax)) {
5736         /* Interior faces add new faces, edges, and vertex */
5737         numLeavesNew += 4 + 4 + 1;
5738       } else if ((p >= fMax) && (p < fEnd)) {
5739         /* Hybrid faces add new faces and edges */
5740         numLeavesNew += 2 + 1;
5741       } else if ((p >= cStart) && (p < cMax)) {
5742         /* Interior cells add new cells, faces, edges, and vertex */
5743         numLeavesNew += 8 + 12 + 6 + 1;
5744       } else if ((p >= cStart) && (p < cEnd)) {
5745         /* Hybrid cells add new cells, faces, and edges */
5746         numLeavesNew += 4 + 4 + 1;
5747       }
5748       break;
5749     default:
5750       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5751     }
5752   }
5753   /* Communicate depthSizes for each remote rank */
5754   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
5755   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
5756   ierr = PetscMalloc5((depth+1)*numNeighbors,&rdepthSize,numNeighbors,&rvStartNew,numNeighbors,&reStartNew,numNeighbors,&rfStartNew,numNeighbors,&rcStartNew);CHKERRQ(ierr);
5757   ierr = PetscMalloc7(depth+1,&depthSizeOld,(depth+1)*numNeighbors,&rdepthSizeOld,(depth+1)*numNeighbors,&rdepthMaxOld,numNeighbors,&rvStart,numNeighbors,&reStart,numNeighbors,&rfStart,numNeighbors,&rcStart);CHKERRQ(ierr);
5758   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
5759   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
5760   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5761   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5762   for (n = 0; n < numNeighbors; ++n) {
5763     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
5764   }
5765   depthSizeOld[depth]   = cMax;
5766   depthSizeOld[0]       = vMax;
5767   depthSizeOld[depth-1] = fMax;
5768   depthSizeOld[1]       = eMax;
5769 
5770   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5771   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5772 
5773   depthSizeOld[depth]   = cEnd - cStart;
5774   depthSizeOld[0]       = vEnd - vStart;
5775   depthSizeOld[depth-1] = fEnd - fStart;
5776   depthSizeOld[1]       = eEnd - eStart;
5777 
5778   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5779   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5780   for (n = 0; n < numNeighbors; ++n) {
5781     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
5782     rdepthMaxOld[n*(depth+1)+depth]   = rdepthMaxOld[n*(depth+1)+depth]   < 0 ? rdepthSizeOld[n*(depth+1)+depth]  +rcStart[n]: rdepthMaxOld[n*(depth+1)+depth];
5783     rdepthMaxOld[n*(depth+1)+depth-1] = rdepthMaxOld[n*(depth+1)+depth-1] < 0 ? rdepthSizeOld[n*(depth+1)+depth-1]+rfStart[n]: rdepthMaxOld[n*(depth+1)+depth-1];
5784     rdepthMaxOld[n*(depth+1)+1]       = rdepthMaxOld[n*(depth+1)+1]       < 0 ? rdepthSizeOld[n*(depth+1)+1]      +reStart[n]: rdepthMaxOld[n*(depth+1)+1];
5785   }
5786   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
5787   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
5788   /* Calculate new point SF */
5789   ierr = PetscMalloc1(numLeavesNew, &localPointsNew);CHKERRQ(ierr);
5790   ierr = PetscMalloc1(numLeavesNew, &remotePointsNew);CHKERRQ(ierr);
5791   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
5792   for (l = 0, m = 0; l < numLeaves; ++l) {
5793     PetscInt    p     = localPoints[l];
5794     PetscInt    rp    = remotePoints[l].index, n;
5795     PetscMPIInt rrank = remotePoints[l].rank;
5796 
5797     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
5798     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
5799     switch (refiner) {
5800     case 1:
5801     case 3:
5802       /* Hybrid simplicial 2D */
5803       if ((p >= vStart) && (p < vEnd)) {
5804         /* Old vertices stay the same */
5805         localPointsNew[m]        = vStartNew     + (p  - vStart);
5806         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5807         remotePointsNew[m].rank  = rrank;
5808         ++m;
5809       } else if ((p >= fStart) && (p < fMax)) {
5810         /* Old interior faces add new faces and vertex */
5811         for (r = 0; r < 2; ++r, ++m) {
5812           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5813           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5814           remotePointsNew[m].rank  = rrank;
5815         }
5816         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5817         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5818         remotePointsNew[m].rank  = rrank;
5819         ++m;
5820       } else if ((p >= fMax) && (p < fEnd)) {
5821         /* Old hybrid faces stay the same */
5822         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
5823         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
5824         remotePointsNew[m].rank  = rrank;
5825         ++m;
5826       } else if ((p >= cStart) && (p < cMax)) {
5827         /* Old interior cells add new cells and interior faces */
5828         for (r = 0; r < 4; ++r, ++m) {
5829           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5830           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5831           remotePointsNew[m].rank  = rrank;
5832         }
5833         for (r = 0; r < 3; ++r, ++m) {
5834           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
5835           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
5836           remotePointsNew[m].rank  = rrank;
5837         }
5838       } else if ((p >= cMax) && (p < cEnd)) {
5839         /* Old hybrid cells add new cells and hybrid face */
5840         for (r = 0; r < 2; ++r, ++m) {
5841           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5842           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5843           remotePointsNew[m].rank  = rrank;
5844         }
5845         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
5846         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]);
5847         remotePointsNew[m].rank  = rrank;
5848         ++m;
5849       }
5850       break;
5851     case 2:
5852     case 4:
5853       /* Hybrid Hex 2D */
5854       if ((p >= vStart) && (p < vEnd)) {
5855         /* Old vertices stay the same */
5856         localPointsNew[m]        = vStartNew     + (p  - vStart);
5857         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5858         remotePointsNew[m].rank  = rrank;
5859         ++m;
5860       } else if ((p >= fStart) && (p < fMax)) {
5861         /* Old interior faces add new faces and vertex */
5862         for (r = 0; r < 2; ++r, ++m) {
5863           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5864           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5865           remotePointsNew[m].rank  = rrank;
5866         }
5867         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5868         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5869         remotePointsNew[m].rank  = rrank;
5870         ++m;
5871       } else if ((p >= fMax) && (p < fEnd)) {
5872         /* Old hybrid faces stay the same */
5873         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
5874         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
5875         remotePointsNew[m].rank  = rrank;
5876         ++m;
5877       } else if ((p >= cStart) && (p < cMax)) {
5878         /* Old interior cells add new cells, interior faces, and vertex */
5879         for (r = 0; r < 4; ++r, ++m) {
5880           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5881           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5882           remotePointsNew[m].rank  = rrank;
5883         }
5884         for (r = 0; r < 4; ++r, ++m) {
5885           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*4     + r;
5886           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*4 + r;
5887           remotePointsNew[m].rank  = rrank;
5888         }
5889         localPointsNew[m]        = vStartNew     + (vEnd - vStart)               + (fMax                              - fStart)     + (p  - cStart);
5890         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0]  + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]);
5891         remotePointsNew[m].rank  = rrank;
5892         ++m;
5893       } else if ((p >= cStart) && (p < cMax)) {
5894         /* Old hybrid cells add new cells and hybrid face */
5895         for (r = 0; r < 2; ++r, ++m) {
5896           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5897           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5898           remotePointsNew[m].rank  = rrank;
5899         }
5900         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*4     + (p  - cMax);
5901         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*4 + (rp - rdepthMaxOld[n*(depth+1)+depth]);
5902         remotePointsNew[m].rank  = rrank;
5903         ++m;
5904       }
5905       break;
5906     case 5:
5907     case 7:
5908       /* Hybrid Simplicial 3D */
5909       if ((p >= vStart) && (p < vEnd)) {
5910         /* Interior vertices stay the same */
5911         localPointsNew[m]        = vStartNew     + (p  - vStart);
5912         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5913         remotePointsNew[m].rank  = rrank;
5914         ++m;
5915       } else if ((p >= eStart) && (p < eMax)) {
5916         /* Interior edges add new edges and vertex */
5917         for (r = 0; r < 2; ++r, ++m) {
5918           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
5919           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
5920           remotePointsNew[m].rank  = rrank;
5921         }
5922         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
5923         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
5924         remotePointsNew[m].rank  = rrank;
5925         ++m;
5926       } else if ((p >= eMax) && (p < eEnd)) {
5927         /* Hybrid edges stay the same */
5928         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - eMax);
5929         remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*3 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n]) + (rp - rdepthMaxOld[n*(depth+1)+1]);
5930         remotePointsNew[m].rank  = rrank;
5931         ++m;
5932       } else if ((p >= fStart) && (p < fMax)) {
5933         /* Interior faces add new faces and edges */
5934         for (r = 0; r < 4; ++r, ++m) {
5935           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
5936           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
5937           remotePointsNew[m].rank  = rrank;
5938         }
5939         for (r = 0; r < 3; ++r, ++m) {
5940           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*3     + r;
5941           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
5942           remotePointsNew[m].rank  = rrank;
5943         }
5944       } else if ((p >= fMax) && (p < fEnd)) {
5945         /* Hybrid faces add new faces and edges */
5946         for (r = 0; r < 2; ++r, ++m) {
5947           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fMax)*2                              + r;
5948           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;
5949           remotePointsNew[m].rank  = rrank;
5950         }
5951         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (eEnd                                    - eMax)                        + (p  - fMax);
5952         remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*3 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n]) + (rdepthSizeOld[n*(depth+1)+1]+reStart[n] - rdepthMaxOld[n*(depth+1)+1]) + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
5953         remotePointsNew[m].rank  = rrank;
5954         ++m;
5955       } else if ((p >= cStart) && (p < cMax)) {
5956         /* Interior cells add new cells, faces, and edges */
5957         for (r = 0; r < 8; ++r, ++m) {
5958           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
5959           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
5960           remotePointsNew[m].rank  = rrank;
5961         }
5962         for (r = 0; r < 8; ++r, ++m) {
5963           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*8     + r;
5964           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*8 + r;
5965           remotePointsNew[m].rank  = rrank;
5966         }
5967         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (p  - cStart)*1     + 0;
5968         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 + 0;
5969         remotePointsNew[m].rank  = rrank;
5970         ++m;
5971       } else if ((p >= cMax) && (p < cEnd)) {
5972         /* Hybrid cells add new cells and faces */
5973         for (r = 0; r < 4; ++r, ++m) {
5974           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
5975           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
5976           remotePointsNew[m].rank  = rrank;
5977         }
5978         for (r = 0; r < 3; ++r, ++m) {
5979           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*2                              + (p  - cMax)*3                            + r;
5980           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;
5981           remotePointsNew[m].rank  = rrank;
5982         }
5983       }
5984       break;
5985     case 6:
5986     case 8:
5987       /* Hybrid Hex 3D */
5988       if ((p >= vStart) && (p < vEnd)) {
5989         /* Interior vertices stay the same */
5990         localPointsNew[m]        = vStartNew     + (p  - vStart);
5991         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5992         remotePointsNew[m].rank  = rrank;
5993         ++m;
5994       } else if ((p >= eStart) && (p < eMax)) {
5995         /* Interior edges add new edges and vertex */
5996         for (r = 0; r < 2; ++r, ++m) {
5997           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
5998           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
5999           remotePointsNew[m].rank  = rrank;
6000         }
6001         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
6002         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
6003         remotePointsNew[m].rank  = rrank;
6004         ++m;
6005       } else if ((p >= eMax) && (p < eEnd)) {
6006         /* Hybrid edges stay the same */
6007         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (p  - eMax);
6008         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 + (rp - rdepthMaxOld[n*(depth+1)+1]);
6009         remotePointsNew[m].rank  = rrank;
6010         ++m;
6011       } else if ((p >= fStart) && (p < fMax)) {
6012         /* Interior faces add new faces, edges, and vertex */
6013         for (r = 0; r < 4; ++r, ++m) {
6014           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
6015           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
6016           remotePointsNew[m].rank  = rrank;
6017         }
6018         for (r = 0; r < 4; ++r, ++m) {
6019           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*4     + r;
6020           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*4 + r;
6021           remotePointsNew[m].rank  = rrank;
6022         }
6023         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax                        - eStart)     + (p  - fStart);
6024         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
6025         remotePointsNew[m].rank  = rrank;
6026         ++m;
6027       } else if ((p >= fMax) && (p < fEnd)) {
6028         /* Hybrid faces add new faces and edges */
6029         for (r = 0; r < 2; ++r, ++m) {
6030           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (p  - fMax)*2                              + r;
6031           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*12 + (rp - rdepthMaxOld[n*(depth+1)+depth-1])*2 + r;
6032           remotePointsNew[m].rank  = rrank;
6033         }
6034         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (p  - fMax);
6035         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)+1]+reStart[n] - rdepthMaxOld[n*(depth+1)+1]) + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
6036         remotePointsNew[m].rank  = rrank;
6037         ++m;
6038       } else if ((p >= cStart) && (p < cMax)) {
6039         /* Interior cells add new cells, faces, edges, and vertex */
6040         for (r = 0; r < 8; ++r, ++m) {
6041           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
6042           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
6043           remotePointsNew[m].rank  = rrank;
6044         }
6045         for (r = 0; r < 12; ++r, ++m) {
6046           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*12     + r;
6047           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*12 + r;
6048           remotePointsNew[m].rank  = rrank;
6049         }
6050         for (r = 0; r < 6; ++r, ++m) {
6051           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (p  - cStart)*6     + r;
6052           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;
6053           remotePointsNew[m].rank  = rrank;
6054         }
6055         for (r = 0; r < 1; ++r, ++m) {
6056           localPointsNew[m]        = vStartNew     + (eMax                        - eStart)     + (fMax                              - fStart)     + (p  - cStart)     + r;
6057           remotePointsNew[m].index = rvStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]) + r;
6058           remotePointsNew[m].rank  = rrank;
6059         }
6060       } else if ((p >= cMax) && (p < cEnd)) {
6061         /* Hybrid cells add new cells, faces, and edges */
6062         for (r = 0; r < 4; ++r, ++m) {
6063           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
6064           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
6065           remotePointsNew[m].rank  = rrank;
6066         }
6067         for (r = 0; r < 4; ++r, ++m) {
6068           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (fEnd                                          - fMax)*2                              + (p  - cMax)*4                            + r;
6069           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*12 + (rdepthSizeOld[n*(depth+1)+depth-1]+rfStart[n] - rdepthMaxOld[n*(depth+1)+depth-1])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
6070           remotePointsNew[m].rank  = rrank;
6071         }
6072         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (fEnd                                          - fMax)                              + (p  - cMax);
6073         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)+1]+reStart[n] - rdepthMaxOld[n*(depth+1)+1]) + (rdepthSizeOld[n*(depth+1)+depth-1]+rfStart[n] - rdepthMaxOld[n*(depth+1)+depth-1]) + (rp - rdepthMaxOld[n*(depth+1)+depth]);
6074         remotePointsNew[m].rank  = rrank;
6075         ++m;
6076       }
6077       break;
6078     default:
6079       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6080     }
6081   }
6082   if (m != numLeavesNew) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of leaf point %d should be %d", m, numLeavesNew);
6083   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
6084   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
6085   {
6086     PetscSFNode *rp, *rtmp;
6087     PetscInt    *lp, *idx, *ltmp, i;
6088 
6089     /* SF needs sorted leaves to correct calculate Gather */
6090     ierr = PetscMalloc1(numLeavesNew,&idx);CHKERRQ(ierr);
6091     ierr = PetscMalloc1(numLeavesNew, &lp);CHKERRQ(ierr);
6092     ierr = PetscMalloc1(numLeavesNew, &rp);CHKERRQ(ierr);
6093     for (i = 0; i < numLeavesNew; ++i) {
6094       if ((localPointsNew[i] < pStartNew) || (localPointsNew[i] >= pEndNew)) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Local SF point %d (%d) not in [%d, %d)", localPointsNew[i], i, pStartNew, pEndNew);
6095       idx[i] = i;
6096     }
6097     ierr = PetscSortIntWithPermutation(numLeavesNew, localPointsNew, idx);CHKERRQ(ierr);
6098     for (i = 0; i < numLeavesNew; ++i) {
6099       lp[i] = localPointsNew[idx[i]];
6100       rp[i] = remotePointsNew[idx[i]];
6101     }
6102     ltmp            = localPointsNew;
6103     localPointsNew  = lp;
6104     rtmp            = remotePointsNew;
6105     remotePointsNew = rp;
6106     ierr = PetscFree(idx);CHKERRQ(ierr);
6107     ierr = PetscFree(ltmp);CHKERRQ(ierr);
6108     ierr = PetscFree(rtmp);CHKERRQ(ierr);
6109   }
6110   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6111   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
6112   ierr = PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
6113   PetscFunctionReturn(0);
6114 }
6115 
6116 #undef __FUNCT__
6117 #define __FUNCT__ "CellRefinerCreateLabels"
6118 static PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6119 {
6120   PetscInt       numLabels, l;
6121   PetscInt       depth, newp, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r;
6122   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
6123   PetscErrorCode ierr;
6124 
6125   PetscFunctionBegin;
6126   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6127   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6128   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6129   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6130   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6131   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
6132   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
6133   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6134   switch (refiner) {
6135   case 0: break;
6136   case 7:
6137   case 8:
6138     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
6139   case 3:
6140   case 4:
6141     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6142     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6143   }
6144   for (l = 0; l < numLabels; ++l) {
6145     DMLabel         label, labelNew;
6146     const char     *lname;
6147     PetscBool       isDepth;
6148     IS              valueIS;
6149     const PetscInt *values;
6150     PetscInt        numValues, val;
6151 
6152     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
6153     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
6154     if (isDepth) continue;
6155     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
6156     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
6157     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
6158     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
6159     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
6160     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
6161     for (val = 0; val < numValues; ++val) {
6162       IS              pointIS;
6163       const PetscInt *points;
6164       PetscInt        numPoints, n;
6165 
6166       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
6167       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
6168       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
6169       for (n = 0; n < numPoints; ++n) {
6170         const PetscInt p = points[n];
6171         switch (refiner) {
6172         case 1:
6173           /* Simplicial 2D */
6174           if ((p >= vStart) && (p < vEnd)) {
6175             /* Old vertices stay the same */
6176             newp = vStartNew + (p - vStart);
6177             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6178           } else if ((p >= fStart) && (p < fEnd)) {
6179             /* Old faces add new faces and vertex */
6180             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6181             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6182             for (r = 0; r < 2; ++r) {
6183               newp = fStartNew + (p - fStart)*2 + r;
6184               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6185             }
6186           } else if ((p >= cStart) && (p < cEnd)) {
6187             /* Old cells add new cells and interior faces */
6188             for (r = 0; r < 4; ++r) {
6189               newp = cStartNew + (p - cStart)*4 + r;
6190               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6191             }
6192             for (r = 0; r < 3; ++r) {
6193               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6194               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6195             }
6196           }
6197           break;
6198         case 2:
6199           /* Hex 2D */
6200           if ((p >= vStart) && (p < vEnd)) {
6201             /* Old vertices stay the same */
6202             newp = vStartNew + (p - vStart);
6203             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6204           } else if ((p >= fStart) && (p < fEnd)) {
6205             /* Old faces add new faces and vertex */
6206             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6207             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6208             for (r = 0; r < 2; ++r) {
6209               newp = fStartNew + (p - fStart)*2 + r;
6210               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6211             }
6212           } else if ((p >= cStart) && (p < cEnd)) {
6213             /* Old cells add new cells and interior faces and vertex */
6214             for (r = 0; r < 4; ++r) {
6215               newp = cStartNew + (p - cStart)*4 + r;
6216               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6217             }
6218             for (r = 0; r < 4; ++r) {
6219               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
6220               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6221             }
6222             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
6223             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6224           }
6225           break;
6226         case 3:
6227           /* Hybrid simplicial 2D */
6228           if ((p >= vStart) && (p < vEnd)) {
6229             /* Old vertices stay the same */
6230             newp = vStartNew + (p - vStart);
6231             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6232           } else if ((p >= fStart) && (p < fMax)) {
6233             /* Old interior faces add new faces and vertex */
6234             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6235             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6236             for (r = 0; r < 2; ++r) {
6237               newp = fStartNew + (p - fStart)*2 + r;
6238               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6239             }
6240           } else if ((p >= fMax) && (p < fEnd)) {
6241             /* Old hybrid faces stay the same */
6242             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
6243             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6244           } else if ((p >= cStart) && (p < cMax)) {
6245             /* Old interior cells add new cells and interior faces */
6246             for (r = 0; r < 4; ++r) {
6247               newp = cStartNew + (p - cStart)*4 + r;
6248               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6249             }
6250             for (r = 0; r < 3; ++r) {
6251               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6252               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6253             }
6254           } else if ((p >= cMax) && (p < cEnd)) {
6255             /* Old hybrid cells add new cells and hybrid face */
6256             for (r = 0; r < 2; ++r) {
6257               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
6258               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6259             }
6260             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
6261             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6262           }
6263           break;
6264         case 4:
6265           /* Hybrid Hex 2D */
6266           if ((p >= vStart) && (p < vEnd)) {
6267             /* Old vertices stay the same */
6268             newp = vStartNew + (p - vStart);
6269             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6270           } else if ((p >= fStart) && (p < fMax)) {
6271             /* Old interior faces add new faces and vertex */
6272             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6273             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6274             for (r = 0; r < 2; ++r) {
6275               newp = fStartNew + (p - fStart)*2 + r;
6276               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6277             }
6278           } else if ((p >= fMax) && (p < fEnd)) {
6279             /* Old hybrid faces stay the same */
6280             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
6281             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6282           } else if ((p >= cStart) && (p < cMax)) {
6283             /* Old interior cells add new cells, interior faces, and vertex */
6284             for (r = 0; r < 4; ++r) {
6285               newp = cStartNew + (p - cStart)*4 + r;
6286               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6287             }
6288             for (r = 0; r < 4; ++r) {
6289               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
6290               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6291             }
6292             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
6293             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6294           } else if ((p >= cMax) && (p < cEnd)) {
6295             /* Old hybrid cells add new cells and hybrid face */
6296             for (r = 0; r < 2; ++r) {
6297               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
6298               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6299             }
6300             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (p - cMax);
6301             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6302           }
6303           break;
6304         case 5:
6305           /* Simplicial 3D */
6306           if ((p >= vStart) && (p < vEnd)) {
6307             /* Old vertices stay the same */
6308             newp = vStartNew + (p - vStart);
6309             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6310           } else if ((p >= eStart) && (p < eEnd)) {
6311             /* Old edges add new edges and vertex */
6312             for (r = 0; r < 2; ++r) {
6313               newp = eStartNew + (p - eStart)*2 + r;
6314               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6315             }
6316             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6317             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6318           } else if ((p >= fStart) && (p < fEnd)) {
6319             /* Old faces add new faces and edges */
6320             for (r = 0; r < 4; ++r) {
6321               newp = fStartNew + (p - fStart)*4 + r;
6322               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6323             }
6324             for (r = 0; r < 3; ++r) {
6325               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
6326               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6327             }
6328           } else if ((p >= cStart) && (p < cEnd)) {
6329             /* Old cells add new cells and interior faces and edges */
6330             for (r = 0; r < 8; ++r) {
6331               newp = cStartNew + (p - cStart)*8 + r;
6332               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6333             }
6334             for (r = 0; r < 8; ++r) {
6335               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*8 + r;
6336               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6337             }
6338             for (r = 0; r < 1; ++r) {
6339               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*1 + r;
6340               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6341             }
6342           }
6343           break;
6344         case 7:
6345           /* Hybrid Simplicial 3D */
6346           if ((p >= vStart) && (p < vEnd)) {
6347             /* Interior vertices stay the same */
6348             newp = vStartNew + (p - vStart);
6349             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6350           } else if ((p >= eStart) && (p < eMax)) {
6351             /* Interior edges add new edges and vertex */
6352             for (r = 0; r < 2; ++r) {
6353               newp = eStartNew + (p - eStart)*2 + r;
6354               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6355             }
6356             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6357             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6358           } else if ((p >= eMax) && (p < eEnd)) {
6359             /* Hybrid edges stay the same */
6360             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - eMax);
6361             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6362           } else if ((p >= fStart) && (p < fMax)) {
6363             /* Interior faces add new faces and edges */
6364             for (r = 0; r < 4; ++r) {
6365               newp = fStartNew + (p - fStart)*4 + r;
6366               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6367             }
6368             for (r = 0; r < 3; ++r) {
6369               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
6370               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6371             }
6372           } else if ((p >= fMax) && (p < fEnd)) {
6373             /* Hybrid faces add new faces and edges */
6374             for (r = 0; r < 2; ++r) {
6375               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (p - fMax)*2 + r;
6376               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6377             }
6378             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - fMax);
6379             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6380           } else if ((p >= cStart) && (p < cMax)) {
6381             /* Interior cells add new cells, faces, and edges */
6382             for (r = 0; r < 8; ++r) {
6383               newp = cStartNew + (p - cStart)*8 + r;
6384               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6385             }
6386             for (r = 0; r < 8; ++r) {
6387               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*8 + r;
6388               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6389             }
6390             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart);
6391             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6392           } else if ((p >= cMax) && (p < cEnd)) {
6393             /* Hybrid cells add new cells and faces */
6394             for (r = 0; r < 4; ++r) {
6395               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
6396               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6397             }
6398             for (r = 0; r < 3; ++r) {
6399               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
6400               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6401             }
6402           }
6403           break;
6404         case 6:
6405           /* Hex 3D */
6406           if ((p >= vStart) && (p < vEnd)) {
6407             /* Old vertices stay the same */
6408             newp = vStartNew + (p - vStart);
6409             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6410           } else if ((p >= eStart) && (p < eEnd)) {
6411             /* Old edges add new edges and vertex */
6412             for (r = 0; r < 2; ++r) {
6413               newp = eStartNew + (p - eStart)*2 + r;
6414               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6415             }
6416             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6417             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6418           } else if ((p >= fStart) && (p < fEnd)) {
6419             /* Old faces add new faces, edges, and vertex */
6420             for (r = 0; r < 4; ++r) {
6421               newp = fStartNew + (p - fStart)*4 + r;
6422               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6423             }
6424             for (r = 0; r < 4; ++r) {
6425               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*4 + r;
6426               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6427             }
6428             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (p - fStart);
6429             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6430           } else if ((p >= cStart) && (p < cEnd)) {
6431             /* Old cells add new cells, faces, edges, and vertex */
6432             for (r = 0; r < 8; ++r) {
6433               newp = cStartNew + (p - cStart)*8 + r;
6434               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6435             }
6436             for (r = 0; r < 12; ++r) {
6437               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*12 + r;
6438               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6439             }
6440             for (r = 0; r < 6; ++r) {
6441               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (p - cStart)*6 + r;
6442               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6443             }
6444             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (p - cStart);
6445             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6446           }
6447           break;
6448         case 8:
6449           /* Hybrid Hex 3D */
6450           if ((p >= vStart) && (p < vEnd)) {
6451             /* Interior vertices stay the same */
6452             newp = vStartNew + (p - vStart);
6453             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6454           } else if ((p >= eStart) && (p < eMax)) {
6455             /* Interior edges add new edges and vertex */
6456             for (r = 0; r < 2; ++r) {
6457               newp = eStartNew + (p - eStart)*2 + r;
6458               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6459             }
6460             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6461             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6462           } else if ((p >= eMax) && (p < eEnd)) {
6463             /* Hybrid edges stay the same */
6464             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - eMax);
6465             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6466           } else if ((p >= fStart) && (p < fMax)) {
6467             /* Interior faces add new faces, edges, and vertex */
6468             for (r = 0; r < 4; ++r) {
6469               newp = fStartNew + (p - fStart)*4 + r;
6470               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6471             }
6472             for (r = 0; r < 4; ++r) {
6473               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*4 + r;
6474               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6475             }
6476             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (p - fStart);
6477             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6478           } else if ((p >= fMax) && (p < fEnd)) {
6479             /* Hybrid faces add new faces and edges */
6480             for (r = 0; r < 2; ++r) {
6481               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (p - fMax)*2 + r;
6482               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6483             }
6484             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - fMax);
6485             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6486           } else if ((p >= cStart) && (p < cMax)) {
6487             /* Interior cells add new cells, faces, edges, and vertex */
6488             for (r = 0; r < 8; ++r) {
6489               newp = cStartNew + (p - cStart)*8 + r;
6490               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6491             }
6492             for (r = 0; r < 12; ++r) {
6493               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*12 + r;
6494               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6495             }
6496             for (r = 0; r < 6; ++r) {
6497               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (p - cStart)*6 + r;
6498               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6499             }
6500             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (p - cStart);
6501             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6502           } else if ((p >= cMax) && (p < cEnd)) {
6503             /* Hybrid cells add new cells, faces, and edges */
6504             for (r = 0; r < 4; ++r) {
6505               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
6506               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6507             }
6508             for (r = 0; r < 4; ++r) {
6509               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (p - cMax)*4 + r;
6510               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6511             }
6512             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (fEnd - fMax) + (p - cMax);
6513             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6514           }
6515           break;
6516         default:
6517           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6518         }
6519       }
6520       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
6521       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
6522     }
6523     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
6524     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
6525     if (0) {
6526       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
6527       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
6528       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
6529     }
6530   }
6531   PetscFunctionReturn(0);
6532 }
6533 
6534 #undef __FUNCT__
6535 #define __FUNCT__ "DMPlexRefineUniform_Internal"
6536 /* This will only work for interpolated meshes */
6537 PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
6538 {
6539   DM             rdm;
6540   PetscInt      *depthSize;
6541   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
6542   PetscErrorCode ierr;
6543 
6544   PetscFunctionBegin;
6545   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
6546   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
6547   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6548   ierr = DMSetDimension(rdm, dim);CHKERRQ(ierr);
6549   /* Calculate number of new points of each depth */
6550   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6551   ierr = PetscMalloc1((depth+1), &depthSize);CHKERRQ(ierr);
6552   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
6553   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
6554   /* Step 1: Set chart */
6555   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
6556   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
6557   /* Step 2: Set cone/support sizes */
6558   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6559   /* Step 3: Setup refined DM */
6560   ierr = DMSetUp(rdm);CHKERRQ(ierr);
6561   /* Step 4: Set cones and supports */
6562   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6563   /* Step 5: Stratify */
6564   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
6565   /* Step 6: Create pointSF */
6566   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6567   /* Step 7: Set coordinates for vertices */
6568   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6569   /* Step 8: Create labels */
6570   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6571   ierr = PetscFree(depthSize);CHKERRQ(ierr);
6572 
6573   *dmRefined = rdm;
6574   PetscFunctionReturn(0);
6575 }
6576 
6577 #undef __FUNCT__
6578 #define __FUNCT__ "DMPlexCreateCoarsePointIS"
6579 /*@
6580   DMPlexCreateCoarsePointIS - Creates an IS covering the coarse DM chart with the fine points as data
6581 
6582   Input Parameter:
6583 . dm - The coarse DM
6584 
6585   Output Parameter:
6586 . fpointIS - The IS of all the fine points which exist in the original coarse mesh
6587 
6588   Level: developer
6589 
6590 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexCreateSubpointIS()
6591 @*/
6592 PetscErrorCode DMPlexCreateCoarsePointIS(DM dm, IS *fpointIS)
6593 {
6594   CellRefiner    cellRefiner;
6595   PetscInt      *depthSize, *fpoints;
6596   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
6597   PetscInt       depth, pStart, pEnd, p, vStart, vEnd, v;
6598   PetscErrorCode ierr;
6599 
6600   PetscFunctionBegin;
6601   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6602   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6603   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6604   ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr);
6605   ierr = PetscMalloc1((depth+1), &depthSize);CHKERRQ(ierr);
6606   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
6607   if (cellRefiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
6608   ierr = PetscMalloc1(pEnd-pStart,&fpoints);CHKERRQ(ierr);
6609   for (p = 0; p < pEnd-pStart; ++p) fpoints[p] = -1;
6610   switch (cellRefiner) {
6611   case 1: /* Simplicial 2D */
6612   case 3: /* Hybrid simplicial 2D */
6613   case 2: /* Hex 2D */
6614   case 4: /* Hybrid Hex 2D */
6615   case 5: /* Simplicial 3D */
6616   case 7: /* Hybrid Simplicial 3D */
6617   case 6: /* Hex 3D */
6618   case 8: /* Hybrid Hex 3D */
6619     for (v = vStart; v < vEnd; ++v) fpoints[v-pStart] = vStartNew + (v - vStart);
6620     break;
6621   default:
6622     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", cellRefiner);
6623   }
6624   ierr = ISCreateGeneral(PETSC_COMM_SELF, pEnd-pStart, fpoints, PETSC_OWN_POINTER, fpointIS);CHKERRQ(ierr);
6625   ierr = PetscFree(depthSize);CHKERRQ(ierr);
6626   PetscFunctionReturn(0);
6627 }
6628 
6629 #undef __FUNCT__
6630 #define __FUNCT__ "DMPlexSetRefinementUniform"
6631 /*@
6632   DMPlexSetRefinementUniform - Set the flag for uniform refinement
6633 
6634   Input Parameters:
6635 + dm - The DM
6636 - refinementUniform - The flag for uniform refinement
6637 
6638   Level: developer
6639 
6640 .seealso: DMRefine(), DMPlexGetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
6641 @*/
6642 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
6643 {
6644   DM_Plex *mesh = (DM_Plex*) dm->data;
6645 
6646   PetscFunctionBegin;
6647   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6648   mesh->refinementUniform = refinementUniform;
6649   PetscFunctionReturn(0);
6650 }
6651 
6652 #undef __FUNCT__
6653 #define __FUNCT__ "DMPlexGetRefinementUniform"
6654 /*@
6655   DMPlexGetRefinementUniform - Retrieve the flag for uniform refinement
6656 
6657   Input Parameter:
6658 . dm - The DM
6659 
6660   Output Parameter:
6661 . refinementUniform - The flag for uniform refinement
6662 
6663   Level: developer
6664 
6665 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
6666 @*/
6667 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
6668 {
6669   DM_Plex *mesh = (DM_Plex*) dm->data;
6670 
6671   PetscFunctionBegin;
6672   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6673   PetscValidPointer(refinementUniform,  2);
6674   *refinementUniform = mesh->refinementUniform;
6675   PetscFunctionReturn(0);
6676 }
6677 
6678 #undef __FUNCT__
6679 #define __FUNCT__ "DMPlexSetRefinementLimit"
6680 /*@
6681   DMPlexSetRefinementLimit - Set the maximum cell volume for refinement
6682 
6683   Input Parameters:
6684 + dm - The DM
6685 - refinementLimit - The maximum cell volume in the refined mesh
6686 
6687   Level: developer
6688 
6689 .seealso: DMRefine(), DMPlexGetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
6690 @*/
6691 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
6692 {
6693   DM_Plex *mesh = (DM_Plex*) dm->data;
6694 
6695   PetscFunctionBegin;
6696   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6697   mesh->refinementLimit = refinementLimit;
6698   PetscFunctionReturn(0);
6699 }
6700 
6701 #undef __FUNCT__
6702 #define __FUNCT__ "DMPlexGetRefinementLimit"
6703 /*@
6704   DMPlexGetRefinementLimit - Retrieve the maximum cell volume for refinement
6705 
6706   Input Parameter:
6707 . dm - The DM
6708 
6709   Output Parameter:
6710 . refinementLimit - The maximum cell volume in the refined mesh
6711 
6712   Level: developer
6713 
6714 .seealso: DMRefine(), DMPlexSetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
6715 @*/
6716 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
6717 {
6718   DM_Plex *mesh = (DM_Plex*) dm->data;
6719 
6720   PetscFunctionBegin;
6721   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6722   PetscValidPointer(refinementLimit,  2);
6723   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
6724   *refinementLimit = mesh->refinementLimit;
6725   PetscFunctionReturn(0);
6726 }
6727 
6728 #undef __FUNCT__
6729 #define __FUNCT__ "DMPlexGetCellRefiner_Internal"
6730 PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
6731 {
6732   PetscInt       dim, cStart, cEnd, coneSize, cMax;
6733   PetscErrorCode ierr;
6734 
6735   PetscFunctionBegin;
6736   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6737   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6738   if (cEnd <= cStart) {*cellRefiner = 0; PetscFunctionReturn(0);}
6739   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
6740   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
6741   switch (dim) {
6742   case 2:
6743     switch (coneSize) {
6744     case 3:
6745       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
6746       else *cellRefiner = 1; /* Triangular */
6747       break;
6748     case 4:
6749       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
6750       else *cellRefiner = 2; /* Quadrilateral */
6751       break;
6752     default:
6753       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
6754     }
6755     break;
6756   case 3:
6757     switch (coneSize) {
6758     case 4:
6759       if (cMax >= 0) *cellRefiner = 7; /* Hybrid */
6760       else *cellRefiner = 5; /* Tetrahedral */
6761       break;
6762     case 6:
6763       if (cMax >= 0) *cellRefiner = 8; /* Hybrid */
6764       else *cellRefiner = 6; /* hexahedral */
6765       break;
6766     default:
6767       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
6768     }
6769     break;
6770   default:
6771     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
6772   }
6773   PetscFunctionReturn(0);
6774 }
6775