xref: /petsc/src/dm/impls/plex/plexrefine.c (revision 4d1a973fe17c9234e2cf908ebb478400f033ef22)
1 #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <petscsf.h>
3 
4 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
5 {
6   PetscFunctionBegin;
7   if (cStart) *cStart = 0;
8   if (vStart) *vStart = depth < 0 ? 0 : depthSize[depth];
9   if (fStart) *fStart = depth < 0 ? 0 : depthSize[depth] + depthSize[0];
10   if (eStart) *eStart = depth < 0 ? 0 : depthSize[depth] + depthSize[0] + depthSize[depth-1];
11   PetscFunctionReturn(0);
12 }
13 
14 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
15 {
16   PetscFunctionBegin;
17   if (cEnd) *cEnd = depth < 0 ? 0 : depthSize[depth];
18   if (vEnd) *vEnd = depth < 0 ? 0 : depthSize[depth] + depthSize[0];
19   if (fEnd) *fEnd = depth < 0 ? 0 : depthSize[depth] + depthSize[0] + depthSize[depth-1];
20   if (eEnd) *eEnd = depth < 0 ? 0 : depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
21   PetscFunctionReturn(0);
22 }
23 
24 /* Gets the affine map from the original cell to each subcell */
25 PetscErrorCode CellRefinerGetAffineTransforms_Internal(CellRefiner refiner, PetscInt *numSubcells, PetscReal *v0[], PetscReal *jac[], PetscReal *invjac[])
26 {
27   PetscReal     *v = NULL, *j = NULL, *invj = NULL, detJ;
28   PetscInt       dim, s;
29   PetscErrorCode ierr;
30 
31   PetscFunctionBegin;
32   switch (refiner) {
33   case REFINER_NOOP: break;
34   case REFINER_SIMPLEX_2D:
35     /*
36      2
37      |\
38      | \
39      |  \
40      |   \
41      | C  \
42      |     \
43      |      \
44      2---1---1
45      |\  D  / \
46      | 2   0   \
47      |A \ /  B  \
48      0---0-------1
49      */
50     dim = 2;
51     if (numSubcells) *numSubcells = 4;
52     if (v0) {
53       ierr = PetscMalloc3(4*dim,&v,4*dim*dim,&j,4*dim*dim,&invj);CHKERRQ(ierr);
54       /* A */
55       v[0+0] = -1.0; v[0+1] = -1.0;
56       j[0+0] =  0.5; j[0+1] =  0.0;
57       j[0+2] =  0.0; j[0+3] =  0.5;
58       /* B */
59       v[2+0] =  0.0; v[2+1] = -1.0;
60       j[4+0] =  0.5; j[4+1] =  0.0;
61       j[4+2] =  0.0; j[4+3] =  0.5;
62       /* C */
63       v[4+0] = -1.0; v[4+1] =  0.0;
64       j[8+0] =  0.5; j[8+1] =  0.0;
65       j[8+2] =  0.0; j[8+3] =  0.5;
66       /* D */
67       v[6+0]  =  0.0; v[6+1]  = -1.0;
68       j[12+0] =  0.0; j[12+1] = -0.5;
69       j[12+2] =  0.5; j[12+3] =  0.5;
70       for (s = 0; s < 4; ++s) {
71         DMPlex_Det2D_Internal(&detJ, &j[s*dim*dim]);
72         DMPlex_Invert2D_Internal(&invj[s*dim*dim], &j[s*dim*dim], detJ);
73       }
74     }
75     break;
76   case REFINER_HEX_2D:
77     /*
78      3---------2---------2
79      |         |         |
80      |    D    2    C    |
81      |         |         |
82      3----3----0----1----1
83      |         |         |
84      |    A    0    B    |
85      |         |         |
86      0---------0---------1
87      */
88     dim = 2;
89     if (numSubcells) *numSubcells = 4;
90     if (v0) {
91       ierr = PetscMalloc3(4*dim,&v,4*dim*dim,&j,4*dim*dim,&invj);CHKERRQ(ierr);
92       /* A */
93       v[0+0] = -1.0; v[0+1] = -1.0;
94       j[0+0] =  0.5; j[0+1] =  0.0;
95       j[0+2] =  0.0; j[0+3] =  0.5;
96       /* B */
97       v[2+0] =  0.0; v[2+1] = -1.0;
98       j[4+0] =  0.5; j[4+1] =  0.0;
99       j[4+2] =  0.0; j[4+3] =  0.5;
100       /* C */
101       v[4+0] =  0.0; v[4+1] =  0.0;
102       j[8+0] =  0.5; j[8+1] =  0.0;
103       j[8+2] =  0.0; j[8+3] =  0.5;
104       /* D */
105       v[6+0]  = -1.0; v[6+1]  =  0.0;
106       j[12+0] =  0.5; j[12+1] =  0.0;
107       j[12+2] =  0.0; j[12+3] =  0.5;
108       for (s = 0; s < 4; ++s) {
109         DMPlex_Det2D_Internal(&detJ, &j[s*dim*dim]);
110         DMPlex_Invert2D_Internal(&invj[s*dim*dim], &j[s*dim*dim], detJ);
111       }
112     }
113     break;
114   case REFINER_HEX_3D:
115     /*
116      Bottom (viewed from top)    Top
117      1---------2---------2       7---------2---------6
118      |         |         |       |         |         |
119      |    B    2    C    |       |    H    2    G    |
120      |         |         |       |         |         |
121      3----3----0----1----1       3----3----0----1----1
122      |         |         |       |         |         |
123      |    A    0    D    |       |    E    0    F    |
124      |         |         |       |         |         |
125      0---------0---------3       4---------0---------5
126      */
127     break;
128     dim = 3;
129     if (numSubcells) *numSubcells = 8;
130     if (v0) {
131       ierr = PetscMalloc3(4*dim,&v,4*dim*dim,&j,4*dim*dim,&invj);CHKERRQ(ierr);
132       /* A */
133       v[0+0] = -1.0; v[0+1] = -1.0; v[0+2] = -1.0;
134       j[0+0] =  0.5; j[0+1] =  0.0; j[0+2] =  0.0;
135       j[0+3] =  0.0; j[0+4] =  0.5; j[0+5] =  0.0;
136       j[0+6] =  0.0; j[0+7] =  0.0; j[0+8] =  0.5;
137       /* B */
138       v[3+0] = -1.0; v[3+1] =  0.0; v[3+2] = -1.0;
139       j[9+0] =  0.5; j[9+1] =  0.0; j[9+2] =  0.0;
140       j[9+3] =  0.0; j[9+4] =  0.5; j[9+5] =  0.0;
141       j[9+6] =  0.0; j[9+7] =  0.0; j[9+8] =  0.5;
142       /* C */
143       v[6+0] =  0.0; v[6+1] =  0.0; v[6+2] = -1.0;
144       j[18+0] = 0.5; j[18+1] = 0.0; j[18+2] = 0.0;
145       j[18+3] = 0.0; j[18+4] = 0.5; j[18+5] = 0.0;
146       j[18+6] = 0.0; j[18+7] = 0.0; j[18+8] = 0.5;
147       /* D */
148       v[9+0] =  0.0; v[9+1] = -1.0; v[9+2] = -1.0;
149       j[27+0] = 0.5; j[27+1] = 0.0; j[27+2] = 0.0;
150       j[27+3] = 0.0; j[27+4] = 0.5; j[27+5] = 0.0;
151       j[27+6] = 0.0; j[27+7] = 0.0; j[27+8] = 0.5;
152       /* E */
153       v[12+0] = -1.0; v[12+1] = -1.0; v[12+2] =  0.0;
154       j[36+0] =  0.5; j[36+1] =  0.0; j[36+2] =  0.0;
155       j[36+3] =  0.0; j[36+4] =  0.5; j[36+5] =  0.0;
156       j[36+6] =  0.0; j[36+7] =  0.0; j[36+8] =  0.5;
157       /* F */
158       v[15+0] =  0.0; v[15+1] = -1.0; v[15+2] =  0.0;
159       j[45+0] =  0.5; j[45+1] =  0.0; j[45+2] =  0.0;
160       j[45+3] =  0.0; j[45+4] =  0.5; j[45+5] =  0.0;
161       j[45+6] =  0.0; j[45+7] =  0.0; j[45+8] =  0.5;
162       /* G */
163       v[18+0] =  0.0; v[18+1] =  0.0; v[18+2] =  0.0;
164       j[54+0] =  0.5; j[54+1] =  0.0; j[54+2] =  0.0;
165       j[54+3] =  0.0; j[54+4] =  0.5; j[54+5] =  0.0;
166       j[54+6] =  0.0; j[54+7] =  0.0; j[54+8] =  0.5;
167       /* H */
168       v[21+0] = -1.0; v[21+1] =  0.0; v[21+2] =  0.0;
169       j[63+0] =  0.5; j[63+1] =  0.0; j[63+2] =  0.0;
170       j[63+3] =  0.0; j[63+4] =  0.5; j[63+5] =  0.0;
171       j[63+6] =  0.0; j[63+7] =  0.0; j[63+8] =  0.5;
172       for (s = 0; s < 8; ++s) {
173         DMPlex_Det3D_Internal(&detJ, &j[s*dim*dim]);
174         DMPlex_Invert3D_Internal(&invj[s*dim*dim], &j[s*dim*dim], detJ);
175       }
176     }
177   default:
178     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
179   }
180   if (v0) {*v0 = v; *jac = j; *invjac = invj;}
181   PetscFunctionReturn(0);
182 }
183 
184 PetscErrorCode CellRefinerRestoreAffineTransforms_Internal(CellRefiner refiner, PetscInt *numSubcells, PetscReal *v0[], PetscReal *jac[], PetscReal *invjac[])
185 {
186   PetscErrorCode ierr;
187 
188   PetscFunctionBegin;
189   ierr = PetscFree3(*v0,*jac,*invjac);CHKERRQ(ierr);
190   PetscFunctionReturn(0);
191 }
192 
193 /* Should this be here or in the DualSpace somehow? */
194 PetscErrorCode CellRefinerInCellTest_Internal(CellRefiner refiner, const PetscReal point[], PetscBool *inside)
195 {
196   PetscReal sum = 0.0;
197   PetscInt  d;
198 
199   PetscFunctionBegin;
200   *inside = PETSC_TRUE;
201   switch (refiner) {
202   case REFINER_NOOP: break;
203   case REFINER_SIMPLEX_2D:
204     for (d = 0; d < 2; ++d) {
205       if (point[d] < -1.0) {*inside = PETSC_FALSE; break;}
206       sum += point[d];
207     }
208     if (sum > 1.0e-10) {*inside = PETSC_FALSE; break;}
209     break;
210   case REFINER_HEX_2D:
211     for (d = 0; d < 2; ++d) if ((point[d] < -1.00000000001) || (point[d] > 1.000000000001)) {*inside = PETSC_FALSE; break;}
212     break;
213   default:
214     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
215   }
216   PetscFunctionReturn(0);
217 }
218 
219 static PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
220 {
221   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
222   PetscErrorCode ierr;
223 
224   PetscFunctionBegin;
225   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
226   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
227   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
228   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
229   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
230   switch (refiner) {
231   case REFINER_NOOP:
232     break;
233   case REFINER_SIMPLEX_1D:
234     depthSize[0] = vEnd - vStart + cEnd - cStart;         /* Add a vertex on every cell. */
235     depthSize[1] = 2*(cEnd - cStart);                     /* Split every cell in 2. */
236     break;
237   case REFINER_SIMPLEX_2D:
238     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
239     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
240     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
241     break;
242   case REFINER_HYBRID_SIMPLEX_2D:
243     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
244     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
245     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
246     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 */
247     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
248     break;
249   case REFINER_SIMPLEX_TO_HEX_2D:
250     depthSize[0] = vEnd - vStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every face and cell */
251     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart);         /* Every face is split into 2 faces and 3 faces are added for each cell */
252     depthSize[2] = 3*(cEnd - cStart);                             /* Every cell split into 3 cells */
253     break;
254   case REFINER_HEX_2D:
255     depthSize[0] = vEnd - vStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every face and cell */
256     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
257     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
258     break;
259   case REFINER_HYBRID_HEX_2D:
260     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
261     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
262     /* Quadrilateral */
263     depthSize[0] = vEnd - vStart + fMax - fStart + cMax - cStart;                 /* Add a vertex on every face and cell */
264     depthSize[1] = 2*(fMax - fStart) + 4*(cMax - cStart);                         /* Every face is split into 2 faces, and 4 faces are added for each cell */
265     depthSize[2] = 4*(cMax - cStart);                                             /* Every cell split into 4 cells */
266     /* Segment Prisms */
267     depthSize[0] += 0;                                                            /* No hybrid vertices */
268     depthSize[1] +=   (fEnd - fMax)  +   (cEnd - cMax);                           /* Every hybrid face remains and 1 faces is added for each hybrid cell */
269     depthSize[2] += 2*(cEnd - cMax);                                              /* Every hybrid cell split into 2 cells */
270     break;
271   case REFINER_SIMPLEX_3D:
272     depthSize[0] =    vEnd - vStart  +    eEnd - eStart;                    /* Add a vertex on every edge */
273     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 */
274     depthSize[2] = 4*(fEnd - fStart) + 8*(cEnd - cStart);                   /* Every face split into 4 faces and 8 faces are added for each cell */
275     depthSize[3] = 8*(cEnd - cStart);                                       /* Every cell split into 8 cells */
276     break;
277   case REFINER_HYBRID_SIMPLEX_3D:
278     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
279     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
280     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
281     /* Tetrahedra */
282     depthSize[0]  =    vEnd - vStart  +    eMax - eStart;                    /* Add a vertex on every interior edge */
283     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 */
284     depthSize[2]  = 4*(fMax - fStart) + 8*(cMax - cStart);                   /* Every interior face split into 4 faces, 8 faces added for each interior cell */
285     depthSize[3]  = 8*(cMax - cStart);                                       /* Every interior cell split into 8 cells */
286     /* Triangular Prisms */
287     depthSize[0] += 0;                                                       /* No hybrid vertices */
288     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax);                     /* Every hybrid edge remains, 1 edge for every hybrid face */
289     depthSize[2] += 2*(fEnd - fMax)   + 3*(cEnd - cMax);                     /* Every hybrid face split into 2 faces and 3 faces are added for each hybrid cell */
290     depthSize[3] += 4*(cEnd - cMax);                                         /* Every hybrid cell split into 4 cells */
291     break;
292   case REFINER_SIMPLEX_TO_HEX_3D:
293     depthSize[0] = vEnd - vStart + fEnd - fStart + eEnd - eStart + cEnd - cStart; /* Add a vertex on every face, edge and cell */
294     depthSize[1] = 2*(eEnd - eStart) + 3*(fEnd - fStart) + 4*(cEnd - cStart);     /* Every edge is split into 2 edges, 3 edges are added for each face, and 4 for each cell */
295     depthSize[2] = 3*(fEnd - fStart) + 6*(cEnd - cStart);                         /* Every face is split into 3 faces and 6 faces are added for each cell */
296     depthSize[3] = 4*(cEnd - cStart);                                             /* Every cell split into 4 cells */
297     break;
298   case REFINER_HEX_3D:
299     depthSize[0] = vEnd - vStart + eEnd - eStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every edge, face and cell */
300     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 */
301     depthSize[2] = 4*(fEnd - fStart) + 12*(cEnd - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
302     depthSize[3] = 8*(cEnd - cStart);                                             /* Every cell split into 8 cells */
303     break;
304   case REFINER_HYBRID_HEX_3D:
305     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
306     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
307     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
308     /* Hexahedra */
309     depthSize[0] = vEnd - vStart + eMax - eStart + fMax - fStart + cMax - cStart; /* Add a vertex on every edge, face and cell */
310     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 */
311     depthSize[2] = 4*(fMax - fStart) + 12*(cMax - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
312     depthSize[3] = 8*(cMax - cStart);                                             /* Every cell split into 8 cells */
313     /* Quadrilateral Prisms */
314     depthSize[0] += 0;                                                            /* No hybrid vertices */
315     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax)   +   (cEnd - cMax);      /* Every hybrid edge remains, 1 edge for every hybrid face and hybrid cell */
316     depthSize[2] += 2*(fEnd - fMax)   + 4*(cEnd - cMax);                          /* Every hybrid face split into 2 faces and 4 faces are added for each hybrid cell */
317     depthSize[3] += 4*(cEnd - cMax);                                              /* Every hybrid cell split into 4 cells */
318     break;
319   default:
320     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
321   }
322   PetscFunctionReturn(0);
323 }
324 
325 /* Return triangle edge for orientation o, if it is r for o == 0 */
326 PETSC_STATIC_INLINE PetscInt GetTriEdge_Static(PetscInt o, PetscInt r) {
327   return (o < 0 ? 2-(o+r) : o+r)%3;
328 }
329 PETSC_STATIC_INLINE PetscInt GetTriEdgeInverse_Static(PetscInt o, PetscInt s) {
330   return (o < 0 ? 2-(o+s) : 3+s-o)%3;
331 }
332 
333 /* Return triangle subface for orientation o, if it is r for o == 0 */
334 PETSC_STATIC_INLINE PetscInt GetTriSubface_Static(PetscInt o, PetscInt r) {
335   return (o < 0 ? 3-(o+r) : o+r)%3;
336 }
337 PETSC_STATIC_INLINE PetscInt GetTriSubfaceInverse_Static(PetscInt o, PetscInt s) {
338   return (o < 0 ? 3-(o+s) : 3+s-o)%3;
339 }
340 
341 /* Return the interior edge number connecting the midpoints of the triangle edges r
342    and r+1 in the transitive closure for triangle orientation o */
343 PETSC_STATIC_INLINE PetscInt GetTriMidEdge_Static(PetscInt o, PetscInt r) {
344   return (o < 0 ? 1-(o+r) : o+r)%3;
345 }
346 PETSC_STATIC_INLINE PetscInt GetTriMidEdgeInverse_Static(PetscInt o, PetscInt s) {
347   return (o < 0 ? 1-(o+s) : 3+s-o)%3;
348 }
349 
350 /* Return the interior edge number connecting the midpoint of the triangle edge r
351    (in the transitive closure) and the vertex in the interior of the face for triangle orientation o */
352 PETSC_STATIC_INLINE PetscInt GetTriInteriorEdge_Static(PetscInt o, PetscInt r) {
353   return (o < 0 ? 2-(o+r) : o+r)%3;
354 }
355 PETSC_STATIC_INLINE PetscInt GetTriInteriorEdgeInverse_Static(PetscInt o, PetscInt s) {
356   return (o < 0 ? 2-(o+s) : 3+s-o)%3;
357 }
358 
359 /* Return quad edge for orientation o, if it is r for o == 0 */
360 PETSC_STATIC_INLINE PetscInt GetQuadEdge_Static(PetscInt o, PetscInt r) {
361   return (o < 0 ? 3-(o+r) : o+r)%4;
362 }
363 PETSC_STATIC_INLINE PetscInt GetQuadEdgeInverse_Static(PetscInt o, PetscInt s) {
364   return (o < 0 ? 3-(o+s) : 4+s-o)%4;
365 }
366 
367 /* Return quad subface for orientation o, if it is r for o == 0 */
368 PETSC_STATIC_INLINE PetscInt GetQuadSubface_Static(PetscInt o, PetscInt r) {
369   return (o < 0 ? 4-(o+r) : o+r)%4;
370 }
371 PETSC_STATIC_INLINE PetscInt GetQuadSubfaceInverse_Static(PetscInt o, PetscInt s) {
372   return (o < 0 ? 4-(o+s) : 4+s-o)%4;
373 }
374 
375 static PetscErrorCode DMLabelSetStratumBounds(DMLabel label, PetscInt value, PetscInt cStart, PetscInt cEnd)
376 {
377   IS             cIS;
378   PetscErrorCode ierr;
379 
380   PetscFunctionBegin;
381   ierr = ISCreateStride(PETSC_COMM_SELF, cEnd - cStart, cStart, 1, &cIS);CHKERRQ(ierr);
382   ierr = DMLabelSetStratumIS(label, value, cIS);CHKERRQ(ierr);
383   ierr = ISDestroy(&cIS);CHKERRQ(ierr);
384   PetscFunctionReturn(0);
385 }
386 
387 static PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
388 {
389   PetscInt       depth, cStart, cStartNew, cEnd, cEndNew, cMax, c, vStart, vStartNew, vEnd, vEndNew, vMax, v, fStart, fStartNew, fEnd, fEndNew, fMax, f, eStart, eStartNew, eEnd, eEndNew, eMax, e, r;
390   DMLabel        depthLabel;
391   PetscErrorCode ierr;
392 
393   PetscFunctionBegin;
394   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
395   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
396   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
397   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
398   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
399   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
400   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
401   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
402   ierr = DMCreateLabel(rdm,"depth");CHKERRQ(ierr);
403   ierr = DMPlexGetDepthLabel(rdm,&depthLabel);CHKERRQ(ierr);
404   ierr = DMLabelSetStratumBounds(depthLabel, 0, vStartNew, vEndNew);CHKERRQ(ierr);
405   if (depth > 2) ierr = DMLabelSetStratumBounds(depthLabel, 1, eStartNew, eEndNew);CHKERRQ(ierr);
406   if (depth > 1) ierr = DMLabelSetStratumBounds(depthLabel, depth - 1, fStartNew, fEndNew);CHKERRQ(ierr);
407   if (depth > 0) ierr = DMLabelSetStratumBounds(depthLabel, depth, cStartNew, cEndNew);CHKERRQ(ierr);
408   {
409     DM_Plex *plex = (DM_Plex *) rdm->data;
410     ierr = DMLabelGetState(depthLabel, &plex->depthState);CHKERRQ(ierr);
411   }
412   if (!refiner) PetscFunctionReturn(0);
413   switch (refiner) {
414   case REFINER_SIMPLEX_1D:
415     /* All cells have 2 vertices */
416     for (c = cStart; c < cEnd; ++c) {
417       for (r = 0; r < 2; ++r) {
418         const PetscInt newp = cStartNew + (c - cStart)*2 + r;
419 
420         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
421       }
422     }
423     /* Old vertices have identical supports */
424     for (v = vStart; v < vEnd; ++v) {
425       const PetscInt newp = vStartNew + (v - vStart);
426       PetscInt       size;
427 
428       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
429       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
430     }
431     /* Cell vertices have support 2 */
432     for (c = cStart; c < cEnd; ++c) {
433       const PetscInt newp = vStartNew + (vEnd - vStart) + (c - cStart);
434 
435       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
436     }
437     break;
438   case REFINER_SIMPLEX_2D:
439     /* All cells have 3 faces */
440     for (c = cStart; c < cEnd; ++c) {
441       for (r = 0; r < 4; ++r) {
442         const PetscInt newp = (c - cStart)*4 + r;
443 
444         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
445       }
446     }
447     /* Split faces have 2 vertices and the same cells as the parent */
448     for (f = fStart; f < fEnd; ++f) {
449       for (r = 0; r < 2; ++r) {
450         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
451         PetscInt       size;
452 
453         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
454         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
455         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
456       }
457     }
458     /* Interior faces have 2 vertices and 2 cells */
459     for (c = cStart; c < cEnd; ++c) {
460       for (r = 0; r < 3; ++r) {
461         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
462 
463         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
464         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
465       }
466     }
467     /* Old vertices have identical supports */
468     for (v = vStart; v < vEnd; ++v) {
469       const PetscInt newp = vStartNew + (v - vStart);
470       PetscInt       size;
471 
472       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
473       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
474     }
475     /* Face vertices have 2 + cells*2 supports */
476     for (f = fStart; f < fEnd; ++f) {
477       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
478       PetscInt       size;
479 
480       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
481       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
482     }
483     break;
484   case REFINER_SIMPLEX_TO_HEX_2D:
485     /* All cells have 4 faces */
486     for (c = cStart; c < cEnd; ++c) {
487       for (r = 0; r < 3; ++r) {
488         const PetscInt newp = (c - cStart)*3 + r;
489 
490         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
491       }
492     }
493     /* Split faces have 2 vertices and the same cells as the parent */
494     for (f = fStart; f < fEnd; ++f) {
495       for (r = 0; r < 2; ++r) {
496         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
497         PetscInt       size;
498 
499         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
500         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
501         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
502       }
503     }
504     /* Interior faces have 2 vertices and 2 cells */
505     for (c = cStart; c < cEnd; ++c) {
506       for (r = 0; r < 3; ++r) {
507         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
508 
509         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
510         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
511       }
512     }
513     /* Old vertices have identical supports */
514     for (v = vStart; v < vEnd; ++v) {
515       const PetscInt newp = vStartNew + (v - vStart);
516       PetscInt       size;
517 
518       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
519       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
520     }
521     /* Split-face vertices have cells + 2 supports */
522     for (f = fStart; f < fEnd; ++f) {
523       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
524       PetscInt       size;
525 
526       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
527       ierr = DMPlexSetSupportSize(rdm, newp, size + 2);CHKERRQ(ierr);
528     }
529     /* Interior vertices have 3 supports */
530     for (c = cStart; c < cEnd; ++c) {
531       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
532 
533       ierr = DMPlexSetSupportSize(rdm, newp, 3);CHKERRQ(ierr);
534     }
535     break;
536   case REFINER_HEX_2D:
537     /* All cells have 4 faces */
538     for (c = cStart; c < cEnd; ++c) {
539       for (r = 0; r < 4; ++r) {
540         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
541 
542         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
543       }
544     }
545     /* Split faces have 2 vertices and the same cells as the parent */
546     for (f = fStart; f < fEnd; ++f) {
547       for (r = 0; r < 2; ++r) {
548         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
549         PetscInt       size;
550 
551         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
552         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
553         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
554       }
555     }
556     /* Interior faces have 2 vertices and 2 cells */
557     for (c = cStart; c < cEnd; ++c) {
558       for (r = 0; r < 4; ++r) {
559         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
560 
561         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
562         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
563       }
564     }
565     /* Old vertices have identical supports */
566     for (v = vStart; v < vEnd; ++v) {
567       const PetscInt newp = vStartNew + (v - vStart);
568       PetscInt       size;
569 
570       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
571       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
572     }
573     /* Face vertices have 2 + cells supports */
574     for (f = fStart; f < fEnd; ++f) {
575       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
576       PetscInt       size;
577 
578       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
579       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
580     }
581     /* Cell vertices have 4 supports */
582     for (c = cStart; c < cEnd; ++c) {
583       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
584 
585       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
586     }
587     break;
588   case REFINER_HYBRID_SIMPLEX_2D:
589     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
590     cMax = PetscMin(cEnd, cMax);
591     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
592     fMax = PetscMin(fEnd, fMax);
593     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
594     /* Interior cells have 3 faces */
595     for (c = cStart; c < cMax; ++c) {
596       for (r = 0; r < 4; ++r) {
597         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
598 
599         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
600       }
601     }
602     /* Hybrid cells have 4 faces */
603     for (c = cMax; c < cEnd; ++c) {
604       for (r = 0; r < 2; ++r) {
605         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
606 
607         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
608       }
609     }
610     /* Interior split faces have 2 vertices and the same cells as the parent */
611     for (f = fStart; f < fMax; ++f) {
612       for (r = 0; r < 2; ++r) {
613         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
614         PetscInt       size;
615 
616         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
617         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
618         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
619       }
620     }
621     /* Interior cell faces have 2 vertices and 2 cells */
622     for (c = cStart; c < cMax; ++c) {
623       for (r = 0; r < 3; ++r) {
624         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
625 
626         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
627         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
628       }
629     }
630     /* Hybrid faces have 2 vertices and the same cells */
631     for (f = fMax; f < fEnd; ++f) {
632       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
633       PetscInt       size;
634 
635       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
636       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
637       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
638     }
639     /* Hybrid cell faces have 2 vertices and 2 cells */
640     for (c = cMax; c < cEnd; ++c) {
641       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
642 
643       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
644       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
645     }
646     /* Old vertices have identical supports */
647     for (v = vStart; v < vEnd; ++v) {
648       const PetscInt newp = vStartNew + (v - vStart);
649       PetscInt       size;
650 
651       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
652       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
653     }
654     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
655     for (f = fStart; f < fMax; ++f) {
656       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
657       const PetscInt *support;
658       PetscInt       size, newSize = 2, s;
659 
660       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
661       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
662       for (s = 0; s < size; ++s) {
663         if (support[s] >= cMax) newSize += 1;
664         else newSize += 2;
665       }
666       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
667     }
668     break;
669   case REFINER_HYBRID_HEX_2D:
670     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
671     cMax = PetscMin(cEnd, cMax);
672     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
673     fMax = PetscMin(fEnd, fMax);
674     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
675     /* Interior cells have 4 faces */
676     for (c = cStart; c < cMax; ++c) {
677       for (r = 0; r < 4; ++r) {
678         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
679 
680         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
681       }
682     }
683     /* Hybrid cells have 4 faces */
684     for (c = cMax; c < cEnd; ++c) {
685       for (r = 0; r < 2; ++r) {
686         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
687 
688         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
689       }
690     }
691     /* Interior split faces have 2 vertices and the same cells as the parent */
692     for (f = fStart; f < fMax; ++f) {
693       for (r = 0; r < 2; ++r) {
694         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
695         PetscInt       size;
696 
697         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
698         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
699         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
700       }
701     }
702     /* Interior cell faces have 2 vertices and 2 cells */
703     for (c = cStart; c < cMax; ++c) {
704       for (r = 0; r < 4; ++r) {
705         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
706 
707         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
708         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
709       }
710     }
711     /* Hybrid faces have 2 vertices and the same cells */
712     for (f = fMax; f < fEnd; ++f) {
713       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
714       PetscInt       size;
715 
716       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
717       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
718       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
719     }
720     /* Hybrid cell faces have 2 vertices and 2 cells */
721     for (c = cMax; c < cEnd; ++c) {
722       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
723 
724       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
725       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
726     }
727     /* Old vertices have identical supports */
728     for (v = vStart; v < vEnd; ++v) {
729       const PetscInt newp = vStartNew + (v - vStart);
730       PetscInt       size;
731 
732       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
733       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
734     }
735     /* Face vertices have 2 + cells supports */
736     for (f = fStart; f < fMax; ++f) {
737       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
738       PetscInt       size;
739 
740       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
741       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
742     }
743     /* Cell vertices have 4 supports */
744     for (c = cStart; c < cMax; ++c) {
745       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
746 
747       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
748     }
749     break;
750   case REFINER_SIMPLEX_3D:
751     /* All cells have 4 faces */
752     for (c = cStart; c < cEnd; ++c) {
753       for (r = 0; r < 8; ++r) {
754         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
755 
756         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
757       }
758     }
759     /* Split faces have 3 edges and the same cells as the parent */
760     for (f = fStart; f < fEnd; ++f) {
761       for (r = 0; r < 4; ++r) {
762         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
763         PetscInt       size;
764 
765         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
766         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
767         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
768       }
769     }
770     /* Interior cell faces have 3 edges and 2 cells */
771     for (c = cStart; c < cEnd; ++c) {
772       for (r = 0; r < 8; ++r) {
773         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + r;
774 
775         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
776         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
777       }
778     }
779     /* Split edges have 2 vertices and the same faces */
780     for (e = eStart; e < eEnd; ++e) {
781       for (r = 0; r < 2; ++r) {
782         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
783         PetscInt       size;
784 
785         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
786         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
787         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
788       }
789     }
790     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
791     for (f = fStart; f < fEnd; ++f) {
792       for (r = 0; r < 3; ++r) {
793         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
794         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
795         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;
796 
797         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
798         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
799         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
800         for (s = 0; s < supportSize; ++s) {
801           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
802           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
803           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
804           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
805           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
806           er = GetTriMidEdgeInverse_Static(ornt[c], r);
807           if (er == eint[c]) {
808             intFaces += 1;
809           } else {
810             intFaces += 2;
811           }
812         }
813         ierr = DMPlexSetSupportSize(rdm, newp, 2+intFaces);CHKERRQ(ierr);
814       }
815     }
816     /* Interior cell edges have 2 vertices and 4 faces */
817     for (c = cStart; c < cEnd; ++c) {
818       const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
819 
820       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
821       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
822     }
823     /* Old vertices have identical supports */
824     for (v = vStart; v < vEnd; ++v) {
825       const PetscInt newp = vStartNew + (v - vStart);
826       PetscInt       size;
827 
828       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
829       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
830     }
831     /* Edge vertices have 2 + faces*2 + cells*0/1 supports */
832     for (e = eStart; e < eEnd; ++e) {
833       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
834       PetscInt       size, *star = NULL, starSize, s, cellSize = 0;
835 
836       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
837       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
838       for (s = 0; s < starSize*2; s += 2) {
839         const PetscInt *cone, *ornt;
840         PetscInt        e01, e23;
841 
842         if ((star[s] >= cStart) && (star[s] < cEnd)) {
843           /* Check edge 0-1 */
844           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
845           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
846           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
847           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
848           /* Check edge 2-3 */
849           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
850           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
851           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
852           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
853           if ((e01 == e) || (e23 == e)) ++cellSize;
854         }
855       }
856       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
857       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2 + cellSize);CHKERRQ(ierr);
858     }
859     break;
860   case REFINER_HYBRID_SIMPLEX_3D:
861     ierr = DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 8*(cMax - cStart),
862                                  eStartNew + 2*(eMax - eStart) + 3*(fMax - fStart) + (cMax - cStart), PETSC_DETERMINE);CHKERRQ(ierr);
863     /* Interior cells have 4 faces */
864     for (c = cStart; c < cMax; ++c) {
865       for (r = 0; r < 8; ++r) {
866         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
867 
868         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
869       }
870     }
871     /* Hybrid cells have 5 faces */
872     for (c = cMax; c < cEnd; ++c) {
873       for (r = 0; r < 4; ++r) {
874         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;
875 
876         ierr = DMPlexSetConeSize(rdm, newp, 5);CHKERRQ(ierr);
877       }
878     }
879     /* Interior split faces have 3 edges and the same cells as the parent */
880     for (f = fStart; f < fMax; ++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, 3);CHKERRQ(ierr);
886         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
887         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
888       }
889     }
890     /* Interior cell faces have 3 edges and 2 cells */
891     for (c = cStart; c < cMax; ++c) {
892       for (r = 0; r < 8; ++r) {
893         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + r;
894 
895         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
896         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
897       }
898     }
899     /* Hybrid split faces have 4 edges and the same cells as the parent */
900     for (f = fMax; f < fEnd; ++f) {
901       for (r = 0; r < 2; ++r) {
902         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
903         PetscInt       size;
904 
905         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
906         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
907         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
908       }
909     }
910     /* Hybrid cells faces have 4 edges and 2 cells */
911     for (c = cMax; c < cEnd; ++c) {
912       for (r = 0; r < 3; ++r) {
913         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + r;
914 
915         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
916         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
917       }
918     }
919     /* Interior split edges have 2 vertices and the same faces */
920     for (e = eStart; e < eMax; ++e) {
921       for (r = 0; r < 2; ++r) {
922         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
923         PetscInt       size;
924 
925         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
926         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
927         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
928       }
929     }
930     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
931     for (f = fStart; f < fMax; ++f) {
932       for (r = 0; r < 3; ++r) {
933         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
934         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
935         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;
936 
937         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
938         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
939         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
940         for (s = 0; s < supportSize; ++s) {
941           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
942           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
943           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
944           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
945           if (support[s] < cMax) {
946             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
947             er = GetTriMidEdgeInverse_Static(ornt[c], r);
948             if (er == eint[c]) {
949               intFaces += 1;
950             } else {
951               intFaces += 2;
952             }
953           } else {
954             intFaces += 1;
955           }
956         }
957         ierr = DMPlexSetSupportSize(rdm, newp, 2+intFaces);CHKERRQ(ierr);
958       }
959     }
960     /* Interior cell edges have 2 vertices and 4 faces */
961     for (c = cStart; c < cMax; ++c) {
962       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
963 
964       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
965       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
966     }
967     /* Hybrid edges have 2 vertices and the same faces */
968     for (e = eMax; e < eEnd; ++e) {
969       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
970       PetscInt       size;
971 
972       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
973       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
974       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
975     }
976     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
977     for (f = fMax; f < fEnd; ++f) {
978       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
979       PetscInt       size;
980 
981       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
982       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
983       ierr = DMPlexSetSupportSize(rdm, newp, 2+2*size);CHKERRQ(ierr);
984     }
985     /* Interior vertices have identical supports */
986     for (v = vStart; v < vEnd; ++v) {
987       const PetscInt newp = vStartNew + (v - vStart);
988       PetscInt       size;
989 
990       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
991       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
992     }
993     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
994     for (e = eStart; e < eMax; ++e) {
995       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
996       const PetscInt *support;
997       PetscInt        size, *star = NULL, starSize, s, faceSize = 0, cellSize = 0;
998 
999       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1000       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
1001       for (s = 0; s < size; ++s) {
1002         if (support[s] < fMax) faceSize += 2;
1003         else                   faceSize += 1;
1004       }
1005       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
1006       for (s = 0; s < starSize*2; s += 2) {
1007         const PetscInt *cone, *ornt;
1008         PetscInt        e01, e23;
1009 
1010         if ((star[s] >= cStart) && (star[s] < cMax)) {
1011           /* Check edge 0-1 */
1012           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
1013           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
1014           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
1015           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
1016           /* Check edge 2-3 */
1017           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
1018           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
1019           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
1020           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
1021           if ((e01 == e) || (e23 == e)) ++cellSize;
1022         }
1023       }
1024       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
1025       ierr = DMPlexSetSupportSize(rdm, newp, 2 + faceSize + cellSize);CHKERRQ(ierr);
1026     }
1027     break;
1028   case REFINER_SIMPLEX_TO_HEX_3D:
1029     /* All cells have 6 faces */
1030     for (c = cStart; c < cEnd; ++c) {
1031       for (r = 0; r < 4; ++r) {
1032         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
1033 
1034         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1035       }
1036     }
1037     /* Split faces have 4 edges and the same cells as the parent */
1038     for (f = fStart; f < fEnd; ++f) {
1039       for (r = 0; r < 3; ++r) {
1040         const PetscInt newp = fStartNew + (f - fStart)*3 + r;
1041         PetscInt       size;
1042 
1043         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1044         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1045         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1046       }
1047     }
1048     /* Interior cell faces have 4 edges and 2 cells */
1049     for (c = cStart; c < cEnd; ++c) {
1050       for (r = 0; r < 6; ++r) {
1051         const PetscInt newp = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + r;
1052 
1053         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1054         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1055       }
1056     }
1057     /* Split edges have 2 vertices and the same faces */
1058     for (e = eStart; e < eEnd; ++e) {
1059       for (r = 0; r < 2; ++r) {
1060         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1061         PetscInt       size;
1062 
1063         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1064         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1065         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1066       }
1067     }
1068     /* Face edges have 2 vertices and 2 + cell faces supports */
1069     for (f = fStart; f < fEnd; ++f) {
1070       for (r = 0; r < 3; ++r) {
1071         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
1072         PetscInt        size;
1073 
1074         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1075         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1076         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1077       }
1078     }
1079     /* Interior cell edges have 2 vertices and 3 faces */
1080     for (c = cStart; c < cEnd; ++c) {
1081       for (r = 0; r < 4; ++r) {
1082         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + r;
1083 
1084         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1085         ierr = DMPlexSetSupportSize(rdm, newp, 3);CHKERRQ(ierr);
1086       }
1087     }
1088     /* Old vertices have identical supports */
1089     for (v = vStart; v < vEnd; ++v) {
1090       const PetscInt newp = vStartNew + (v - vStart);
1091       PetscInt       size;
1092 
1093       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1094       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1095     }
1096     /* Edge vertices have 2 + faces supports */
1097     for (e = eStart; e < eEnd; ++e) {
1098       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1099       PetscInt       size;
1100 
1101       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1102       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1103     }
1104     /* Face vertices have 3 + cells supports */
1105     for (f = fStart; f < fEnd; ++f) {
1106       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + f - fStart;
1107       PetscInt       size;
1108 
1109       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1110       ierr = DMPlexSetSupportSize(rdm, newp, 3 + size);CHKERRQ(ierr);
1111     }
1112     /* Interior cell vertices have 4 supports */
1113     for (c = cStart; c < cEnd; ++c) {
1114       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + fEnd - fStart + c - cStart;
1115 
1116       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1117     }
1118     break;
1119   case REFINER_HEX_3D:
1120     /* All cells have 6 faces */
1121     for (c = cStart; c < cEnd; ++c) {
1122       for (r = 0; r < 8; ++r) {
1123         const PetscInt newp = (c - cStart)*8 + r;
1124 
1125         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1126       }
1127     }
1128     /* Split faces have 4 edges and the same cells as the parent */
1129     for (f = fStart; f < fEnd; ++f) {
1130       for (r = 0; r < 4; ++r) {
1131         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
1132         PetscInt       size;
1133 
1134         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1135         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1136         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1137       }
1138     }
1139     /* Interior faces have 4 edges and 2 cells */
1140     for (c = cStart; c < cEnd; ++c) {
1141       for (r = 0; r < 12; ++r) {
1142         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
1143 
1144         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1145         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1146       }
1147     }
1148     /* Split edges have 2 vertices and the same faces as the parent */
1149     for (e = eStart; e < eEnd; ++e) {
1150       for (r = 0; r < 2; ++r) {
1151         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1152         PetscInt       size;
1153 
1154         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1155         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1156         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1157       }
1158     }
1159     /* Face edges have 2 vertices and 2+cells faces */
1160     for (f = fStart; f < fEnd; ++f) {
1161       for (r = 0; r < 4; ++r) {
1162         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
1163         PetscInt       size;
1164 
1165         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1166         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1167         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1168       }
1169     }
1170     /* Cell edges have 2 vertices and 4 faces */
1171     for (c = cStart; c < cEnd; ++c) {
1172       for (r = 0; r < 6; ++r) {
1173         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
1174 
1175         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1176         ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1177       }
1178     }
1179     /* Old vertices have identical supports */
1180     for (v = vStart; v < vEnd; ++v) {
1181       const PetscInt newp = vStartNew + (v - vStart);
1182       PetscInt       size;
1183 
1184       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1185       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1186     }
1187     /* Edge vertices have 2 + faces supports */
1188     for (e = eStart; e < eEnd; ++e) {
1189       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1190       PetscInt       size;
1191 
1192       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1193       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1194     }
1195     /* Face vertices have 4 + cells supports */
1196     for (f = fStart; f < fEnd; ++f) {
1197       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
1198       PetscInt       size;
1199 
1200       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1201       ierr = DMPlexSetSupportSize(rdm, newp, 4 + size);CHKERRQ(ierr);
1202     }
1203     /* Cell vertices have 6 supports */
1204     for (c = cStart; c < cEnd; ++c) {
1205       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
1206 
1207       ierr = DMPlexSetSupportSize(rdm, newp, 6);CHKERRQ(ierr);
1208     }
1209     break;
1210   case REFINER_HYBRID_HEX_3D:
1211     ierr = DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 12*(cMax - cStart),
1212                                  eStartNew + 2*(eMax - eStart) + 4*(fMax - fStart) + 6*(cMax - cStart), PETSC_DETERMINE);CHKERRQ(ierr);
1213     /* Interior cells have 6 faces */
1214     for (c = cStart; c < cMax; ++c) {
1215       for (r = 0; r < 8; ++r) {
1216         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
1217 
1218         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1219       }
1220     }
1221     /* Hybrid cells have 6 faces */
1222     for (c = cMax; c < cEnd; ++c) {
1223       for (r = 0; r < 4; ++r) {
1224         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;
1225 
1226         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1227       }
1228     }
1229     /* Interior split faces have 4 edges and the same cells as the parent */
1230     for (f = fStart; f < fMax; ++f) {
1231       for (r = 0; r < 4; ++r) {
1232         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
1233         PetscInt       size;
1234 
1235         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1236         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1237         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1238       }
1239     }
1240     /* Interior cell faces have 4 edges and 2 cells */
1241     for (c = cStart; c < cMax; ++c) {
1242       for (r = 0; r < 12; ++r) {
1243         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
1244 
1245         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1246         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1247       }
1248     }
1249     /* Hybrid split faces have 4 edges and the same cells as the parent */
1250     for (f = fMax; f < fEnd; ++f) {
1251       for (r = 0; r < 2; ++r) {
1252         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
1253         PetscInt       size;
1254 
1255         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1256         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1257         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1258       }
1259     }
1260     /* Hybrid cells faces have 4 edges and 2 cells */
1261     for (c = cMax; c < cEnd; ++c) {
1262       for (r = 0; r < 4; ++r) {
1263         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + r;
1264 
1265         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1266         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1267       }
1268     }
1269     /* Interior split edges have 2 vertices and the same faces as the parent */
1270     for (e = eStart; e < eMax; ++e) {
1271       for (r = 0; r < 2; ++r) {
1272         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1273         PetscInt       size;
1274 
1275         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1276         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1277         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1278       }
1279     }
1280     /* Interior face edges have 2 vertices and 2+cells faces */
1281     for (f = fStart; f < fMax; ++f) {
1282       for (r = 0; r < 4; ++r) {
1283         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
1284         PetscInt       size;
1285 
1286         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1287         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1288         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1289       }
1290     }
1291     /* Interior cell edges have 2 vertices and 4 faces */
1292     for (c = cStart; c < cMax; ++c) {
1293       for (r = 0; r < 6; ++r) {
1294         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
1295 
1296         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1297         ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1298       }
1299     }
1300     /* Hybrid edges have 2 vertices and the same faces */
1301     for (e = eMax; e < eEnd; ++e) {
1302       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
1303       PetscInt       size;
1304 
1305       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1306       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1307       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1308     }
1309     /* Hybrid face edges have 2 vertices and 2+cells faces */
1310     for (f = fMax; f < fEnd; ++f) {
1311       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
1312       PetscInt       size;
1313 
1314       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1315       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1316       ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1317     }
1318     /* Hybrid cell edges have 2 vertices and 4 faces */
1319     for (c = cMax; c < cEnd; ++c) {
1320       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
1321 
1322       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1323       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1324     }
1325     /* Interior vertices have identical supports */
1326     for (v = vStart; v < vEnd; ++v) {
1327       const PetscInt newp = vStartNew + (v - vStart);
1328       PetscInt       size;
1329 
1330       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1331       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1332     }
1333     /* Interior edge vertices have 2 + faces supports */
1334     for (e = eStart; e < eMax; ++e) {
1335       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1336       PetscInt       size;
1337 
1338       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1339       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1340     }
1341     /* Interior face vertices have 4 + cells supports */
1342     for (f = fStart; f < fMax; ++f) {
1343       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
1344       PetscInt       size;
1345 
1346       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1347       ierr = DMPlexSetSupportSize(rdm, newp, 4 + size);CHKERRQ(ierr);
1348     }
1349     /* Interior cell vertices have 6 supports */
1350     for (c = cStart; c < cMax; ++c) {
1351       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
1352 
1353       ierr = DMPlexSetSupportSize(rdm, newp, 6);CHKERRQ(ierr);
1354     }
1355     break;
1356   default:
1357     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
1358   }
1359   PetscFunctionReturn(0);
1360 }
1361 
1362 static PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
1363 {
1364   const PetscInt *faces, cellInd[4] = {0, 1, 2, 3};
1365   PetscInt        cStart,    cEnd,    cMax,    vStart,    vEnd, vMax, fStart,    fEnd,    fMax,    eStart,    eEnd,    eMax;
1366   PetscInt        cStartNew, cEndNew, cMaxNew, vStartNew, vEndNew,    fStartNew, fEndNew, fMaxNew, eStartNew, eEndNew, eMaxNew;
1367   PetscInt        depth, maxSupportSize, *supportRef, c, f, e, v, r, p;
1368   PetscErrorCode  ierr;
1369 
1370   PetscFunctionBegin;
1371   if (!refiner) PetscFunctionReturn(0);
1372   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1373   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
1374   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
1375   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1376   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
1377   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
1378   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
1379   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
1380   switch (refiner) {
1381   case REFINER_SIMPLEX_1D:
1382     /* Max support size of refined mesh is 2 */
1383     ierr = PetscMalloc1(2, &supportRef);CHKERRQ(ierr);
1384     /* All cells have 2 vertices */
1385     for (c = cStart; c < cEnd; ++c) {
1386       const PetscInt  newv = vStartNew + (vEnd - vStart) + (c - cStart);
1387 
1388       for (r = 0; r < 2; ++r) {
1389         const PetscInt newp = cStartNew + (c - cStart)*2 + r;
1390         const PetscInt *cone;
1391         PetscInt        coneNew[2];
1392 
1393         ierr             = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1394         coneNew[0]       = vStartNew + (cone[0] - vStart);
1395         coneNew[1]       = vStartNew + (cone[1] - vStart);
1396         coneNew[(r+1)%2] = newv;
1397         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1398 #if 1
1399         if ((newp < cStartNew) || (newp >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp, cStartNew, cEndNew);
1400         for (p = 0; p < 2; ++p) {
1401           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);
1402         }
1403 #endif
1404       }
1405     }
1406     /* Old vertices have identical supports */
1407     for (v = vStart; v < vEnd; ++v) {
1408       const PetscInt  newp = vStartNew + (v - vStart);
1409       const PetscInt *support, *cone;
1410       PetscInt        size, s;
1411 
1412       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1413       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1414       for (s = 0; s < size; ++s) {
1415         PetscInt r = 0;
1416 
1417         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1418         if (cone[1] == v) r = 1;
1419         supportRef[s] = cStartNew + (support[s] - cStart)*2 + r;
1420       }
1421       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1422 #if 1
1423       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1424       for (p = 0; p < size; ++p) {
1425         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);
1426       }
1427 #endif
1428     }
1429     /* Cell vertices have support of 2 cells */
1430     for (c = cStart; c < cEnd; ++c) {
1431       const PetscInt  newp = vStartNew + (vEnd - vStart) + (c - cStart);
1432 
1433       supportRef[0] = cStartNew + (c - cStart)*2 + 0;
1434       supportRef[1] = cStartNew + (c - cStart)*2 + 1;
1435       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1436 #if 1
1437       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1438       for (p = 0; p < 2; ++p) {
1439         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);
1440       }
1441 #endif
1442     }
1443     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1444     break;
1445   case REFINER_SIMPLEX_2D:
1446     /*
1447      2
1448      |\
1449      | \
1450      |  \
1451      |   \
1452      | C  \
1453      |     \
1454      |      \
1455      2---1---1
1456      |\  D  / \
1457      | 2   0   \
1458      |A \ /  B  \
1459      0---0-------1
1460      */
1461     /* All cells have 3 faces */
1462     for (c = cStart; c < cEnd; ++c) {
1463       const PetscInt  newp = cStartNew + (c - cStart)*4;
1464       const PetscInt *cone, *ornt;
1465       PetscInt        coneNew[3], orntNew[3];
1466 
1467       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1468       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1469       /* A triangle */
1470       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1471       orntNew[0] = ornt[0];
1472       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1473       orntNew[1] = -2;
1474       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1475       orntNew[2] = ornt[2];
1476       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1477       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1478 #if 1
1479       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);
1480       for (p = 0; p < 3; ++p) {
1481         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);
1482       }
1483 #endif
1484       /* B triangle */
1485       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1486       orntNew[0] = ornt[0];
1487       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1488       orntNew[1] = ornt[1];
1489       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1490       orntNew[2] = -2;
1491       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1492       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1493 #if 1
1494       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);
1495       for (p = 0; p < 3; ++p) {
1496         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);
1497       }
1498 #endif
1499       /* C triangle */
1500       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1501       orntNew[0] = -2;
1502       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1503       orntNew[1] = ornt[1];
1504       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1505       orntNew[2] = ornt[2];
1506       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1507       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1508 #if 1
1509       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);
1510       for (p = 0; p < 3; ++p) {
1511         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);
1512       }
1513 #endif
1514       /* D triangle */
1515       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1516       orntNew[0] = 0;
1517       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1518       orntNew[1] = 0;
1519       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1520       orntNew[2] = 0;
1521       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1522       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1523 #if 1
1524       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);
1525       for (p = 0; p < 3; ++p) {
1526         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);
1527       }
1528 #endif
1529     }
1530     /* Split faces have 2 vertices and the same cells as the parent */
1531     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1532     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
1533     for (f = fStart; f < fEnd; ++f) {
1534       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1535 
1536       for (r = 0; r < 2; ++r) {
1537         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1538         const PetscInt *cone, *ornt, *support;
1539         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1540 
1541         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1542         coneNew[0]       = vStartNew + (cone[0] - vStart);
1543         coneNew[1]       = vStartNew + (cone[1] - vStart);
1544         coneNew[(r+1)%2] = newv;
1545         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1546 #if 1
1547         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1548         for (p = 0; p < 2; ++p) {
1549           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);
1550         }
1551 #endif
1552         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1553         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1554         for (s = 0; s < supportSize; ++s) {
1555           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1556           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1557           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1558           for (c = 0; c < coneSize; ++c) {
1559             if (cone[c] == f) break;
1560           }
1561           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1562         }
1563         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1564 #if 1
1565         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1566         for (p = 0; p < supportSize; ++p) {
1567           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);
1568         }
1569 #endif
1570       }
1571     }
1572     /* Interior faces have 2 vertices and 2 cells */
1573     for (c = cStart; c < cEnd; ++c) {
1574       const PetscInt *cone;
1575 
1576       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1577       for (r = 0; r < 3; ++r) {
1578         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
1579         PetscInt       coneNew[2];
1580         PetscInt       supportNew[2];
1581 
1582         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
1583         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
1584         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1585 #if 1
1586         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1587         for (p = 0; p < 2; ++p) {
1588           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);
1589         }
1590 #endif
1591         supportNew[0] = (c - cStart)*4 + (r+1)%3;
1592         supportNew[1] = (c - cStart)*4 + 3;
1593         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1594 #if 1
1595         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1596         for (p = 0; p < 2; ++p) {
1597           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);
1598         }
1599 #endif
1600       }
1601     }
1602     /* Old vertices have identical supports */
1603     for (v = vStart; v < vEnd; ++v) {
1604       const PetscInt  newp = vStartNew + (v - vStart);
1605       const PetscInt *support, *cone;
1606       PetscInt        size, s;
1607 
1608       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1609       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1610       for (s = 0; s < size; ++s) {
1611         PetscInt r = 0;
1612 
1613         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1614         if (cone[1] == v) r = 1;
1615         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1616       }
1617       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1618 #if 1
1619       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1620       for (p = 0; p < size; ++p) {
1621         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);
1622       }
1623 #endif
1624     }
1625     /* Face vertices have 2 + cells*2 supports */
1626     for (f = fStart; f < fEnd; ++f) {
1627       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1628       const PetscInt *cone, *support;
1629       PetscInt        size, s;
1630 
1631       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1632       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1633       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1634       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1635       for (s = 0; s < size; ++s) {
1636         PetscInt r = 0;
1637 
1638         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1639         if      (cone[1] == f) r = 1;
1640         else if (cone[2] == f) r = 2;
1641         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
1642         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
1643       }
1644       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1645 #if 1
1646       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1647       for (p = 0; p < 2+size*2; ++p) {
1648         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);
1649       }
1650 #endif
1651     }
1652     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1653     break;
1654   case REFINER_SIMPLEX_TO_HEX_2D:
1655     /*
1656      2
1657      |\
1658      | \
1659      |  \
1660      |   \
1661      | C  \
1662      |     \
1663      2      1
1664      |\    / \
1665      | 2  1   \
1666      |  \/     \
1667      |   |      \
1668      |A  |   B   \
1669      |   0        \
1670      |   |         \
1671      0---0----------1
1672      */
1673     /* All cells have 4 faces */
1674     for (c = cStart; c < cEnd; ++c) {
1675       const PetscInt  newp = cStartNew + (c - cStart)*3;
1676       const PetscInt *cone, *ornt;
1677       PetscInt        coneNew[4], orntNew[4];
1678 
1679       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1680       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1681       /* A quad */
1682       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1683       orntNew[0] = ornt[0];
1684       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1685       orntNew[1] = 0;
1686       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1687       orntNew[2] = -2;
1688       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1689       orntNew[3] = ornt[2];
1690       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1691       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1692 #if 1
1693       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);
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       /* B quad */
1699       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1700       orntNew[0] = ornt[0];
1701       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1702       orntNew[1] = ornt[1];
1703       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1704       orntNew[2] = 0;
1705       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1706       orntNew[3] = -2;
1707       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1708       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1709 #if 1
1710       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);
1711       for (p = 0; p < 4; ++p) {
1712         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);
1713       }
1714 #endif
1715       /* C quad */
1716       coneNew[0] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1717       orntNew[0] = ornt[1];
1718       coneNew[1] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1719       orntNew[1] = ornt[2];
1720       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1721       orntNew[2] = 0;
1722       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1723       orntNew[3] = -2;
1724       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1725       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1726 #if 1
1727       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);
1728       for (p = 0; p < 4; ++p) {
1729         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);
1730       }
1731 #endif
1732     }
1733     /* Split faces have 2 vertices and the same cells as the parent */
1734     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1735     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
1736     for (f = fStart; f < fEnd; ++f) {
1737       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1738 
1739       for (r = 0; r < 2; ++r) {
1740         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1741         const PetscInt *cone, *ornt, *support;
1742         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1743 
1744         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1745         coneNew[0]       = vStartNew + (cone[0] - vStart);
1746         coneNew[1]       = vStartNew + (cone[1] - vStart);
1747         coneNew[(r+1)%2] = newv;
1748         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1749 #if 1
1750         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1751         for (p = 0; p < 2; ++p) {
1752           if ((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);
1753         }
1754 #endif
1755         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1756         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1757         for (s = 0; s < supportSize; ++s) {
1758           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1759           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1760           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1761           for (c = 0; c < coneSize; ++c) {
1762             if (cone[c] == f) break;
1763           }
1764           supportRef[s] = cStartNew + (support[s] - cStart)*3 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1765         }
1766         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1767 #if 1
1768         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1769         for (p = 0; p < supportSize; ++p) {
1770           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);
1771         }
1772 #endif
1773       }
1774     }
1775     /* Interior faces have 2 vertices and 2 cells */
1776     for (c = cStart; c < cEnd; ++c) {
1777       const PetscInt *cone;
1778 
1779       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1780       for (r = 0; r < 3; ++r) {
1781         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
1782         PetscInt       coneNew[2];
1783         PetscInt       supportNew[2];
1784 
1785         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
1786         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
1787         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1788 #if 1
1789         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1790         for (p = 0; p < 2; ++p) {
1791           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);
1792         }
1793 #endif
1794         supportNew[0] = (c - cStart)*3 + r%3;
1795         supportNew[1] = (c - cStart)*3 + (r+1)%3;
1796         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1797 #if 1
1798         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1799         for (p = 0; p < 2; ++p) {
1800           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);
1801         }
1802 #endif
1803       }
1804     }
1805     /* Old vertices have identical supports */
1806     for (v = vStart; v < vEnd; ++v) {
1807       const PetscInt  newp = vStartNew + (v - vStart);
1808       const PetscInt *support, *cone;
1809       PetscInt        size, s;
1810 
1811       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1812       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1813       for (s = 0; s < size; ++s) {
1814         PetscInt r = 0;
1815 
1816         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1817         if (cone[1] == v) r = 1;
1818         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1819       }
1820       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1821 #if 1
1822       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1823       for (p = 0; p < size; ++p) {
1824         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);
1825       }
1826 #endif
1827     }
1828     /* Split-face vertices have cells + 2 supports */
1829     for (f = fStart; f < fEnd; ++f) {
1830       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1831       const PetscInt *cone, *support;
1832       PetscInt        size, s;
1833 
1834       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1835       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1836       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1837       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1838       for (s = 0; s < size; ++s) {
1839         PetscInt r = 0;
1840 
1841         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1842         if      (cone[1] == f) r = 1;
1843         else if (cone[2] == f) r = 2;
1844         supportRef[2+s+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
1845       }
1846       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1847 #if 1
1848       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1849       for (p = 0; p < 2+size; ++p) {
1850         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);
1851       }
1852 #endif
1853     }
1854     /* Interior vertices vertices have 3 supports */
1855     for (c = cStart; c < cEnd; ++c) {
1856       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
1857 
1858       supportRef[0] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 0;
1859       supportRef[1] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 1;
1860       supportRef[2] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 2;
1861       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1862     }
1863     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1864     break;
1865   case REFINER_HEX_2D:
1866     /*
1867      3---------2---------2
1868      |         |         |
1869      |    D    2    C    |
1870      |         |         |
1871      3----3----0----1----1
1872      |         |         |
1873      |    A    0    B    |
1874      |         |         |
1875      0---------0---------1
1876      */
1877     /* All cells have 4 faces */
1878     for (c = cStart; c < cEnd; ++c) {
1879       const PetscInt  newp = (c - cStart)*4;
1880       const PetscInt *cone, *ornt;
1881       PetscInt        coneNew[4], orntNew[4];
1882 
1883       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1884       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1885       /* A quad */
1886       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1887       orntNew[0] = ornt[0];
1888       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
1889       orntNew[1] = 0;
1890       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
1891       orntNew[2] = -2;
1892       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
1893       orntNew[3] = ornt[3];
1894       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1895       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1896 #if 1
1897       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);
1898       for (p = 0; p < 4; ++p) {
1899         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);
1900       }
1901 #endif
1902       /* B quad */
1903       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1904       orntNew[0] = ornt[0];
1905       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1906       orntNew[1] = ornt[1];
1907       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
1908       orntNew[2] = -2;
1909       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
1910       orntNew[3] = -2;
1911       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1912       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1913 #if 1
1914       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);
1915       for (p = 0; p < 4; ++p) {
1916         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);
1917       }
1918 #endif
1919       /* C quad */
1920       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
1921       orntNew[0] = 0;
1922       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1923       orntNew[1] = ornt[1];
1924       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1925       orntNew[2] = ornt[2];
1926       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
1927       orntNew[3] = -2;
1928       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1929       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1930 #if 1
1931       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);
1932       for (p = 0; p < 4; ++p) {
1933         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);
1934       }
1935 #endif
1936       /* D quad */
1937       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
1938       orntNew[0] = 0;
1939       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
1940       orntNew[1] = 0;
1941       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1942       orntNew[2] = ornt[2];
1943       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
1944       orntNew[3] = ornt[3];
1945       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1946       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1947 #if 1
1948       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);
1949       for (p = 0; p < 4; ++p) {
1950         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);
1951       }
1952 #endif
1953     }
1954     /* Split faces have 2 vertices and the same cells as the parent */
1955     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1956     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
1957     for (f = fStart; f < fEnd; ++f) {
1958       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1959 
1960       for (r = 0; r < 2; ++r) {
1961         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1962         const PetscInt *cone, *ornt, *support;
1963         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1964 
1965         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1966         coneNew[0]       = vStartNew + (cone[0] - vStart);
1967         coneNew[1]       = vStartNew + (cone[1] - vStart);
1968         coneNew[(r+1)%2] = newv;
1969         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1970 #if 1
1971         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1972         for (p = 0; p < 2; ++p) {
1973           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);
1974         }
1975 #endif
1976         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1977         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1978         for (s = 0; s < supportSize; ++s) {
1979           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1980           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1981           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1982           for (c = 0; c < coneSize; ++c) {
1983             if (cone[c] == f) break;
1984           }
1985           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
1986         }
1987         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1988 #if 1
1989         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1990         for (p = 0; p < supportSize; ++p) {
1991           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);
1992         }
1993 #endif
1994       }
1995     }
1996     /* Interior faces have 2 vertices and 2 cells */
1997     for (c = cStart; c < cEnd; ++c) {
1998       const PetscInt *cone;
1999       PetscInt        coneNew[2], supportNew[2];
2000 
2001       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2002       for (r = 0; r < 4; ++r) {
2003         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
2004 
2005 	if (r==1 || r==2) {
2006           coneNew[0] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
2007           coneNew[1] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2008 	} else {
2009           coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2010           coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
2011 	}
2012 	ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2013 #if 1
2014         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2015         for (p = 0; p < 2; ++p) {
2016           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);
2017         }
2018 #endif
2019         supportNew[0] = (c - cStart)*4 + r;
2020         supportNew[1] = (c - cStart)*4 + (r+1)%4;
2021         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2022 #if 1
2023         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2024         for (p = 0; p < 2; ++p) {
2025           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);
2026         }
2027 #endif
2028       }
2029     }
2030     /* Old vertices have identical supports */
2031     for (v = vStart; v < vEnd; ++v) {
2032       const PetscInt  newp = vStartNew + (v - vStart);
2033       const PetscInt *support, *cone;
2034       PetscInt        size, s;
2035 
2036       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2037       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2038       for (s = 0; s < size; ++s) {
2039         PetscInt r = 0;
2040 
2041         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2042         if (cone[1] == v) r = 1;
2043         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2044       }
2045       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2046 #if 1
2047       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2048       for (p = 0; p < size; ++p) {
2049         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);
2050       }
2051 #endif
2052     }
2053     /* Face vertices have 2 + cells supports */
2054     for (f = fStart; f < fEnd; ++f) {
2055       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2056       const PetscInt *cone, *support;
2057       PetscInt        size, s;
2058 
2059       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2060       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2061       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2062       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2063       for (s = 0; s < size; ++s) {
2064         PetscInt r = 0;
2065 
2066         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2067         if      (cone[1] == f) r = 1;
2068         else if (cone[2] == f) r = 2;
2069         else if (cone[3] == f) r = 3;
2070         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
2071       }
2072       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2073 #if 1
2074       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2075       for (p = 0; p < 2+size; ++p) {
2076         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);
2077       }
2078 #endif
2079     }
2080     /* Cell vertices have 4 supports */
2081     for (c = cStart; c < cEnd; ++c) {
2082       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
2083       PetscInt       supportNew[4];
2084 
2085       for (r = 0; r < 4; ++r) {
2086         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
2087       }
2088       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2089     }
2090     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2091     break;
2092   case REFINER_HYBRID_SIMPLEX_2D:
2093     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
2094     cMax = PetscMin(cEnd, cMax);
2095     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
2096     fMax = PetscMin(fEnd, fMax);
2097     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);CHKERRQ(ierr);
2098     /* Interior cells have 3 faces */
2099     for (c = cStart; c < cMax; ++c) {
2100       const PetscInt  newp = cStartNew + (c - cStart)*4;
2101       const PetscInt *cone, *ornt;
2102       PetscInt        coneNew[3], orntNew[3];
2103 
2104       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2105       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2106       /* A triangle */
2107       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2108       orntNew[0] = ornt[0];
2109       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
2110       orntNew[1] = -2;
2111       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2112       orntNew[2] = ornt[2];
2113       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2114       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2115 #if 1
2116       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);
2117       for (p = 0; p < 3; ++p) {
2118         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);
2119       }
2120 #endif
2121       /* B triangle */
2122       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2123       orntNew[0] = ornt[0];
2124       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2125       orntNew[1] = ornt[1];
2126       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
2127       orntNew[2] = -2;
2128       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2129       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2130 #if 1
2131       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);
2132       for (p = 0; p < 3; ++p) {
2133         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);
2134       }
2135 #endif
2136       /* C triangle */
2137       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
2138       orntNew[0] = -2;
2139       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2140       orntNew[1] = ornt[1];
2141       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2142       orntNew[2] = ornt[2];
2143       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2144       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2145 #if 1
2146       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);
2147       for (p = 0; p < 3; ++p) {
2148         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);
2149       }
2150 #endif
2151       /* D triangle */
2152       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
2153       orntNew[0] = 0;
2154       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
2155       orntNew[1] = 0;
2156       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
2157       orntNew[2] = 0;
2158       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2159       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2160 #if 1
2161       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);
2162       for (p = 0; p < 3; ++p) {
2163         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);
2164       }
2165 #endif
2166     }
2167     /*
2168      2----3----3
2169      |         |
2170      |    B    |
2171      |         |
2172      0----4--- 1
2173      |         |
2174      |    A    |
2175      |         |
2176      0----2----1
2177      */
2178     /* Hybrid cells have 4 faces */
2179     for (c = cMax; c < cEnd; ++c) {
2180       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
2181       const PetscInt *cone, *ornt;
2182       PetscInt        coneNew[4], orntNew[4], r;
2183 
2184       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2185       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2186       r    = (ornt[0] < 0 ? 1 : 0);
2187       /* A quad */
2188       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + r;
2189       orntNew[0]   = ornt[0];
2190       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + r;
2191       orntNew[1]   = ornt[1];
2192       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2+r] - fMax);
2193       orntNew[2+r] = 0;
2194       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
2195       orntNew[3-r] = 0;
2196       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2197       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2198 #if 1
2199       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);
2200       for (p = 0; p < 4; ++p) {
2201         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);
2202       }
2203 #endif
2204       /* B quad */
2205       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + 1-r;
2206       orntNew[0]   = ornt[0];
2207       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + 1-r;
2208       orntNew[1]   = ornt[1];
2209       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
2210       orntNew[2+r] = 0;
2211       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3-r] - fMax);
2212       orntNew[3-r] = 0;
2213       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2214       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2215 #if 1
2216       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);
2217       for (p = 0; p < 4; ++p) {
2218         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);
2219       }
2220 #endif
2221     }
2222     /* Interior split faces have 2 vertices and the same cells as the parent */
2223     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2224     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2225     for (f = fStart; f < fMax; ++f) {
2226       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
2227 
2228       for (r = 0; r < 2; ++r) {
2229         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2230         const PetscInt *cone, *ornt, *support;
2231         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2232 
2233         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2234         coneNew[0]       = vStartNew + (cone[0] - vStart);
2235         coneNew[1]       = vStartNew + (cone[1] - vStart);
2236         coneNew[(r+1)%2] = newv;
2237         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2238 #if 1
2239         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2240         for (p = 0; p < 2; ++p) {
2241           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);
2242         }
2243 #endif
2244         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2245         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2246         for (s = 0; s < supportSize; ++s) {
2247           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2248           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2249           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2250           for (c = 0; c < coneSize; ++c) if (cone[c] == f) break;
2251           if (support[s] >= cMax) {
2252             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[c] < 0 ? 1-r : r);
2253           } else {
2254             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
2255           }
2256         }
2257         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2258 #if 1
2259         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2260         for (p = 0; p < supportSize; ++p) {
2261           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);
2262         }
2263 #endif
2264       }
2265     }
2266     /* Interior cell faces have 2 vertices and 2 cells */
2267     for (c = cStart; c < cMax; ++c) {
2268       const PetscInt *cone;
2269 
2270       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2271       for (r = 0; r < 3; ++r) {
2272         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
2273         PetscInt       coneNew[2];
2274         PetscInt       supportNew[2];
2275 
2276         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
2277         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
2278         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2279 #if 1
2280         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2281         for (p = 0; p < 2; ++p) {
2282           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);
2283         }
2284 #endif
2285         supportNew[0] = (c - cStart)*4 + (r+1)%3;
2286         supportNew[1] = (c - cStart)*4 + 3;
2287         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2288 #if 1
2289         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2290         for (p = 0; p < 2; ++p) {
2291           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);
2292         }
2293 #endif
2294       }
2295     }
2296     /* Interior hybrid faces have 2 vertices and the same cells */
2297     for (f = fMax; f < fEnd; ++f) {
2298       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
2299       const PetscInt *cone, *ornt;
2300       const PetscInt *support;
2301       PetscInt        coneNew[2];
2302       PetscInt        supportNew[2];
2303       PetscInt        size, s, r;
2304 
2305       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2306       coneNew[0] = vStartNew + (cone[0] - vStart);
2307       coneNew[1] = vStartNew + (cone[1] - vStart);
2308       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2309 #if 1
2310       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2311       for (p = 0; p < 2; ++p) {
2312         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);
2313       }
2314 #endif
2315       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2316       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2317       for (s = 0; s < size; ++s) {
2318         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2319         ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2320         for (r = 0; r < 2; ++r) {
2321           if (cone[r+2] == f) break;
2322         }
2323         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[0] < 0 ? 1-r : r);
2324       }
2325       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2326 #if 1
2327       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2328       for (p = 0; p < size; ++p) {
2329         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);
2330       }
2331 #endif
2332     }
2333     /* Cell hybrid faces have 2 vertices and 2 cells */
2334     for (c = cMax; c < cEnd; ++c) {
2335       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
2336       const PetscInt *cone;
2337       PetscInt        coneNew[2];
2338       PetscInt        supportNew[2];
2339 
2340       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2341       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
2342       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
2343       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2344 #if 1
2345       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2346       for (p = 0; p < 2; ++p) {
2347         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);
2348       }
2349 #endif
2350       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
2351       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
2352       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2353 #if 1
2354       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2355       for (p = 0; p < 2; ++p) {
2356         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);
2357       }
2358 #endif
2359     }
2360     /* Old vertices have identical supports */
2361     for (v = vStart; v < vEnd; ++v) {
2362       const PetscInt  newp = vStartNew + (v - vStart);
2363       const PetscInt *support, *cone;
2364       PetscInt        size, s;
2365 
2366       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2367       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2368       for (s = 0; s < size; ++s) {
2369         if (support[s] >= fMax) {
2370           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
2371         } else {
2372           PetscInt r = 0;
2373 
2374           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2375           if (cone[1] == v) r = 1;
2376           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2377         }
2378       }
2379       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2380 #if 1
2381       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2382       for (p = 0; p < size; ++p) {
2383         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);
2384       }
2385 #endif
2386     }
2387     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
2388     for (f = fStart; f < fMax; ++f) {
2389       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2390       const PetscInt *cone, *support;
2391       PetscInt        size, newSize = 2, s;
2392 
2393       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2394       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2395       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2396       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2397       for (s = 0; s < size; ++s) {
2398         PetscInt r = 0;
2399 
2400         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2401         if (support[s] >= cMax) {
2402           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
2403 
2404           newSize += 1;
2405         } else {
2406           if      (cone[1] == f) r = 1;
2407           else if (cone[2] == f) r = 2;
2408           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
2409           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
2410 
2411           newSize += 2;
2412         }
2413       }
2414       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2415 #if 1
2416       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2417       for (p = 0; p < newSize; ++p) {
2418         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);
2419       }
2420 #endif
2421     }
2422     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2423     break;
2424   case REFINER_HYBRID_HEX_2D:
2425     /* Hybrid Hex 2D */
2426     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
2427     cMax = PetscMin(cEnd, cMax);
2428     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
2429     fMax = PetscMin(fEnd, fMax);
2430     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);CHKERRQ(ierr);
2431     /* Interior cells have 4 faces */
2432     for (c = cStart; c < cMax; ++c) {
2433       const PetscInt  newp = cStartNew + (c - cStart)*4;
2434       const PetscInt *cone, *ornt;
2435       PetscInt        coneNew[4], orntNew[4];
2436 
2437       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2438       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2439       /* A quad */
2440       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2441       orntNew[0] = ornt[0];
2442       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
2443       orntNew[1] = 0;
2444       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
2445       orntNew[2] = -2;
2446       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
2447       orntNew[3] = ornt[3];
2448       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2449       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2450 #if 1
2451       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);
2452       for (p = 0; p < 4; ++p) {
2453         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);
2454       }
2455 #endif
2456       /* B quad */
2457       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2458       orntNew[0] = ornt[0];
2459       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2460       orntNew[1] = ornt[1];
2461       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
2462       orntNew[2] = 0;
2463       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
2464       orntNew[3] = -2;
2465       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2466       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2467 #if 1
2468       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);
2469       for (p = 0; p < 4; ++p) {
2470         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);
2471       }
2472 #endif
2473       /* C quad */
2474       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
2475       orntNew[0] = -2;
2476       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2477       orntNew[1] = ornt[1];
2478       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2479       orntNew[2] = ornt[2];
2480       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
2481       orntNew[3] = 0;
2482       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2483       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2484 #if 1
2485       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);
2486       for (p = 0; p < 4; ++p) {
2487         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);
2488       }
2489 #endif
2490       /* D quad */
2491       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
2492       orntNew[0] = 0;
2493       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
2494       orntNew[1] = -2;
2495       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2496       orntNew[2] = ornt[2];
2497       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
2498       orntNew[3] = ornt[3];
2499       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2500       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2501 #if 1
2502       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);
2503       for (p = 0; p < 4; ++p) {
2504         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);
2505       }
2506 #endif
2507     }
2508     /*
2509      2----3----3
2510      |         |
2511      |    B    |
2512      |         |
2513      0----4--- 1
2514      |         |
2515      |    A    |
2516      |         |
2517      0----2----1
2518      */
2519     /* Hybrid cells have 4 faces */
2520     for (c = cMax; c < cEnd; ++c) {
2521       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
2522       const PetscInt *cone, *ornt;
2523       PetscInt        coneNew[4], orntNew[4];
2524 
2525       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2526       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2527       /* A quad */
2528       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2529       orntNew[0] = ornt[0];
2530       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2531       orntNew[1] = ornt[1];
2532       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[2] - fMax);
2533       orntNew[2] = 0;
2534       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
2535       orntNew[3] = 0;
2536       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2537       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2538 #if 1
2539       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);
2540       for (p = 0; p < 4; ++p) {
2541         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);
2542       }
2543 #endif
2544       /* B quad */
2545       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2546       orntNew[0] = ornt[0];
2547       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2548       orntNew[1] = ornt[1];
2549       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
2550       orntNew[2] = 0;
2551       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[3] - fMax);
2552       orntNew[3] = 0;
2553       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2554       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2555 #if 1
2556       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);
2557       for (p = 0; p < 4; ++p) {
2558         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);
2559       }
2560 #endif
2561     }
2562     /* Interior split faces have 2 vertices and the same cells as the parent */
2563     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2564     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2565     for (f = fStart; f < fMax; ++f) {
2566       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
2567 
2568       for (r = 0; r < 2; ++r) {
2569         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2570         const PetscInt *cone, *ornt, *support;
2571         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2572 
2573         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2574         coneNew[0]       = vStartNew + (cone[0] - vStart);
2575         coneNew[1]       = vStartNew + (cone[1] - vStart);
2576         coneNew[(r+1)%2] = newv;
2577         ierr             = DMPlexSetCone(rdm, newp, coneNew);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 < 2; ++p) {
2581           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);
2582         }
2583 #endif
2584         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2585         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2586         for (s = 0; s < supportSize; ++s) {
2587           if (support[s] >= cMax) {
2588             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
2589           } else {
2590             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2591             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2592             ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2593             for (c = 0; c < coneSize; ++c) {
2594               if (cone[c] == f) break;
2595             }
2596             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
2597           }
2598         }
2599         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2600 #if 1
2601         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2602         for (p = 0; p < supportSize; ++p) {
2603           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);
2604         }
2605 #endif
2606       }
2607     }
2608     /* Interior cell faces have 2 vertices and 2 cells */
2609     for (c = cStart; c < cMax; ++c) {
2610       const PetscInt *cone;
2611 
2612       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2613       for (r = 0; r < 4; ++r) {
2614         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
2615         PetscInt       coneNew[2], supportNew[2];
2616 
2617         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2618         coneNew[1] = vStartNew + (vEnd - vStart) + (fMax    - fStart) + (c - cStart);
2619         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2620 #if 1
2621         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2622         for (p = 0; p < 2; ++p) {
2623           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);
2624         }
2625 #endif
2626         supportNew[0] = (c - cStart)*4 + r;
2627         supportNew[1] = (c - cStart)*4 + (r+1)%4;
2628         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2629 #if 1
2630         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2631         for (p = 0; p < 2; ++p) {
2632           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);
2633         }
2634 #endif
2635       }
2636     }
2637     /* Hybrid faces have 2 vertices and the same cells */
2638     for (f = fMax; f < fEnd; ++f) {
2639       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
2640       const PetscInt *cone, *support;
2641       PetscInt        coneNew[2], supportNew[2];
2642       PetscInt        size, s, r;
2643 
2644       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2645       coneNew[0] = vStartNew + (cone[0] - vStart);
2646       coneNew[1] = vStartNew + (cone[1] - vStart);
2647       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2648 #if 1
2649       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2650       for (p = 0; p < 2; ++p) {
2651         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);
2652       }
2653 #endif
2654       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2655       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2656       for (s = 0; s < size; ++s) {
2657         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2658         for (r = 0; r < 2; ++r) {
2659           if (cone[r+2] == f) break;
2660         }
2661         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
2662       }
2663       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2664 #if 1
2665       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2666       for (p = 0; p < size; ++p) {
2667         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);
2668       }
2669 #endif
2670     }
2671     /* Cell hybrid faces have 2 vertices and 2 cells */
2672     for (c = cMax; c < cEnd; ++c) {
2673       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
2674       const PetscInt *cone;
2675       PetscInt        coneNew[2], supportNew[2];
2676 
2677       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2678       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
2679       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
2680       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2681 #if 1
2682       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2683       for (p = 0; p < 2; ++p) {
2684         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);
2685       }
2686 #endif
2687       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
2688       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
2689       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2690 #if 1
2691       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2692       for (p = 0; p < 2; ++p) {
2693         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);
2694       }
2695 #endif
2696     }
2697     /* Old vertices have identical supports */
2698     for (v = vStart; v < vEnd; ++v) {
2699       const PetscInt  newp = vStartNew + (v - vStart);
2700       const PetscInt *support, *cone;
2701       PetscInt        size, s;
2702 
2703       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2704       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2705       for (s = 0; s < size; ++s) {
2706         if (support[s] >= fMax) {
2707           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (support[s] - fMax);
2708         } else {
2709           PetscInt r = 0;
2710 
2711           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2712           if (cone[1] == v) r = 1;
2713           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2714         }
2715       }
2716       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2717 #if 1
2718       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2719       for (p = 0; p < size; ++p) {
2720         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);
2721       }
2722 #endif
2723     }
2724     /* Face vertices have 2 + cells supports */
2725     for (f = fStart; f < fMax; ++f) {
2726       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2727       const PetscInt *cone, *support;
2728       PetscInt        size, s;
2729 
2730       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2731       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2732       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2733       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2734       for (s = 0; s < size; ++s) {
2735         PetscInt r = 0;
2736 
2737         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2738         if (support[s] >= cMax) {
2739           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (support[s] - cMax);
2740         } else {
2741           if      (cone[1] == f) r = 1;
2742           else if (cone[2] == f) r = 2;
2743           else if (cone[3] == f) r = 3;
2744           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*4 + r;
2745         }
2746       }
2747       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2748 #if 1
2749       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2750       for (p = 0; p < 2+size; ++p) {
2751         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);
2752       }
2753 #endif
2754     }
2755     /* Cell vertices have 4 supports */
2756     for (c = cStart; c < cMax; ++c) {
2757       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
2758       PetscInt       supportNew[4];
2759 
2760       for (r = 0; r < 4; ++r) {
2761         supportNew[r] = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
2762       }
2763       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2764     }
2765     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2766     break;
2767   case REFINER_SIMPLEX_3D:
2768     /* All cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
2769     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
2770     for (c = cStart; c < cEnd; ++c) {
2771       const PetscInt  newp = cStartNew + (c - cStart)*8;
2772       const PetscInt *cone, *ornt;
2773       PetscInt        coneNew[4], orntNew[4];
2774 
2775       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2776       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2777       /* A tetrahedron: {0, a, c, d} */
2778       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
2779       orntNew[0] = ornt[0];
2780       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
2781       orntNew[1] = ornt[1];
2782       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
2783       orntNew[2] = ornt[2];
2784       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
2785       orntNew[3] = 0;
2786       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2787       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2788 #if 1
2789       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);
2790       for (p = 0; p < 4; ++p) {
2791         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);
2792       }
2793 #endif
2794       /* B tetrahedron: {a, 1, b, e} */
2795       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
2796       orntNew[0] = ornt[0];
2797       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
2798       orntNew[1] = ornt[1];
2799       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
2800       orntNew[2] = 0;
2801       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
2802       orntNew[3] = ornt[3];
2803       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2804       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2805 #if 1
2806       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);
2807       for (p = 0; p < 4; ++p) {
2808         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);
2809       }
2810 #endif
2811       /* C tetrahedron: {c, b, 2, f} */
2812       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
2813       orntNew[0] = ornt[0];
2814       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
2815       orntNew[1] = 0;
2816       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
2817       orntNew[2] = ornt[2];
2818       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
2819       orntNew[3] = ornt[3];
2820       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2821       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2822 #if 1
2823       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);
2824       for (p = 0; p < 4; ++p) {
2825         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);
2826       }
2827 #endif
2828       /* D tetrahedron: {d, e, f, 3} */
2829       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
2830       orntNew[0] = 0;
2831       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
2832       orntNew[1] = ornt[1];
2833       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
2834       orntNew[2] = ornt[2];
2835       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
2836       orntNew[3] = ornt[3];
2837       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2838       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2839 #if 1
2840       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);
2841       for (p = 0; p < 4; ++p) {
2842         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);
2843       }
2844 #endif
2845       /* A' tetrahedron: {c, d, a, f} */
2846       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
2847       orntNew[0] = -3;
2848       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
2849       orntNew[1] = ornt[2] < 0 ? -(GetTriMidEdge_Static(ornt[2], 0)+1) : GetTriMidEdge_Static(ornt[2], 0);
2850       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
2851       orntNew[2] = 0;
2852       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
2853       orntNew[3] = 2;
2854       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
2855       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
2856 #if 1
2857       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);
2858       for (p = 0; p < 4; ++p) {
2859         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);
2860       }
2861 #endif
2862       /* B' tetrahedron: {e, b, a, f} */
2863       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
2864       orntNew[0] = -2;
2865       coneNew[1] = fStartNew + (cone[3] - fStart)*4 + 3;
2866       orntNew[1] = ornt[3] < 0 ? -(GetTriMidEdge_Static(ornt[3], 1)+1) : GetTriMidEdge_Static(ornt[3], 1);
2867       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
2868       orntNew[2] = 0;
2869       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
2870       orntNew[3] = 0;
2871       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
2872       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
2873 #if 1
2874       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);
2875       for (p = 0; p < 4; ++p) {
2876         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);
2877       }
2878 #endif
2879       /* C' tetrahedron: {f, a, c, b} */
2880       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
2881       orntNew[0] = -2;
2882       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
2883       orntNew[1] = -2;
2884       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
2885       orntNew[2] = -1;
2886       coneNew[3] = fStartNew + (cone[0] - fStart)*4 + 3;
2887       orntNew[3] = ornt[0] < 0 ? -(GetTriMidEdge_Static(ornt[0], 2)+1) : GetTriMidEdge_Static(ornt[0], 2);
2888       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
2889       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
2890 #if 1
2891       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);
2892       for (p = 0; p < 4; ++p) {
2893         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);
2894       }
2895 #endif
2896       /* D' tetrahedron: {f, a, e, d} */
2897       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
2898       orntNew[0] = -2;
2899       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
2900       orntNew[1] = -1;
2901       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
2902       orntNew[2] = -2;
2903       coneNew[3] = fStartNew + (cone[1] - fStart)*4 + 3;
2904       orntNew[3] = ornt[1] < 0 ? -(GetTriMidEdge_Static(ornt[1], 1)+1) : GetTriMidEdge_Static(ornt[1], 1);
2905       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
2906       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
2907 #if 1
2908       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);
2909       for (p = 0; p < 4; ++p) {
2910         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);
2911       }
2912 #endif
2913     }
2914     /* Split faces have 3 edges and the same cells as the parent */
2915     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2916     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2917     for (f = fStart; f < fEnd; ++f) {
2918       const PetscInt  newp = fStartNew + (f - fStart)*4;
2919       const PetscInt *cone, *ornt, *support;
2920       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
2921 
2922       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2923       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
2924       /* A triangle */
2925       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
2926       orntNew[0] = ornt[0];
2927       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
2928       orntNew[1] = -2;
2929       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
2930       orntNew[2] = ornt[2];
2931       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2932       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2933 #if 1
2934       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);
2935       for (p = 0; p < 3; ++p) {
2936         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);
2937       }
2938 #endif
2939       /* B triangle */
2940       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
2941       orntNew[0] = ornt[0];
2942       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
2943       orntNew[1] = ornt[1];
2944       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
2945       orntNew[2] = -2;
2946       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2947       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2948 #if 1
2949       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);
2950       for (p = 0; p < 3; ++p) {
2951         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);
2952       }
2953 #endif
2954       /* C triangle */
2955       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
2956       orntNew[0] = -2;
2957       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
2958       orntNew[1] = ornt[1];
2959       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
2960       orntNew[2] = ornt[2];
2961       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2962       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2963 #if 1
2964       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);
2965       for (p = 0; p < 3; ++p) {
2966         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);
2967       }
2968 #endif
2969       /* D triangle */
2970       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
2971       orntNew[0] = 0;
2972       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
2973       orntNew[1] = 0;
2974       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
2975       orntNew[2] = 0;
2976       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2977       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2978 #if 1
2979       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);
2980       for (p = 0; p < 3; ++p) {
2981         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);
2982       }
2983 #endif
2984       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2985       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2986       for (r = 0; r < 4; ++r) {
2987         for (s = 0; s < supportSize; ++s) {
2988           PetscInt subf;
2989           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2990           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2991           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2992           for (c = 0; c < coneSize; ++c) {
2993             if (cone[c] == f) break;
2994           }
2995           subf = GetTriSubfaceInverse_Static(ornt[c], r);
2996           supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
2997         }
2998         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
2999 #if 1
3000         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);
3001         for (p = 0; p < supportSize; ++p) {
3002           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);
3003         }
3004 #endif
3005       }
3006     }
3007     /* Interior faces have 3 edges and 2 cells */
3008     for (c = cStart; c < cEnd; ++c) {
3009       PetscInt        newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8;
3010       const PetscInt *cone, *ornt;
3011       PetscInt        coneNew[3], orntNew[3];
3012       PetscInt        supportNew[2];
3013 
3014       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3015       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3016       /* Face A: {c, a, d} */
3017       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3018       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3019       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3020       orntNew[1] = ornt[1] < 0 ? -2 : 0;
3021       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 2);
3022       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3023       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3024       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3025 #if 1
3026       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3027       for (p = 0; p < 3; ++p) {
3028         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);
3029       }
3030 #endif
3031       supportNew[0] = (c - cStart)*8 + 0;
3032       supportNew[1] = (c - cStart)*8 + 0+4;
3033       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3034 #if 1
3035       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3036       for (p = 0; p < 2; ++p) {
3037         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);
3038       }
3039 #endif
3040       ++newp;
3041       /* Face B: {a, b, e} */
3042       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3043       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3044       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 0);
3045       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3046       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3047       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3048       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3049       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3050 #if 1
3051       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3052       for (p = 0; p < 3; ++p) {
3053         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);
3054       }
3055 #endif
3056       supportNew[0] = (c - cStart)*8 + 1;
3057       supportNew[1] = (c - cStart)*8 + 1+4;
3058       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3059 #if 1
3060       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3061       for (p = 0; p < 2; ++p) {
3062         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);
3063       }
3064 #endif
3065       ++newp;
3066       /* Face C: {c, f, b} */
3067       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3068       orntNew[0] = ornt[2] < 0 ? -2 : 0;
3069       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3070       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3071       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 1);
3072       orntNew[2] = ornt[0] < 0 ? -2 : 0;
3073       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3074       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3075 #if 1
3076       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3077       for (p = 0; p < 3; ++p) {
3078         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);
3079       }
3080 #endif
3081       supportNew[0] = (c - cStart)*8 + 2;
3082       supportNew[1] = (c - cStart)*8 + 2+4;
3083       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3084 #if 1
3085       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3086       for (p = 0; p < 2; ++p) {
3087         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);
3088       }
3089 #endif
3090       ++newp;
3091       /* Face D: {d, e, f} */
3092       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 0);
3093       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3094       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3095       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3096       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3097       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3098       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3099       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3100 #if 1
3101       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3102       for (p = 0; p < 3; ++p) {
3103         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);
3104       }
3105 #endif
3106       supportNew[0] = (c - cStart)*8 + 3;
3107       supportNew[1] = (c - cStart)*8 + 3+4;
3108       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3109 #if 1
3110       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3111       for (p = 0; p < 2; ++p) {
3112         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);
3113       }
3114 #endif
3115       ++newp;
3116       /* Face E: {d, f, a} */
3117       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3118       orntNew[0] = ornt[2] < 0 ? 0 : -2;
3119       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3120       orntNew[1] = -2;
3121       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3122       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3123       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3124       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3125 #if 1
3126       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3127       for (p = 0; p < 3; ++p) {
3128         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);
3129       }
3130 #endif
3131       supportNew[0] = (c - cStart)*8 + 0+4;
3132       supportNew[1] = (c - cStart)*8 + 3+4;
3133       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3134 #if 1
3135       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3136       for (p = 0; p < 2; ++p) {
3137         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);
3138       }
3139 #endif
3140       ++newp;
3141       /* Face F: {c, a, f} */
3142       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3143       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3144       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3145       orntNew[1] = 0;
3146       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3147       orntNew[2] = ornt[2] < 0 ? 0 : -2;
3148       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3149       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3150 #if 1
3151       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3152       for (p = 0; p < 3; ++p) {
3153         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);
3154       }
3155 #endif
3156       supportNew[0] = (c - cStart)*8 + 0+4;
3157       supportNew[1] = (c - cStart)*8 + 2+4;
3158       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3159 #if 1
3160       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3161       for (p = 0; p < 2; ++p) {
3162         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);
3163       }
3164 #endif
3165       ++newp;
3166       /* Face G: {e, a, f} */
3167       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3168       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3169       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3170       orntNew[1] = 0;
3171       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3172       orntNew[2] = ornt[3] < 0 ? 0 : -2;
3173       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3174       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3175 #if 1
3176       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3177       for (p = 0; p < 3; ++p) {
3178         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);
3179       }
3180 #endif
3181       supportNew[0] = (c - cStart)*8 + 1+4;
3182       supportNew[1] = (c - cStart)*8 + 3+4;
3183       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3184 #if 1
3185       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3186       for (p = 0; p < 2; ++p) {
3187         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);
3188       }
3189 #endif
3190       ++newp;
3191       /* Face H: {a, b, f} */
3192       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3193       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3194       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3195       orntNew[1] = ornt[3] < 0 ? 0 : -2;
3196       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3197       orntNew[2] = -2;
3198       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3199       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3200 #if 1
3201       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3202       for (p = 0; p < 3; ++p) {
3203         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);
3204       }
3205 #endif
3206       supportNew[0] = (c - cStart)*8 + 1+4;
3207       supportNew[1] = (c - cStart)*8 + 2+4;
3208       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3209 #if 1
3210       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3211       for (p = 0; p < 2; ++p) {
3212         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);
3213       }
3214 #endif
3215       ++newp;
3216     }
3217     /* Split Edges have 2 vertices and the same faces as the parent */
3218     for (e = eStart; e < eEnd; ++e) {
3219       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
3220 
3221       for (r = 0; r < 2; ++r) {
3222         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
3223         const PetscInt *cone, *ornt, *support;
3224         PetscInt        coneNew[2], coneSize, c, supportSize, s;
3225 
3226         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3227         coneNew[0]       = vStartNew + (cone[0] - vStart);
3228         coneNew[1]       = vStartNew + (cone[1] - vStart);
3229         coneNew[(r+1)%2] = newv;
3230         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3231 #if 1
3232         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3233         for (p = 0; p < 2; ++p) {
3234           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);
3235         }
3236 #endif
3237         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
3238         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3239         for (s = 0; s < supportSize; ++s) {
3240           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3241           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3242           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3243           for (c = 0; c < coneSize; ++c) {
3244             if (cone[c] == e) break;
3245           }
3246           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
3247         }
3248         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3249 #if 1
3250         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3251         for (p = 0; p < supportSize; ++p) {
3252           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);
3253         }
3254 #endif
3255       }
3256     }
3257     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
3258     for (f = fStart; f < fEnd; ++f) {
3259       const PetscInt *cone, *ornt, *support;
3260       PetscInt        coneSize, supportSize, s;
3261 
3262       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3263       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3264       for (r = 0; r < 3; ++r) {
3265         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
3266         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
3267         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
3268                                     -1, -1,  1,  6,  0,  4,
3269                                      2,  5,  3,  4, -1, -1,
3270                                     -1, -1,  3,  6,  2,  7};
3271 
3272         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3273         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
3274         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
3275         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3276 #if 1
3277         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3278         for (p = 0; p < 2; ++p) {
3279           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);
3280         }
3281 #endif
3282         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
3283         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
3284         for (s = 0; s < supportSize; ++s) {
3285           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3286           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3287           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3288           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
3289           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
3290           er = GetTriMidEdgeInverse_Static(ornt[c], r);
3291           if (er == eint[c]) {
3292             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
3293           } else {
3294             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
3295             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
3296           }
3297         }
3298         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3299 #if 1
3300         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3301         for (p = 0; p < intFaces; ++p) {
3302           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);
3303         }
3304 #endif
3305       }
3306     }
3307     /* Interior edges have 2 vertices and 4 faces */
3308     for (c = cStart; c < cEnd; ++c) {
3309       const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3310       const PetscInt *cone, *ornt, *fcone;
3311       PetscInt        coneNew[2], supportNew[4], find;
3312 
3313       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3314       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3315       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
3316       find = GetTriEdge_Static(ornt[0], 0);
3317       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3318       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
3319       find = GetTriEdge_Static(ornt[2], 1);
3320       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3321       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3322 #if 1
3323       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3324       for (p = 0; p < 2; ++p) {
3325         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);
3326       }
3327 #endif
3328       supportNew[0] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 4;
3329       supportNew[1] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 5;
3330       supportNew[2] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 6;
3331       supportNew[3] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 7;
3332       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3333 #if 1
3334       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3335       for (p = 0; p < 4; ++p) {
3336         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);
3337       }
3338 #endif
3339     }
3340     /* Old vertices have identical supports */
3341     for (v = vStart; v < vEnd; ++v) {
3342       const PetscInt  newp = vStartNew + (v - vStart);
3343       const PetscInt *support, *cone;
3344       PetscInt        size, s;
3345 
3346       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
3347       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
3348       for (s = 0; s < size; ++s) {
3349         PetscInt r = 0;
3350 
3351         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3352         if (cone[1] == v) r = 1;
3353         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
3354       }
3355       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3356 #if 1
3357       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3358       for (p = 0; p < size; ++p) {
3359         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);
3360       }
3361 #endif
3362     }
3363     /* Edge vertices have 2 + face*2 + 0/1 supports */
3364     for (e = eStart; e < eEnd; ++e) {
3365       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
3366       const PetscInt *cone, *support;
3367       PetscInt       *star = NULL, starSize, cellSize = 0, coneSize, size, s;
3368 
3369       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
3370       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3371       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
3372       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
3373       for (s = 0; s < size; ++s) {
3374         PetscInt r = 0;
3375 
3376         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3377         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3378         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
3379         supportRef[2+s*2+0] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
3380         supportRef[2+s*2+1] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
3381       }
3382       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
3383       for (s = 0; s < starSize*2; s += 2) {
3384         const PetscInt *cone, *ornt;
3385         PetscInt        e01, e23;
3386 
3387         if ((star[s] >= cStart) && (star[s] < cEnd)) {
3388           /* Check edge 0-1 */
3389           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
3390           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
3391           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
3392           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
3393           /* Check edge 2-3 */
3394           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
3395           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
3396           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
3397           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
3398           if ((e01 == e) || (e23 == e)) {supportRef[2+size*2+cellSize++] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (star[s] - cStart);}
3399         }
3400       }
3401       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
3402       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3403 #if 1
3404       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3405       for (p = 0; p < 2+size*2+cellSize; ++p) {
3406         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);
3407       }
3408 #endif
3409     }
3410     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3411     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
3412     break;
3413   case REFINER_HYBRID_SIMPLEX_3D:
3414     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
3415     /* Interior cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
3416     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
3417     for (c = cStart; c < cMax; ++c) {
3418       const PetscInt  newp = cStartNew + (c - cStart)*8;
3419       const PetscInt *cone, *ornt;
3420       PetscInt        coneNew[4], orntNew[4];
3421 
3422       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3423       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3424       /* A tetrahedron: {0, a, c, d} */
3425       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
3426       orntNew[0] = ornt[0];
3427       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
3428       orntNew[1] = ornt[1];
3429       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
3430       orntNew[2] = ornt[2];
3431       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
3432       orntNew[3] = 0;
3433       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3434       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3435 #if 1
3436       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);
3437       for (p = 0; p < 4; ++p) {
3438         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);
3439       }
3440 #endif
3441       /* B tetrahedron: {a, 1, b, e} */
3442       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
3443       orntNew[0] = ornt[0];
3444       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
3445       orntNew[1] = ornt[1];
3446       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
3447       orntNew[2] = 0;
3448       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
3449       orntNew[3] = ornt[3];
3450       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3451       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3452 #if 1
3453       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);
3454       for (p = 0; p < 4; ++p) {
3455         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);
3456       }
3457 #endif
3458       /* C tetrahedron: {c, b, 2, f} */
3459       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
3460       orntNew[0] = ornt[0];
3461       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
3462       orntNew[1] = 0;
3463       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
3464       orntNew[2] = ornt[2];
3465       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
3466       orntNew[3] = ornt[3];
3467       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3468       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3469 #if 1
3470       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);
3471       for (p = 0; p < 4; ++p) {
3472         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);
3473       }
3474 #endif
3475       /* D tetrahedron: {d, e, f, 3} */
3476       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
3477       orntNew[0] = 0;
3478       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
3479       orntNew[1] = ornt[1];
3480       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
3481       orntNew[2] = ornt[2];
3482       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
3483       orntNew[3] = ornt[3];
3484       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3485       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3486 #if 1
3487       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);
3488       for (p = 0; p < 4; ++p) {
3489         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);
3490       }
3491 #endif
3492       /* A' tetrahedron: {d, a, c, f} */
3493       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
3494       orntNew[0] = -3;
3495       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
3496       orntNew[1] = ornt[2] < 0 ? -(GetTriMidEdge_Static(ornt[2], 0)+1) : GetTriMidEdge_Static(ornt[2], 0);
3497       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
3498       orntNew[2] = 0;
3499       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
3500       orntNew[3] = 2;
3501       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
3502       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
3503 #if 1
3504       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);
3505       for (p = 0; p < 4; ++p) {
3506         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);
3507       }
3508 #endif
3509       /* B' tetrahedron: {e, b, a, f} */
3510       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
3511       orntNew[0] = -3;
3512       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
3513       orntNew[1] = 1;
3514       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
3515       orntNew[2] = 0;
3516       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + 3;
3517       orntNew[3] = ornt[3] < 0 ? -(GetTriMidEdge_Static(ornt[3], 0)+1) : GetTriMidEdge_Static(ornt[3], 0);
3518       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
3519       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
3520 #if 1
3521       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);
3522       for (p = 0; p < 4; ++p) {
3523         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);
3524       }
3525 #endif
3526       /* C' tetrahedron: {b, f, c, a} */
3527       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
3528       orntNew[0] = -3;
3529       coneNew[1] = fStartNew + (cone[0] - fStart)*4 + 3;
3530       orntNew[1] = ornt[0] < 0 ? -(GetTriMidEdge_Static(ornt[0], 2)+1) : GetTriMidEdge_Static(ornt[0], 2);
3531       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
3532       orntNew[2] = -3;
3533       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
3534       orntNew[3] = -2;
3535       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
3536       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
3537 #if 1
3538       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);
3539       for (p = 0; p < 4; ++p) {
3540         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);
3541       }
3542 #endif
3543       /* D' tetrahedron: {f, e, d, a} */
3544       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
3545       orntNew[0] = -3;
3546       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
3547       orntNew[1] = -3;
3548       coneNew[2] = fStartNew + (cone[1] - fStart)*4 + 3;
3549       orntNew[2] = ornt[1] < 0 ? -(GetTriMidEdge_Static(ornt[1], 0)+1) : GetTriMidEdge_Static(ornt[1], 0);
3550       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
3551       orntNew[3] = -3;
3552       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
3553       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
3554 #if 1
3555       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);
3556       for (p = 0; p < 4; ++p) {
3557         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);
3558       }
3559 #endif
3560     }
3561     /* Hybrid cells have 5 faces */
3562     for (c = cMax; c < cEnd; ++c) {
3563       const PetscInt  newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4;
3564       const PetscInt *cone, *ornt, *fornt;
3565       PetscInt        coneNew[5], orntNew[5], o, of, i;
3566 
3567       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3568       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3569       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
3570       o = ornt[0] < 0 ? -1 : 1;
3571       for (r = 0; r < 3; ++r) {
3572         coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], r);
3573         orntNew[0] = ornt[0];
3574         coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], r);
3575         orntNew[1] = ornt[1];
3576         of = fornt[GetTriEdge_Static(ornt[0], r)]       < 0 ? -1 : 1;
3577         i  = GetTriEdgeInverse_Static(ornt[0], r)       + 2;
3578         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], r)]       - fMax)*2 + (o*of < 0 ? 1 : 0);
3579         orntNew[i] = 0;
3580         i  = GetTriEdgeInverse_Static(ornt[0], (r+1)%3) + 2;
3581         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + GetTriSubface_Static(ornt[0], r);
3582         orntNew[i] = 0;
3583         of = fornt[GetTriEdge_Static(ornt[0], (r+2)%3)] < 0 ? -1 : 1;
3584         i  = GetTriEdgeInverse_Static(ornt[0], (r+2)%3) + 2;
3585         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);
3586         orntNew[i] = 0;
3587         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
3588         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
3589 #if 1
3590         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);
3591         for (p = 0; p < 2; ++p) {
3592           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);
3593         }
3594         for (p = 2; p < 5; ++p) {
3595           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);
3596         }
3597 #endif
3598       }
3599       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + 3;
3600       orntNew[0] = 0;
3601       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + 3;
3602       orntNew[1] = 0;
3603       coneNew[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
3604       orntNew[2] = 0;
3605       coneNew[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
3606       orntNew[3] = 0;
3607       coneNew[4] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
3608       orntNew[4] = 0;
3609       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3610       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3611 #if 1
3612       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);
3613       for (p = 0; p < 2; ++p) {
3614         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);
3615       }
3616       for (p = 2; p < 5; ++p) {
3617         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);
3618       }
3619 #endif
3620     }
3621     /* Split faces have 3 edges and the same cells as the parent */
3622     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3623     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
3624     for (f = fStart; f < fMax; ++f) {
3625       const PetscInt  newp = fStartNew + (f - fStart)*4;
3626       const PetscInt *cone, *ornt, *support;
3627       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
3628 
3629       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3630       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3631       /* A triangle */
3632       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
3633       orntNew[0] = ornt[0];
3634       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
3635       orntNew[1] = -2;
3636       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
3637       orntNew[2] = ornt[2];
3638       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3639       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3640 #if 1
3641       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);
3642       for (p = 0; p < 3; ++p) {
3643         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);
3644       }
3645 #endif
3646       /* B triangle */
3647       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
3648       orntNew[0] = ornt[0];
3649       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
3650       orntNew[1] = ornt[1];
3651       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
3652       orntNew[2] = -2;
3653       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3654       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3655 #if 1
3656       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);
3657       for (p = 0; p < 3; ++p) {
3658         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);
3659       }
3660 #endif
3661       /* C triangle */
3662       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
3663       orntNew[0] = -2;
3664       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
3665       orntNew[1] = ornt[1];
3666       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
3667       orntNew[2] = ornt[2];
3668       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3669       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3670 #if 1
3671       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);
3672       for (p = 0; p < 3; ++p) {
3673         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);
3674       }
3675 #endif
3676       /* D triangle */
3677       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
3678       orntNew[0] = 0;
3679       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
3680       orntNew[1] = 0;
3681       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
3682       orntNew[2] = 0;
3683       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3684       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3685 #if 1
3686       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);
3687       for (p = 0; p < 3; ++p) {
3688         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);
3689       }
3690 #endif
3691       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3692       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3693       for (r = 0; r < 4; ++r) {
3694         for (s = 0; s < supportSize; ++s) {
3695           PetscInt subf;
3696           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3697           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3698           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3699           for (c = 0; c < coneSize; ++c) {
3700             if (cone[c] == f) break;
3701           }
3702           subf = GetTriSubfaceInverse_Static(ornt[c], r);
3703           if (support[s] < cMax) {
3704             supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
3705           } else {
3706             supportRef[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (r==3 ? r : subf);
3707           }
3708         }
3709         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
3710 #if 1
3711         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);
3712         for (p = 0; p < supportSize; ++p) {
3713           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);
3714         }
3715 #endif
3716       }
3717     }
3718     /* Interior cell faces have 3 edges and 2 cells */
3719     for (c = cStart; c < cMax; ++c) {
3720       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8;
3721       const PetscInt *cone, *ornt;
3722       PetscInt        coneNew[3], orntNew[3];
3723       PetscInt        supportNew[2];
3724 
3725       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3726       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3727       /* Face A: {c, a, d} */
3728       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3729       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3730       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3731       orntNew[1] = ornt[1] < 0 ? -2 : 0;
3732       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 2);
3733       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3734       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3735       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3736 #if 1
3737       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3738       for (p = 0; p < 3; ++p) {
3739         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);
3740       }
3741 #endif
3742       supportNew[0] = (c - cStart)*8 + 0;
3743       supportNew[1] = (c - cStart)*8 + 0+4;
3744       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3745 #if 1
3746       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3747       for (p = 0; p < 2; ++p) {
3748         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);
3749       }
3750 #endif
3751       ++newp;
3752       /* Face B: {a, b, e} */
3753       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3754       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3755       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 0);
3756       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3757       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3758       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3759       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3760       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3761 #if 1
3762       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);
3763       for (p = 0; p < 3; ++p) {
3764         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);
3765       }
3766 #endif
3767       supportNew[0] = (c - cStart)*8 + 1;
3768       supportNew[1] = (c - cStart)*8 + 1+4;
3769       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3770 #if 1
3771       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3772       for (p = 0; p < 2; ++p) {
3773         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);
3774       }
3775 #endif
3776       ++newp;
3777       /* Face C: {c, f, b} */
3778       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3779       orntNew[0] = ornt[2] < 0 ? -2 : 0;
3780       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3781       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3782       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 1);
3783       orntNew[2] = ornt[0] < 0 ? -2 : 0;
3784       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3785       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3786 #if 1
3787       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3788       for (p = 0; p < 3; ++p) {
3789         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);
3790       }
3791 #endif
3792       supportNew[0] = (c - cStart)*8 + 2;
3793       supportNew[1] = (c - cStart)*8 + 2+4;
3794       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3795 #if 1
3796       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3797       for (p = 0; p < 2; ++p) {
3798         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);
3799       }
3800 #endif
3801       ++newp;
3802       /* Face D: {d, e, f} */
3803       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 0);
3804       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3805       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3806       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3807       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3808       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3809       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3810       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3811 #if 1
3812       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3813       for (p = 0; p < 3; ++p) {
3814         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);
3815       }
3816 #endif
3817       supportNew[0] = (c - cStart)*8 + 3;
3818       supportNew[1] = (c - cStart)*8 + 3+4;
3819       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3820 #if 1
3821       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3822       for (p = 0; p < 2; ++p) {
3823         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);
3824       }
3825 #endif
3826       ++newp;
3827       /* Face E: {d, f, a} */
3828       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3829       orntNew[0] = ornt[2] < 0 ? 0 : -2;
3830       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3831       orntNew[1] = -2;
3832       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3833       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3834       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3835       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3836 #if 1
3837       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3838       for (p = 0; p < 3; ++p) {
3839         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);
3840       }
3841 #endif
3842       supportNew[0] = (c - cStart)*8 + 0+4;
3843       supportNew[1] = (c - cStart)*8 + 3+4;
3844       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3845 #if 1
3846       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3847       for (p = 0; p < 2; ++p) {
3848         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);
3849       }
3850 #endif
3851       ++newp;
3852       /* Face F: {c, a, f} */
3853       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3854       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3855       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3856       orntNew[1] = 0;
3857       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3858       orntNew[2] = ornt[2] < 0 ? 0 : -2;
3859       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3860       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3861 #if 1
3862       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3863       for (p = 0; p < 3; ++p) {
3864         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);
3865       }
3866 #endif
3867       supportNew[0] = (c - cStart)*8 + 0+4;
3868       supportNew[1] = (c - cStart)*8 + 2+4;
3869       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3870 #if 1
3871       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3872       for (p = 0; p < 2; ++p) {
3873         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);
3874       }
3875 #endif
3876       ++newp;
3877       /* Face G: {e, a, f} */
3878       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3879       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3880       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3881       orntNew[1] = 0;
3882       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3883       orntNew[2] = ornt[3] < 0 ? 0 : -2;
3884       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3885       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3886 #if 1
3887       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3888       for (p = 0; p < 3; ++p) {
3889         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);
3890       }
3891 #endif
3892       supportNew[0] = (c - cStart)*8 + 1+4;
3893       supportNew[1] = (c - cStart)*8 + 3+4;
3894       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3895 #if 1
3896       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3897       for (p = 0; p < 2; ++p) {
3898         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);
3899       }
3900 #endif
3901       ++newp;
3902       /* Face H: {a, b, f} */
3903       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3904       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3905       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3906       orntNew[1] = ornt[3] < 0 ? 0 : -2;
3907       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3908       orntNew[2] = -2;
3909       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3910       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3911 #if 1
3912       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3913       for (p = 0; p < 3; ++p) {
3914         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);
3915       }
3916 #endif
3917       supportNew[0] = (c - cStart)*8 + 1+4;
3918       supportNew[1] = (c - cStart)*8 + 2+4;
3919       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3920 #if 1
3921       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3922       for (p = 0; p < 2; ++p) {
3923         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);
3924       }
3925 #endif
3926       ++newp;
3927     }
3928     /* Hybrid split faces have 4 edges and same cells */
3929     for (f = fMax; f < fEnd; ++f) {
3930       const PetscInt *cone, *ornt, *support;
3931       PetscInt        coneNew[4], orntNew[4];
3932       PetscInt        supportNew[2], size, s, c;
3933 
3934       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3935       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3936       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3937       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3938       for (r = 0; r < 2; ++r) {
3939         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
3940 
3941         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
3942         orntNew[0]   = ornt[0];
3943         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
3944         orntNew[1]   = ornt[1];
3945         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (cone[2+r] - eMax);
3946         orntNew[2+r] = 0;
3947         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd      - eMax) + (f - fMax);
3948         orntNew[3-r] = 0;
3949         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3950         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3951 #if 1
3952         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
3953         for (p = 0; p < 2; ++p) {
3954           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);
3955         }
3956         for (p = 2; p < 4; ++p) {
3957           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);
3958         }
3959 #endif
3960         for (s = 0; s < size; ++s) {
3961           const PetscInt *coneCell, *orntCell, *fornt;
3962           PetscInt        o, of;
3963 
3964           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
3965           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
3966           o = orntCell[0] < 0 ? -1 : 1;
3967           for (c = 2; c < 5; ++c) if (coneCell[c] == f) break;
3968           if (c >= 5) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
3969           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
3970           of = fornt[c-2] < 0 ? -1 : 1;
3971           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetTriEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%3;
3972         }
3973         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3974 #if 1
3975         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
3976         for (p = 0; p < size; ++p) {
3977           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);
3978         }
3979 #endif
3980       }
3981     }
3982     /* Hybrid cell faces have 4 edges and 2 cells */
3983     for (c = cMax; c < cEnd; ++c) {
3984       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3;
3985       const PetscInt *cone, *ornt;
3986       PetscInt        coneNew[4], orntNew[4];
3987       PetscInt        supportNew[2];
3988 
3989       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3990       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3991       for (r = 0; r < 3; ++r) {
3992         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + (r+2)%3;
3993         orntNew[0] = 0;
3994         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + (r+2)%3;
3995         orntNew[1] = 0;
3996         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+(r+2)%3] - fMax);
3997         orntNew[2] = 0;
3998         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+r]       - fMax);
3999         orntNew[3] = 0;
4000         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
4001         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
4002 #if 1
4003         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);
4004         for (p = 0; p < 2; ++p) {
4005           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);
4006         }
4007         for (p = 2; p < 4; ++p) {
4008           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);
4009         }
4010 #endif
4011         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetTriSubface_Static(ornt[0], r);
4012         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + 3;
4013         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
4014 #if 1
4015         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);
4016         for (p = 0; p < 2; ++p) {
4017           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);
4018         }
4019 #endif
4020       }
4021     }
4022     /* Interior split edges have 2 vertices and the same faces as the parent */
4023     for (e = eStart; e < eMax; ++e) {
4024       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
4025 
4026       for (r = 0; r < 2; ++r) {
4027         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
4028         const PetscInt *cone, *ornt, *support;
4029         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4030 
4031         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4032         coneNew[0]       = vStartNew + (cone[0] - vStart);
4033         coneNew[1]       = vStartNew + (cone[1] - vStart);
4034         coneNew[(r+1)%2] = newv;
4035         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4036 #if 1
4037         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4038         for (p = 0; p < 2; ++p) {
4039           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);
4040         }
4041 #endif
4042         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
4043         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4044         for (s = 0; s < supportSize; ++s) {
4045           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4046           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4047           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4048           for (c = 0; c < coneSize; ++c) if (cone[c] == e) break;
4049           if (support[s] < fMax) {
4050             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
4051           } else {
4052             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
4053           }
4054         }
4055         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4056 #if 1
4057         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4058         for (p = 0; p < supportSize; ++p) {
4059           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);
4060         }
4061 #endif
4062       }
4063     }
4064     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
4065     for (f = fStart; f < fMax; ++f) {
4066       const PetscInt *cone, *ornt, *support;
4067       PetscInt        coneSize, supportSize, s;
4068 
4069       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4070       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4071       for (r = 0; r < 3; ++r) {
4072         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
4073         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
4074         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
4075                                     -1, -1,  1,  6,  0,  4,
4076                                      2,  5,  3,  4, -1, -1,
4077                                     -1, -1,  3,  6,  2,  7};
4078 
4079         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4080         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
4081         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
4082         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4083 #if 1
4084         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4085         for (p = 0; p < 2; ++p) {
4086           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);
4087         }
4088 #endif
4089         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
4090         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
4091         for (s = 0; s < supportSize; ++s) {
4092           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4093           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4094           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4095           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
4096           if (support[s] < cMax) {
4097             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
4098             er = GetTriMidEdgeInverse_Static(ornt[c], r);
4099             if (er == eint[c]) {
4100               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
4101             } else {
4102               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
4103               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
4104             }
4105           } else {
4106             supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (r + 1)%3;
4107           }
4108         }
4109         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4110 #if 1
4111         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4112         for (p = 0; p < intFaces; ++p) {
4113           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);
4114         }
4115 #endif
4116       }
4117     }
4118     /* Interior cell edges have 2 vertices and 4 faces */
4119     for (c = cStart; c < cMax; ++c) {
4120       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4121       const PetscInt *cone, *ornt, *fcone;
4122       PetscInt        coneNew[2], supportNew[4], find;
4123 
4124       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4125       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4126       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
4127       find = GetTriEdge_Static(ornt[0], 0);
4128       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4129       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
4130       find = GetTriEdge_Static(ornt[2], 1);
4131       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4132       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4133 #if 1
4134       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4135       for (p = 0; p < 2; ++p) {
4136         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);
4137       }
4138 #endif
4139       supportNew[0] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 4;
4140       supportNew[1] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 5;
4141       supportNew[2] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 6;
4142       supportNew[3] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 7;
4143       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4144 #if 1
4145       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4146       for (p = 0; p < 4; ++p) {
4147         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);
4148       }
4149 #endif
4150     }
4151     /* Hybrid edges have two vertices and the same faces */
4152     for (e = eMax; e < eEnd; ++e) {
4153       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
4154       const PetscInt *cone, *support, *fcone;
4155       PetscInt        coneNew[2], size, fsize, s;
4156 
4157       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4158       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4159       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4160       coneNew[0] = vStartNew + (cone[0] - vStart);
4161       coneNew[1] = vStartNew + (cone[1] - vStart);
4162       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4163 #if 1
4164       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4165       for (p = 0; p < 2; ++p) {
4166         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);
4167       }
4168 #endif
4169       for (s = 0; s < size; ++s) {
4170         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
4171         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
4172         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
4173         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
4174         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + c-2;
4175       }
4176       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4177 #if 1
4178       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4179       for (p = 0; p < size; ++p) {
4180         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);
4181       }
4182 #endif
4183     }
4184     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
4185     for (f = fMax; f < fEnd; ++f) {
4186       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
4187       const PetscInt *cone, *support, *ccone, *cornt;
4188       PetscInt        coneNew[2], size, csize, s;
4189 
4190       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4191       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4192       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4193       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
4194       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
4195       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4196 #if 1
4197       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4198       for (p = 0; p < 2; ++p) {
4199         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);
4200       }
4201 #endif
4202       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 0;
4203       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 1;
4204       for (s = 0; s < size; ++s) {
4205         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
4206         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
4207         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
4208         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
4209         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]);
4210         supportRef[2+s*2+0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + c-2;
4211         supportRef[2+s*2+1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (c-1)%3;
4212       }
4213       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4214 #if 1
4215       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4216       for (p = 0; p < 2+size*2; ++p) {
4217         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);
4218       }
4219 #endif
4220     }
4221     /* Interior vertices have identical supports */
4222     for (v = vStart; v < vEnd; ++v) {
4223       const PetscInt  newp = vStartNew + (v - vStart);
4224       const PetscInt *support, *cone;
4225       PetscInt        size, s;
4226 
4227       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4228       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4229       for (s = 0; s < size; ++s) {
4230         PetscInt r = 0;
4231 
4232         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4233         if (cone[1] == v) r = 1;
4234         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4235         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (support[s] - eMax);
4236       }
4237       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4238 #if 1
4239       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4240       for (p = 0; p < size; ++p) {
4241         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);
4242       }
4243 #endif
4244     }
4245     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
4246     for (e = eStart; e < eMax; ++e) {
4247       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4248       const PetscInt *cone, *support;
4249       PetscInt       *star = NULL, starSize, faceSize = 0, cellSize = 0, coneSize, size, s;
4250 
4251       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4252       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4253       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4254       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4255       for (s = 0; s < size; ++s) {
4256         PetscInt r = 0;
4257 
4258         if (support[s] < fMax) {
4259           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4260           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4261           for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
4262           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
4263           supportRef[2+faceSize+1] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
4264           faceSize += 2;
4265         } else {
4266           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (support[s] - fMax);
4267           ++faceSize;
4268         }
4269       }
4270       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4271       for (s = 0; s < starSize*2; s += 2) {
4272         const PetscInt *cone, *ornt;
4273         PetscInt        e01, e23;
4274 
4275         if ((star[s] >= cStart) && (star[s] < cMax)) {
4276           /* Check edge 0-1 */
4277           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
4278           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
4279           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
4280           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
4281           /* Check edge 2-3 */
4282           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
4283           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
4284           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
4285           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
4286           if ((e01 == e) || (e23 == e)) {supportRef[2+faceSize+cellSize++] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (star[s] - cStart);}
4287         }
4288       }
4289       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4290       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4291 #if 1
4292       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4293       for (p = 0; p < 2+faceSize+cellSize; ++p) {
4294         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);
4295       }
4296 #endif
4297     }
4298     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4299     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
4300     break;
4301   case REFINER_SIMPLEX_TO_HEX_3D:
4302     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
4303     /* All cells have 6 faces */
4304     for (c = cStart; c < cEnd; ++c) {
4305       const PetscInt  newp = cStartNew + (c - cStart)*4;
4306       const PetscInt *cone, *ornt;
4307       PetscInt        coneNew[6];
4308       PetscInt        orntNew[6];
4309 
4310       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4311       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4312       /* A hex */
4313       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 0); /* B */
4314       orntNew[0] = ornt[0] < 0 ? -1 : 1;
4315       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 3;               /* T */
4316       orntNew[1] = -4;
4317       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 0); /* F */
4318       orntNew[2] = ornt[2] < 0 ? -1 : 1;
4319       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 0;               /* K */
4320       orntNew[3] = -1;
4321       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 2;               /* R */
4322       orntNew[4] = 0;
4323       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 0); /* L */
4324       orntNew[5] = ornt[1] < 0 ? -1 : 1;
4325       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4326       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4327 #if 1
4328       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);
4329       for (p = 0; p < 6; ++p) {
4330         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);
4331       }
4332 #endif
4333       /* B hex */
4334       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 1); /* B */
4335       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4336       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 4;               /* T */
4337       orntNew[1] = 0;
4338       coneNew[2] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 0;               /* F */
4339       orntNew[2] = 0;
4340       coneNew[3] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 1); /* K */
4341       orntNew[3] = ornt[3] < 0 ? -2 : 0;
4342       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 1;               /* R */
4343       orntNew[4] = 0;
4344       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 2); /* L */
4345       orntNew[5] = ornt[1] < 0 ? -4 : 2;
4346       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4347       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4348 #if 1
4349       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);
4350       for (p = 0; p < 6; ++p) {
4351         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);
4352       }
4353 #endif
4354       /* C hex */
4355       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 2); /* B */
4356       orntNew[0] = ornt[0] < 0 ? -4 : 2;
4357       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 5;               /* T */
4358       orntNew[1] = -4;
4359       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 1); /* F */
4360       orntNew[2] = ornt[2] < 0 ? -2 : 0;
4361       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 1;               /* K */
4362       orntNew[3] = -1;
4363       coneNew[4] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 0); /* R */
4364       orntNew[4] = ornt[3] < 0 ? -1 : 1;
4365       coneNew[5] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 2;               /* L */
4366       orntNew[5] = -4;
4367       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4368       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4369 #if 1
4370       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);
4371       for (p = 0; p < 6; ++p) {
4372         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);
4373       }
4374 #endif
4375       /* D hex */
4376       coneNew[0] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 3;               /* B */
4377       orntNew[0] = 0;
4378       coneNew[1] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 2); /* T */
4379       orntNew[1] = ornt[3] < 0 ? -1 : 1;
4380       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 2); /* F */
4381       orntNew[2] = ornt[2] < 0 ? -4 : 2;
4382       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 4;               /* K */
4383       orntNew[3] = -1;
4384       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 5;               /* R */
4385       orntNew[4] = 0;
4386       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 1); /* L */
4387       orntNew[5] = ornt[1] < 0 ? -2 : 0;
4388       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4389       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4390 #if 1
4391       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);
4392       for (p = 0; p < 6; ++p) {
4393         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);
4394       }
4395 #endif
4396     }
4397     /* Split faces have 4 edges and the same cells as the parent */
4398     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4399     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
4400     for (f = fStart; f < fEnd; ++f) {
4401       const PetscInt  newp = fStartNew + (f - fStart)*3;
4402       const PetscInt *cone, *ornt, *support;
4403       PetscInt        coneNew[4], orntNew[4], coneSize, supportSize, s;
4404 
4405       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4406       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4407       /* A quad */
4408       coneNew[0] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
4409       orntNew[0] = ornt[2];
4410       coneNew[1] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
4411       orntNew[1] = ornt[0];
4412       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
4413       orntNew[2] = 0;
4414       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
4415       orntNew[3] = -2;
4416       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4417       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4418 #if 1
4419       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);
4420       for (p = 0; p < 4; ++p) {
4421         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);
4422       }
4423 #endif
4424       /* B quad */
4425       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
4426       orntNew[0] = ornt[0];
4427       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
4428       orntNew[1] = ornt[1];
4429       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
4430       orntNew[2] = 0;
4431       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
4432       orntNew[3] = -2;
4433       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4434       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4435 #if 1
4436       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);
4437       for (p = 0; p < 4; ++p) {
4438         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);
4439       }
4440 #endif
4441       /* C quad */
4442       coneNew[0] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
4443       orntNew[0] = ornt[1];
4444       coneNew[1] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
4445       orntNew[1] = ornt[2];
4446       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
4447       orntNew[2] = 0;
4448       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
4449       orntNew[3] = -2;
4450       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4451       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4452 #if 1
4453       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);
4454       for (p = 0; p < 4; ++p) {
4455         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);
4456       }
4457 #endif
4458       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4459       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4460       for (r = 0; r < 3; ++r) {
4461         for (s = 0; s < supportSize; ++s) {
4462           PetscInt subf;
4463           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4464           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4465           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4466           for (c = 0; c < coneSize; ++c) {
4467             if (cone[c] == f) break;
4468           }
4469           subf = GetTriSubfaceInverse_Static(ornt[c], r);
4470           supportRef[s] = cStartNew + (support[s] - cStart)*4 + faces[c*3+subf];
4471         }
4472         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
4473 #if 1
4474         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);
4475         for (p = 0; p < supportSize; ++p) {
4476           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);
4477         }
4478 #endif
4479       }
4480     }
4481     /* Interior faces have 4 edges and 2 cells */
4482     for (c = cStart; c < cEnd; ++c) {
4483       PetscInt        newp = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6;
4484       const PetscInt *cone, *ornt;
4485       PetscInt        coneNew[4], orntNew[4];
4486       PetscInt        supportNew[2];
4487 
4488       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4489       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4490       /* Face {a, g, m, h} */
4491       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],0);
4492       orntNew[0] = 0;
4493       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
4494       orntNew[1] = 0;
4495       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
4496       orntNew[2] = -2;
4497       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],2);
4498       orntNew[3] = -2;
4499       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4500       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4501 #if 1
4502       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4503       for (p = 0; p < 4; ++p) {
4504         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);
4505       }
4506 #endif
4507       supportNew[0] = (c - cStart)*4 + 0;
4508       supportNew[1] = (c - cStart)*4 + 1;
4509       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4510 #if 1
4511       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4512       for (p = 0; p < 2; ++p) {
4513         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);
4514       }
4515 #endif
4516       ++newp;
4517       /* Face {g, b, l , m} */
4518       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],1);
4519       orntNew[0] = -2;
4520       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],0);
4521       orntNew[1] = 0;
4522       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
4523       orntNew[2] = 0;
4524       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
4525       orntNew[3] = -2;
4526       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4527       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4528 #if 1
4529       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4530       for (p = 0; p < 4; ++p) {
4531         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);
4532       }
4533 #endif
4534       supportNew[0] = (c - cStart)*4 + 1;
4535       supportNew[1] = (c - cStart)*4 + 2;
4536       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4537 #if 1
4538       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4539       for (p = 0; p < 2; ++p) {
4540         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);
4541       }
4542 #endif
4543       ++newp;
4544       /* Face {c, g, m, i} */
4545       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],2);
4546       orntNew[0] = 0;
4547       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
4548       orntNew[1] = 0;
4549       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
4550       orntNew[2] = -2;
4551       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],0);
4552       orntNew[3] = -2;
4553       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4554       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4555 #if 1
4556       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4557       for (p = 0; p < 4; ++p) {
4558         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);
4559       }
4560 #endif
4561       supportNew[0] = (c - cStart)*4 + 0;
4562       supportNew[1] = (c - cStart)*4 + 2;
4563       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4564 #if 1
4565       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4566       for (p = 0; p < 2; ++p) {
4567         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);
4568       }
4569 #endif
4570       ++newp;
4571       /* Face {d, h, m, i} */
4572       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],0);
4573       orntNew[0] = 0;
4574       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
4575       orntNew[1] = 0;
4576       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
4577       orntNew[2] = -2;
4578       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],2);
4579       orntNew[3] = -2;
4580       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4581       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4582 #if 1
4583       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4584       for (p = 0; p < 4; ++p) {
4585         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);
4586       }
4587 #endif
4588       supportNew[0] = (c - cStart)*4 + 0;
4589       supportNew[1] = (c - cStart)*4 + 3;
4590       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4591 #if 1
4592       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4593       for (p = 0; p < 2; ++p) {
4594         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);
4595       }
4596 #endif
4597       ++newp;
4598       /* Face {h, m, l, e} */
4599       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
4600       orntNew[0] = 0;
4601       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
4602       orntNew[1] = -2;
4603       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],1);
4604       orntNew[2] = -2;
4605       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],1);
4606       orntNew[3] = 0;
4607       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4608       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4609 #if 1
4610       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4611       for (p = 0; p < 4; ++p) {
4612         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);
4613       }
4614 #endif
4615       supportNew[0] = (c - cStart)*4 + 1;
4616       supportNew[1] = (c - cStart)*4 + 3;
4617       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4618 #if 1
4619       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4620       for (p = 0; p < 2; ++p) {
4621         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);
4622       }
4623 #endif
4624       ++newp;
4625       /* Face {i, m, l, f} */
4626       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
4627       orntNew[0] = 0;
4628       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
4629       orntNew[1] = -2;
4630       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],2);
4631       orntNew[2] = -2;
4632       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],1);
4633       orntNew[3] = 0;
4634       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4635       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4636 #if 1
4637       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4638       for (p = 0; p < 4; ++p) {
4639         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);
4640       }
4641 #endif
4642       supportNew[0] = (c - cStart)*4 + 2;
4643       supportNew[1] = (c - cStart)*4 + 3;
4644       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4645 #if 1
4646       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4647       for (p = 0; p < 2; ++p) {
4648         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);
4649       }
4650 #endif
4651       ++newp;
4652     }
4653     /* Split Edges have 2 vertices and the same faces as the parent */
4654     for (e = eStart; e < eEnd; ++e) {
4655       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
4656 
4657       for (r = 0; r < 2; ++r) {
4658         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
4659         const PetscInt *cone, *ornt, *support;
4660         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4661 
4662         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4663         coneNew[0]       = vStartNew + (cone[0] - vStart);
4664         coneNew[1]       = vStartNew + (cone[1] - vStart);
4665         coneNew[(r+1)%2] = newv;
4666         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4667 #if 1
4668         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4669         for (p = 0; p < 2; ++p) {
4670           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);
4671         }
4672 #endif
4673         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
4674         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4675         for (s = 0; s < supportSize; ++s) {
4676           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4677           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4678           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4679           for (c = 0; c < coneSize; ++c) {
4680             if (cone[c] == e) break;
4681           }
4682           supportRef[s] = fStartNew + (support[s] - fStart)*3 + (c + (ornt[c] < 0 ? 1-r : r))%3;
4683         }
4684         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4685 #if 1
4686         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4687         for (p = 0; p < supportSize; ++p) {
4688           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);
4689         }
4690 #endif
4691       }
4692     }
4693     /* Face edges have 2 vertices and 2 + cell faces supports */
4694     for (f = fStart; f < fEnd; ++f) {
4695       const PetscInt *cone, *ornt, *support;
4696       PetscInt        coneSize, supportSize, s;
4697 
4698       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4699       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4700       for (r = 0; r < 3; ++r) {
4701         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
4702         PetscInt        coneNew[2];
4703         PetscInt        fint[4][3] = { {0, 1, 2},
4704                                        {3, 4, 0},
4705                                        {2, 5, 3},
4706                                        {1, 4, 5} };
4707 
4708         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4709         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
4710         coneNew[1] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + f - fStart;
4711         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4712 #if 1
4713         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4714         for (p = 0; p < 2; ++p) {
4715           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);
4716         }
4717 #endif
4718         supportRef[0] = fStartNew + (f - fStart)*3 + (r+0)%3;
4719         supportRef[1] = fStartNew + (f - fStart)*3 + (r+1)%3;
4720         for (s = 0; s < supportSize; ++s) {
4721           PetscInt er;
4722           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4723           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4724           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4725           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
4726           er = GetTriInteriorEdgeInverse_Static(ornt[c], r);
4727           supportRef[2+s] = fStartNew + (fEnd - fStart)*3 + (support[s] - cStart)*6 + fint[c][er];
4728         }
4729         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4730 #if 1
4731         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4732         for (p = 0; p < supportSize + 2; ++p) {
4733           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);
4734         }
4735 #endif
4736       }
4737     }
4738     /* Interior cell edges have 2 vertices and 3 faces */
4739     for (c = cStart; c < cEnd; ++c) {
4740       const PetscInt *cone;
4741       PetscInt       fint[4][3] = { {0,1,2},
4742                                     {0,3,4},
4743                                     {2,3,5},
4744                                     {1,4,5} } ;
4745 
4746       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4747       for (r = 0; r < 4; r++) {
4748         PetscInt       coneNew[2], supportNew[3];
4749         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + r;
4750 
4751         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
4752         coneNew[1] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd -fStart) + c - cStart;
4753         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4754 #if 1
4755         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4756         for (p = 0; p < 2; ++p) {
4757           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);
4758         }
4759 #endif
4760         supportNew[0] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][0];
4761         supportNew[1] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][1];
4762         supportNew[2] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][2];
4763         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4764 #if 1
4765         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4766         for (p = 0; p < 3; ++p) {
4767           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);
4768         }
4769 #endif
4770       }
4771     }
4772     /* Old vertices have identical supports */
4773     for (v = vStart; v < vEnd; ++v) {
4774       const PetscInt  newp = vStartNew + (v - vStart);
4775       const PetscInt *support, *cone;
4776       PetscInt        size, s;
4777 
4778       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4779       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4780       for (s = 0; s < size; ++s) {
4781         PetscInt r = 0;
4782 
4783         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4784         if (cone[1] == v) r = 1;
4785         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4786       }
4787       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4788 #if 1
4789       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4790       for (p = 0; p < size; ++p) {
4791         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);
4792       }
4793 #endif
4794     }
4795     /* Edge vertices have 2 + faces supports */
4796     for (e = eStart; e < eEnd; ++e) {
4797       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4798       const PetscInt *cone, *support;
4799       PetscInt        size, s;
4800 
4801       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4802       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4803       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4804       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4805       for (s = 0; s < size; ++s) {
4806         PetscInt r = 0, coneSize;
4807 
4808         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4809         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4810         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
4811         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + r;
4812       }
4813       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4814 #if 1
4815       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4816       for (p = 0; p < 2+size; ++p) {
4817         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);
4818       }
4819 #endif
4820     }
4821     /* Face vertices have 3 + cells supports */
4822     for (f = fStart; f < fEnd; ++f) {
4823       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
4824       const PetscInt *cone, *support;
4825       PetscInt        size, s;
4826 
4827       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4828       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4829       supportRef[0] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 0;
4830       supportRef[1] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 1;
4831       supportRef[2] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 2;
4832       for (s = 0; s < size; ++s) {
4833         PetscInt r = 0, coneSize;
4834 
4835         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4836         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4837         for (r = 0; r < coneSize; ++r) {if (cone[r] == f) break;}
4838         supportRef[3+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (support[s] - cStart)*4 + r;
4839       }
4840       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4841 #if 1
4842       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4843       for (p = 0; p < 3+size; ++p) {
4844         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
4845       }
4846 #endif
4847     }
4848     /* Interior cell vertices have 4 supports */
4849     for (c = cStart; c < cEnd; ++c) {
4850       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + c - cStart;
4851       supportRef[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
4852       supportRef[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
4853       supportRef[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
4854       supportRef[3] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
4855       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4856 #if 1
4857       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4858       for (p = 0; p < 4; ++p) {
4859         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);
4860       }
4861 #endif
4862     }
4863     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4864     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
4865     break;
4866   case REFINER_HEX_3D:
4867     /*
4868      Bottom (viewed from top)    Top
4869      1---------2---------2       7---------2---------6
4870      |         |         |       |         |         |
4871      |    B    2    C    |       |    H    2    G    |
4872      |         |         |       |         |         |
4873      3----3----0----1----1       3----3----0----1----1
4874      |         |         |       |         |         |
4875      |    A    0    D    |       |    E    0    F    |
4876      |         |         |       |         |         |
4877      0---------0---------3       4---------0---------5
4878      */
4879     /* All cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
4880     for (c = cStart; c < cEnd; ++c) {
4881       const PetscInt  newp = (c - cStart)*8;
4882       const PetscInt *cone, *ornt;
4883       PetscInt        coneNew[6], orntNew[6];
4884 
4885       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4886       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4887       /* A hex */
4888       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
4889       orntNew[0] = ornt[0];
4890       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
4891       orntNew[1] = 0;
4892       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
4893       orntNew[2] = ornt[2];
4894       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
4895       orntNew[3] = 0;
4896       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
4897       orntNew[4] = 0;
4898       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
4899       orntNew[5] = ornt[5];
4900       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4901       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4902 #if 1
4903       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);
4904       for (p = 0; p < 6; ++p) {
4905         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);
4906       }
4907 #endif
4908       /* B hex */
4909       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
4910       orntNew[0] = ornt[0];
4911       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
4912       orntNew[1] = 0;
4913       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
4914       orntNew[2] = -1;
4915       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
4916       orntNew[3] = ornt[3];
4917       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
4918       orntNew[4] = 0;
4919       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
4920       orntNew[5] = ornt[5];
4921       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4922       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4923 #if 1
4924       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);
4925       for (p = 0; p < 6; ++p) {
4926         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);
4927       }
4928 #endif
4929       /* C hex */
4930       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
4931       orntNew[0] = ornt[0];
4932       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
4933       orntNew[1] = 0;
4934       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
4935       orntNew[2] = -1;
4936       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
4937       orntNew[3] = ornt[3];
4938       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
4939       orntNew[4] = ornt[4];
4940       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
4941       orntNew[5] = -4;
4942       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4943       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4944 #if 1
4945       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);
4946       for (p = 0; p < 6; ++p) {
4947         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);
4948       }
4949 #endif
4950       /* D hex */
4951       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
4952       orntNew[0] = ornt[0];
4953       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
4954       orntNew[1] = 0;
4955       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
4956       orntNew[2] = ornt[2];
4957       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
4958       orntNew[3] = 0;
4959       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
4960       orntNew[4] = ornt[4];
4961       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
4962       orntNew[5] = -4;
4963       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4964       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4965 #if 1
4966       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);
4967       for (p = 0; p < 6; ++p) {
4968         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);
4969       }
4970 #endif
4971       /* E hex */
4972       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
4973       orntNew[0] = -4;
4974       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
4975       orntNew[1] = ornt[1];
4976       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
4977       orntNew[2] = ornt[2];
4978       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
4979       orntNew[3] = 0;
4980       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
4981       orntNew[4] = -1;
4982       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
4983       orntNew[5] = ornt[5];
4984       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
4985       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
4986 #if 1
4987       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);
4988       for (p = 0; p < 6; ++p) {
4989         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);
4990       }
4991 #endif
4992       /* F hex */
4993       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
4994       orntNew[0] = -4;
4995       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
4996       orntNew[1] = ornt[1];
4997       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
4998       orntNew[2] = ornt[2];
4999       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
5000       orntNew[3] = -1;
5001       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
5002       orntNew[4] = ornt[4];
5003       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
5004       orntNew[5] = 1;
5005       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
5006       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
5007 #if 1
5008       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);
5009       for (p = 0; p < 6; ++p) {
5010         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);
5011       }
5012 #endif
5013       /* G hex */
5014       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
5015       orntNew[0] = -4;
5016       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
5017       orntNew[1] = ornt[1];
5018       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
5019       orntNew[2] = 0;
5020       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
5021       orntNew[3] = ornt[3];
5022       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
5023       orntNew[4] = ornt[4];
5024       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
5025       orntNew[5] = -3;
5026       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
5027       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
5028 #if 1
5029       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);
5030       for (p = 0; p < 6; ++p) {
5031         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);
5032       }
5033 #endif
5034       /* H hex */
5035       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
5036       orntNew[0] = -4;
5037       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
5038       orntNew[1] = ornt[1];
5039       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
5040       orntNew[2] = -1;
5041       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
5042       orntNew[3] = ornt[3];
5043       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
5044       orntNew[4] = 3;
5045       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
5046       orntNew[5] = ornt[5];
5047       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
5048       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
5049 #if 1
5050       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);
5051       for (p = 0; p < 6; ++p) {
5052         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);
5053       }
5054 #endif
5055     }
5056     /* Split faces have 4 edges and the same cells as the parent */
5057     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5058     ierr = PetscMalloc1(4 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
5059     for (f = fStart; f < fEnd; ++f) {
5060       for (r = 0; r < 4; ++r) {
5061         /* TODO: This can come from GetFaces_Internal() */
5062         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};
5063         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
5064         const PetscInt *cone, *ornt, *support;
5065         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
5066 
5067         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5068         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
5069         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
5070         orntNew[(r+3)%4] = ornt[(r+3)%4];
5071         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
5072         orntNew[(r+0)%4] = ornt[r];
5073         coneNew[(r+1)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
5074         orntNew[(r+1)%4] = 0;
5075         coneNew[(r+2)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + (r+3)%4;
5076         orntNew[(r+2)%4] = -2;
5077         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5078         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5079 #if 1
5080         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5081         for (p = 0; p < 4; ++p) {
5082           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);
5083         }
5084 #endif
5085         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5086         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5087         for (s = 0; s < supportSize; ++s) {
5088           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5089           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5090           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5091           for (c = 0; c < coneSize; ++c) {
5092             if (cone[c] == f) break;
5093           }
5094           supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+GetQuadSubfaceInverse_Static(ornt[c], r)];
5095         }
5096         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5097 #if 1
5098         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5099         for (p = 0; p < supportSize; ++p) {
5100           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);
5101         }
5102 #endif
5103       }
5104     }
5105     /* Interior faces have 4 edges and 2 cells */
5106     for (c = cStart; c < cEnd; ++c) {
5107       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};
5108       const PetscInt *cone, *ornt;
5109       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
5110 
5111       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5112       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5113       /* A-D face */
5114       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 0;
5115       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
5116       orntNew[0] = 0;
5117       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
5118       orntNew[1] = 0;
5119       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
5120       orntNew[2] = -2;
5121       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
5122       orntNew[3] = -2;
5123       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5124       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5125 #if 1
5126       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5127       for (p = 0; p < 4; ++p) {
5128         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);
5129       }
5130 #endif
5131       /* C-D face */
5132       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 1;
5133       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
5134       orntNew[0] = 0;
5135       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
5136       orntNew[1] = 0;
5137       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
5138       orntNew[2] = -2;
5139       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
5140       orntNew[3] = -2;
5141       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5142       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5143 #if 1
5144       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5145       for (p = 0; p < 4; ++p) {
5146         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);
5147       }
5148 #endif
5149       /* B-C face */
5150       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 2;
5151       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
5152       orntNew[0] = -2;
5153       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
5154       orntNew[1] = 0;
5155       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
5156       orntNew[2] = 0;
5157       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
5158       orntNew[3] = -2;
5159       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5160       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5161 #if 1
5162       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5163       for (p = 0; p < 4; ++p) {
5164         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);
5165       }
5166 #endif
5167       /* A-B face */
5168       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 3;
5169       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
5170       orntNew[0] = -2;
5171       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
5172       orntNew[1] = 0;
5173       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
5174       orntNew[2] = 0;
5175       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
5176       orntNew[3] = -2;
5177       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5178       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5179 #if 1
5180       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5181       for (p = 0; p < 4; ++p) {
5182         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);
5183       }
5184 #endif
5185       /* E-F face */
5186       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 4;
5187       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
5188       orntNew[0] = -2;
5189       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
5190       orntNew[1] = -2;
5191       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
5192       orntNew[2] = 0;
5193       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
5194       orntNew[3] = 0;
5195       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5196       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5197 #if 1
5198       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5199       for (p = 0; p < 4; ++p) {
5200         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);
5201       }
5202 #endif
5203       /* F-G face */
5204       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 5;
5205       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
5206       orntNew[0] = -2;
5207       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
5208       orntNew[1] = -2;
5209       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
5210       orntNew[2] = 0;
5211       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
5212       orntNew[3] = 0;
5213       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5214       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5215 #if 1
5216       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5217       for (p = 0; p < 4; ++p) {
5218         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);
5219       }
5220 #endif
5221       /* G-H face */
5222       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 6;
5223       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
5224       orntNew[0] = -2;
5225       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
5226       orntNew[1] = 0;
5227       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
5228       orntNew[2] = 0;
5229       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
5230       orntNew[3] = -2;
5231       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5232       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5233 #if 1
5234       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5235       for (p = 0; p < 4; ++p) {
5236         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);
5237       }
5238 #endif
5239       /* E-H face */
5240       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 7;
5241       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
5242       orntNew[0] = -2;
5243       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
5244       orntNew[1] = -2;
5245       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
5246       orntNew[2] = 0;
5247       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
5248       orntNew[3] = 0;
5249       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5250       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5251 #if 1
5252       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5253       for (p = 0; p < 4; ++p) {
5254         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);
5255       }
5256 #endif
5257       /* A-E face */
5258       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 8;
5259       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
5260       orntNew[0] = 0;
5261       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
5262       orntNew[1] = 0;
5263       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
5264       orntNew[2] = -2;
5265       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
5266       orntNew[3] = -2;
5267       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5268       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5269 #if 1
5270       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5271       for (p = 0; p < 4; ++p) {
5272         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);
5273       }
5274 #endif
5275       /* D-F face */
5276       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 9;
5277       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
5278       orntNew[0] = -2;
5279       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
5280       orntNew[1] = 0;
5281       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
5282       orntNew[2] = 0;
5283       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
5284       orntNew[3] = -2;
5285       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5286       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5287 #if 1
5288       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5289       for (p = 0; p < 4; ++p) {
5290         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);
5291       }
5292 #endif
5293       /* C-G face */
5294       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 10;
5295       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
5296       orntNew[0] = -2;
5297       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
5298       orntNew[1] = -2;
5299       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
5300       orntNew[2] = 0;
5301       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
5302       orntNew[3] = 0;
5303       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5304       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5305 #if 1
5306       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5307       for (p = 0; p < 4; ++p) {
5308         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);
5309       }
5310 #endif
5311       /* B-H face */
5312       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 11;
5313       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
5314       orntNew[0] = 0;
5315       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
5316       orntNew[1] = -2;
5317       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
5318       orntNew[2] = -2;
5319       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
5320       orntNew[3] = 0;
5321       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5322       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5323 #if 1
5324       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5325       for (p = 0; p < 4; ++p) {
5326         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);
5327       }
5328 #endif
5329       for (r = 0; r < 12; ++r) {
5330         newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
5331         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
5332         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
5333         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5334 #if 1
5335         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5336         for (p = 0; p < 2; ++p) {
5337           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);
5338         }
5339 #endif
5340       }
5341     }
5342     /* Split edges have 2 vertices and the same faces as the parent */
5343     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5344     for (e = eStart; e < eEnd; ++e) {
5345       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
5346 
5347       for (r = 0; r < 2; ++r) {
5348         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
5349         const PetscInt *cone, *ornt, *support;
5350         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5351 
5352         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
5353         coneNew[0]       = vStartNew + (cone[0] - vStart);
5354         coneNew[1]       = vStartNew + (cone[1] - vStart);
5355         coneNew[(r+1)%2] = newv;
5356         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5357 #if 1
5358         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5359         for (p = 0; p < 2; ++p) {
5360           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);
5361         }
5362 #endif
5363         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
5364         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5365         for (s = 0; s < supportSize; ++s) {
5366           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5367           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5368           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5369           for (c = 0; c < coneSize; ++c) {
5370             if (cone[c] == e) break;
5371           }
5372           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
5373         }
5374         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5375 #if 1
5376         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5377         for (p = 0; p < supportSize; ++p) {
5378           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);
5379         }
5380 #endif
5381       }
5382     }
5383     /* Face edges have 2 vertices and 2+cells faces */
5384     for (f = fStart; f < fEnd; ++f) {
5385       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};
5386       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
5387       const PetscInt *cone, *coneCell, *orntCell, *support;
5388       PetscInt        coneNew[2], coneSize, c, supportSize, s;
5389 
5390       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5391       for (r = 0; r < 4; ++r) {
5392         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
5393 
5394         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
5395         coneNew[1] = newv;
5396         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5397 #if 1
5398         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5399         for (p = 0; p < 2; ++p) {
5400           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);
5401         }
5402 #endif
5403         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5404         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5405         supportRef[0] = fStartNew + (f - fStart)*4 + r;
5406         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
5407         for (s = 0; s < supportSize; ++s) {
5408           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5409           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
5410           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
5411           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
5412           supportRef[2+s] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
5413         }
5414         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5415 #if 1
5416         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5417         for (p = 0; p < 2+supportSize; ++p) {
5418           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);
5419         }
5420 #endif
5421       }
5422     }
5423     /* Cell edges have 2 vertices and 4 faces */
5424     for (c = cStart; c < cEnd; ++c) {
5425       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};
5426       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
5427       const PetscInt *cone;
5428       PetscInt        coneNew[2], supportNew[4];
5429 
5430       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5431       for (r = 0; r < 6; ++r) {
5432         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
5433 
5434         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
5435         coneNew[1] = newv;
5436         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5437 #if 1
5438         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5439         for (p = 0; p < 2; ++p) {
5440           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);
5441         }
5442 #endif
5443         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
5444         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5445 #if 1
5446         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5447         for (p = 0; p < 4; ++p) {
5448           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);
5449         }
5450 #endif
5451       }
5452     }
5453     /* Old vertices have identical supports */
5454     for (v = vStart; v < vEnd; ++v) {
5455       const PetscInt  newp = vStartNew + (v - vStart);
5456       const PetscInt *support, *cone;
5457       PetscInt        size, s;
5458 
5459       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5460       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5461       for (s = 0; s < size; ++s) {
5462         PetscInt r = 0;
5463 
5464         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5465         if (cone[1] == v) r = 1;
5466         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
5467       }
5468       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5469 #if 1
5470       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5471       for (p = 0; p < size; ++p) {
5472         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);
5473       }
5474 #endif
5475     }
5476     /* Edge vertices have 2 + faces supports */
5477     for (e = eStart; e < eEnd; ++e) {
5478       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
5479       const PetscInt *cone, *support;
5480       PetscInt        size, s;
5481 
5482       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
5483       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5484       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
5485       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
5486       for (s = 0; s < size; ++s) {
5487         PetscInt r;
5488 
5489         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5490         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
5491         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*4 + r;
5492       }
5493       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5494 #if 1
5495       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5496       for (p = 0; p < 2+size; ++p) {
5497         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);
5498       }
5499 #endif
5500     }
5501     /* Face vertices have 4 + cells supports */
5502     for (f = fStart; f < fEnd; ++f) {
5503       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
5504       const PetscInt *cone, *support;
5505       PetscInt        size, s;
5506 
5507       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5508       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5509       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eEnd - eStart)*2 +  (f - fStart)*4 + r;
5510       for (s = 0; s < size; ++s) {
5511         PetscInt r;
5512 
5513         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5514         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
5515         supportRef[4+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (support[s] - cStart)*6 + r;
5516       }
5517       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5518 #if 1
5519       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5520       for (p = 0; p < 4+size; ++p) {
5521         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);
5522       }
5523 #endif
5524     }
5525     /* Cell vertices have 6 supports */
5526     for (c = cStart; c < cEnd; ++c) {
5527       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
5528       PetscInt       supportNew[6];
5529 
5530       for (r = 0; r < 6; ++r) {
5531         supportNew[r] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
5532       }
5533       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5534     }
5535     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5536     break;
5537   case REFINER_HYBRID_HEX_3D:
5538     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
5539     /*
5540      Bottom (viewed from top)    Top
5541      1---------2---------2       7---------2---------6
5542      |         |         |       |         |         |
5543      |    B    2    C    |       |    H    2    G    |
5544      |         |         |       |         |         |
5545      3----3----0----1----1       3----3----0----1----1
5546      |         |         |       |         |         |
5547      |    A    0    D    |       |    E    0    F    |
5548      |         |         |       |         |         |
5549      0---------0---------3       4---------0---------5
5550      */
5551     /* Interior cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
5552     for (c = cStart; c < cMax; ++c) {
5553       const PetscInt  newp = (c - cStart)*8;
5554       const PetscInt *cone, *ornt;
5555       PetscInt        coneNew[6], orntNew[6];
5556 
5557       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5558       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5559       /* A hex */
5560       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
5561       orntNew[0] = ornt[0];
5562       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
5563       orntNew[1] = 0;
5564       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
5565       orntNew[2] = ornt[2];
5566       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
5567       orntNew[3] = 0;
5568       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
5569       orntNew[4] = 0;
5570       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
5571       orntNew[5] = ornt[5];
5572       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5573       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5574 #if 1
5575       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);
5576       for (p = 0; p < 6; ++p) {
5577         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);
5578       }
5579 #endif
5580       /* B hex */
5581       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
5582       orntNew[0] = ornt[0];
5583       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
5584       orntNew[1] = 0;
5585       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
5586       orntNew[2] = -1;
5587       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
5588       orntNew[3] = ornt[3];
5589       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
5590       orntNew[4] = 0;
5591       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
5592       orntNew[5] = ornt[5];
5593       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5594       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5595 #if 1
5596       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);
5597       for (p = 0; p < 6; ++p) {
5598         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);
5599       }
5600 #endif
5601       /* C hex */
5602       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
5603       orntNew[0] = ornt[0];
5604       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
5605       orntNew[1] = 0;
5606       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
5607       orntNew[2] = -1;
5608       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
5609       orntNew[3] = ornt[3];
5610       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
5611       orntNew[4] = ornt[4];
5612       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
5613       orntNew[5] = -4;
5614       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5615       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5616 #if 1
5617       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);
5618       for (p = 0; p < 6; ++p) {
5619         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);
5620       }
5621 #endif
5622       /* D hex */
5623       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
5624       orntNew[0] = ornt[0];
5625       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
5626       orntNew[1] = 0;
5627       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
5628       orntNew[2] = ornt[2];
5629       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
5630       orntNew[3] = 0;
5631       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
5632       orntNew[4] = ornt[4];
5633       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
5634       orntNew[5] = -4;
5635       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5636       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5637 #if 1
5638       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);
5639       for (p = 0; p < 6; ++p) {
5640         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);
5641       }
5642 #endif
5643       /* E hex */
5644       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
5645       orntNew[0] = -4;
5646       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
5647       orntNew[1] = ornt[1];
5648       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
5649       orntNew[2] = ornt[2];
5650       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
5651       orntNew[3] = 0;
5652       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
5653       orntNew[4] = -1;
5654       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
5655       orntNew[5] = ornt[5];
5656       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
5657       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
5658 #if 1
5659       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);
5660       for (p = 0; p < 6; ++p) {
5661         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);
5662       }
5663 #endif
5664       /* F hex */
5665       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
5666       orntNew[0] = -4;
5667       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
5668       orntNew[1] = ornt[1];
5669       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
5670       orntNew[2] = ornt[2];
5671       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
5672       orntNew[3] = -1;
5673       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
5674       orntNew[4] = ornt[4];
5675       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
5676       orntNew[5] = 1;
5677       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
5678       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
5679 #if 1
5680       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);
5681       for (p = 0; p < 6; ++p) {
5682         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);
5683       }
5684 #endif
5685       /* G hex */
5686       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
5687       orntNew[0] = -4;
5688       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
5689       orntNew[1] = ornt[1];
5690       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
5691       orntNew[2] = 0;
5692       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
5693       orntNew[3] = ornt[3];
5694       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
5695       orntNew[4] = ornt[4];
5696       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
5697       orntNew[5] = -3;
5698       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
5699       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
5700 #if 1
5701       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);
5702       for (p = 0; p < 6; ++p) {
5703         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);
5704       }
5705 #endif
5706       /* H hex */
5707       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
5708       orntNew[0] = -4;
5709       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
5710       orntNew[1] = ornt[1];
5711       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
5712       orntNew[2] = -1;
5713       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
5714       orntNew[3] = ornt[3];
5715       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
5716       orntNew[4] = 3;
5717       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
5718       orntNew[5] = ornt[5];
5719       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
5720       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
5721 #if 1
5722       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);
5723       for (p = 0; p < 6; ++p) {
5724         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);
5725       }
5726 #endif
5727     }
5728     /* Hybrid cells have 6 faces: Front, Back, Sides */
5729     /*
5730      3---------2---------2
5731      |         |         |
5732      |    D    2    C    |
5733      |         |         |
5734      3----3----0----1----1
5735      |         |         |
5736      |    A    0    B    |
5737      |         |         |
5738      0---------0---------1
5739      */
5740     for (c = cMax; c < cEnd; ++c) {
5741       const PetscInt  newp = (cMax - cStart)*8 + (c - cMax)*4;
5742       const PetscInt *cone, *ornt, *fornt;
5743       PetscInt        coneNew[6], orntNew[6], o, of, i;
5744 
5745       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5746       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5747       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
5748       o = ornt[0] < 0 ? -1 : 1;
5749       for (r = 0; r < 4; ++r) {
5750         PetscInt subfA = GetQuadSubface_Static(ornt[0], r);
5751         PetscInt edgeA = GetQuadEdge_Static(ornt[0], r);
5752         PetscInt edgeB = GetQuadEdge_Static(ornt[0], (r+3)%4);
5753         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]);
5754         coneNew[0]         = fStartNew + (cone[0] - fStart)*4 + subfA;
5755         orntNew[0]         = ornt[0];
5756         coneNew[1]         = fStartNew + (cone[1] - fStart)*4 + subfA;
5757         orntNew[1]         = ornt[0];
5758         of = fornt[edgeA] < 0 ? -1 : 1;
5759         i  = GetQuadEdgeInverse_Static(ornt[0], r) + 2;
5760         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeA] - fMax)*2 + (o*of < 0 ? 1 : 0);
5761         orntNew[i] = ornt[edgeA];
5762         i  = GetQuadEdgeInverse_Static(ornt[0], (r+1)%4) + 2;
5763         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeA;
5764         orntNew[i] = 0;
5765         i  = GetQuadEdgeInverse_Static(ornt[0], (r+2)%4) + 2;
5766         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeB;
5767         orntNew[i] = -2;
5768         of = fornt[edgeB] < 0 ? -1 : 1;
5769         i  = GetQuadEdgeInverse_Static(ornt[0], (r+3)%4) + 2;
5770         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeB] - fMax)*2 + (o*of < 0 ? 0 : 1);
5771         orntNew[i] = ornt[edgeB];
5772         ierr       = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
5773         ierr       = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
5774 #if 1
5775         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);
5776         for (p = 0; p < 2; ++p) {
5777           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);
5778         }
5779         for (p = 2; p < 6; ++p) {
5780           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);
5781         }
5782 #endif
5783       }
5784     }
5785     /* Interior split faces have 4 edges and the same cells as the parent */
5786     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5787     ierr = PetscMalloc1(4 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
5788     for (f = fStart; f < fMax; ++f) {
5789       for (r = 0; r < 4; ++r) {
5790         /* TODO: This can come from GetFaces_Internal() */
5791         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};
5792         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
5793         const PetscInt *cone, *ornt, *support;
5794         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
5795 
5796         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5797         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
5798         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
5799         orntNew[(r+3)%4] = ornt[(r+3)%4];
5800         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
5801         orntNew[(r+0)%4] = ornt[r];
5802         coneNew[(r+1)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
5803         orntNew[(r+1)%4] = 0;
5804         coneNew[(r+2)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + (r+3)%4;
5805         orntNew[(r+2)%4] = -2;
5806         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5807         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5808 #if 1
5809         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5810         for (p = 0; p < 4; ++p) {
5811           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);
5812         }
5813 #endif
5814         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5815         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5816         for (s = 0; s < supportSize; ++s) {
5817           PetscInt subf;
5818           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5819           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5820           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5821           for (c = 0; c < coneSize; ++c) {
5822             if (cone[c] == f) break;
5823           }
5824           subf = GetQuadSubfaceInverse_Static(ornt[c], r);
5825           if (support[s] < cMax) {
5826             supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+subf];
5827           } else {
5828             supportRef[s] = cStartNew + (cMax       - cStart)*8 + (support[s] - cMax)*4 + subf;
5829           }
5830         }
5831         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5832 #if 1
5833         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5834         for (p = 0; p < supportSize; ++p) {
5835           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);
5836         }
5837 #endif
5838       }
5839     }
5840     /* Interior cell faces have 4 edges and 2 cells */
5841     for (c = cStart; c < cMax; ++c) {
5842       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};
5843       const PetscInt *cone, *ornt;
5844       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
5845 
5846       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5847       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5848       /* A-D face */
5849       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 0;
5850       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
5851       orntNew[0] = 0;
5852       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
5853       orntNew[1] = 0;
5854       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
5855       orntNew[2] = -2;
5856       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
5857       orntNew[3] = -2;
5858       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5859       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5860 #if 1
5861       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5862       for (p = 0; p < 4; ++p) {
5863         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);
5864       }
5865 #endif
5866       /* C-D face */
5867       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 1;
5868       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
5869       orntNew[0] = 0;
5870       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
5871       orntNew[1] = 0;
5872       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
5873       orntNew[2] = -2;
5874       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
5875       orntNew[3] = -2;
5876       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5877       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5878 #if 1
5879       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5880       for (p = 0; p < 4; ++p) {
5881         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);
5882       }
5883 #endif
5884       /* B-C face */
5885       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 2;
5886       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
5887       orntNew[0] = -2;
5888       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
5889       orntNew[1] = 0;
5890       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
5891       orntNew[2] = 0;
5892       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
5893       orntNew[3] = -2;
5894       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5895       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5896 #if 1
5897       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5898       for (p = 0; p < 4; ++p) {
5899         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);
5900       }
5901 #endif
5902       /* A-B face */
5903       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 3;
5904       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
5905       orntNew[0] = -2;
5906       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
5907       orntNew[1] = 0;
5908       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
5909       orntNew[2] = 0;
5910       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
5911       orntNew[3] = -2;
5912       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5913       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5914 #if 1
5915       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5916       for (p = 0; p < 4; ++p) {
5917         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);
5918       }
5919 #endif
5920       /* E-F face */
5921       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 4;
5922       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
5923       orntNew[0] = -2;
5924       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
5925       orntNew[1] = -2;
5926       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
5927       orntNew[2] = 0;
5928       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
5929       orntNew[3] = 0;
5930       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5931       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5932 #if 1
5933       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5934       for (p = 0; p < 4; ++p) {
5935         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);
5936       }
5937 #endif
5938       /* F-G face */
5939       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 5;
5940       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
5941       orntNew[0] = -2;
5942       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
5943       orntNew[1] = -2;
5944       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
5945       orntNew[2] = 0;
5946       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
5947       orntNew[3] = 0;
5948       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5949       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5950 #if 1
5951       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5952       for (p = 0; p < 4; ++p) {
5953         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);
5954       }
5955 #endif
5956       /* G-H face */
5957       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 6;
5958       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
5959       orntNew[0] = -2;
5960       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
5961       orntNew[1] = 0;
5962       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
5963       orntNew[2] = 0;
5964       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
5965       orntNew[3] = -2;
5966       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5967       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5968 #if 1
5969       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5970       for (p = 0; p < 4; ++p) {
5971         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);
5972       }
5973 #endif
5974       /* E-H face */
5975       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 7;
5976       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
5977       orntNew[0] = -2;
5978       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
5979       orntNew[1] = -2;
5980       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
5981       orntNew[2] = 0;
5982       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
5983       orntNew[3] = 0;
5984       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5985       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5986 #if 1
5987       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5988       for (p = 0; p < 4; ++p) {
5989         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);
5990       }
5991 #endif
5992       /* A-E face */
5993       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 8;
5994       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
5995       orntNew[0] = 0;
5996       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
5997       orntNew[1] = 0;
5998       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
5999       orntNew[2] = -2;
6000       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
6001       orntNew[3] = -2;
6002       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6003       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6004 #if 1
6005       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
6006       for (p = 0; p < 4; ++p) {
6007         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);
6008       }
6009 #endif
6010       /* D-F face */
6011       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 9;
6012       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
6013       orntNew[0] = -2;
6014       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
6015       orntNew[1] = 0;
6016       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
6017       orntNew[2] = 0;
6018       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
6019       orntNew[3] = -2;
6020       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6021       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6022 #if 1
6023       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
6024       for (p = 0; p < 4; ++p) {
6025         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);
6026       }
6027 #endif
6028       /* C-G face */
6029       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 10;
6030       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
6031       orntNew[0] = -2;
6032       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
6033       orntNew[1] = -2;
6034       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
6035       orntNew[2] = 0;
6036       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
6037       orntNew[3] = 0;
6038       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6039       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6040 #if 1
6041       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
6042       for (p = 0; p < 4; ++p) {
6043         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);
6044       }
6045 #endif
6046       /* B-H face */
6047       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 11;
6048       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
6049       orntNew[0] = 0;
6050       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
6051       orntNew[1] = -2;
6052       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
6053       orntNew[2] = -2;
6054       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
6055       orntNew[3] = 0;
6056       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6057       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6058 #if 1
6059       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
6060       for (p = 0; p < 4; ++p) {
6061         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);
6062       }
6063 #endif
6064       for (r = 0; r < 12; ++r) {
6065         newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
6066         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
6067         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
6068         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6069 #if 1
6070         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
6071         for (p = 0; p < 2; ++p) {
6072           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);
6073         }
6074 #endif
6075       }
6076     }
6077     /* Hybrid split faces have 4 edges and same cells */
6078     for (f = fMax; f < fEnd; ++f) {
6079       const PetscInt *cone, *ornt, *support;
6080       PetscInt        coneNew[4], orntNew[4];
6081       PetscInt        supportNew[2], size, s, c;
6082 
6083       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6084       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
6085       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6086       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6087       for (r = 0; r < 2; ++r) {
6088         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
6089 
6090         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
6091         orntNew[0]   = ornt[0];
6092         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
6093         orntNew[1]   = ornt[1];
6094         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (cone[2+r] - eMax);
6095         orntNew[2+r] = 0;
6096         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd      - eMax) + (f - fMax);
6097         orntNew[3-r] = 0;
6098         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6099         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6100 #if 1
6101         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
6102         for (p = 0; p < 2; ++p) {
6103           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);
6104         }
6105         for (p = 2; p < 4; ++p) {
6106           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);
6107         }
6108 #endif
6109         for (s = 0; s < size; ++s) {
6110           const PetscInt *coneCell, *orntCell, *fornt;
6111           PetscInt        o, of;
6112 
6113           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
6114           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
6115           o = orntCell[0] < 0 ? -1 : 1;
6116           for (c = 2; c < 6; ++c) if (coneCell[c] == f) break;
6117           if (c >= 6) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
6118           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
6119           of = fornt[c-2] < 0 ? -1 : 1;
6120           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetQuadEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%4;
6121         }
6122         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6123 #if 1
6124         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
6125         for (p = 0; p < size; ++p) {
6126           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);
6127         }
6128 #endif
6129       }
6130     }
6131     /* Hybrid cell faces have 4 edges and 2 cells */
6132     for (c = cMax; c < cEnd; ++c) {
6133       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4;
6134       const PetscInt *cone, *ornt;
6135       PetscInt        coneNew[4], orntNew[4];
6136       PetscInt        supportNew[2];
6137 
6138       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6139       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6140       for (r = 0; r < 4; ++r) {
6141 #if 0
6142         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], r);
6143         orntNew[0] = 0;
6144         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], r);
6145         orntNew[1] = 0;
6146         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+GetQuadEdge_Static(ornt[0], r)] - fMax);
6147         orntNew[2] = 0;
6148         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd                                   - fMax) + (c - cMax);
6149         orntNew[3] = 0;
6150 #else
6151         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + r;
6152         orntNew[0] = 0;
6153         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + r;
6154         orntNew[1] = 0;
6155         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+r] - fMax);
6156         orntNew[2] = 0;
6157         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd      - fMax) + (c - cMax);
6158         orntNew[3] = 0;
6159 #endif
6160         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
6161         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
6162 #if 1
6163         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);
6164         for (p = 0; p < 2; ++p) {
6165           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);
6166         }
6167         for (p = 2; p < 4; ++p) {
6168           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);
6169         }
6170 #endif
6171         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], r);
6172         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], (r+1)%4);
6173         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
6174 #if 1
6175         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);
6176         for (p = 0; p < 2; ++p) {
6177           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);
6178         }
6179 #endif
6180       }
6181     }
6182     /* Interior split edges have 2 vertices and the same faces as the parent */
6183     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6184     for (e = eStart; e < eMax; ++e) {
6185       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
6186 
6187       for (r = 0; r < 2; ++r) {
6188         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
6189         const PetscInt *cone, *ornt, *support;
6190         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6191 
6192         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6193         coneNew[0]       = vStartNew + (cone[0] - vStart);
6194         coneNew[1]       = vStartNew + (cone[1] - vStart);
6195         coneNew[(r+1)%2] = newv;
6196         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6197 #if 1
6198         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6199         for (p = 0; p < 2; ++p) {
6200           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);
6201         }
6202 #endif
6203         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
6204         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
6205         for (s = 0; s < supportSize; ++s) {
6206           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6207           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6208           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
6209           for (c = 0; c < coneSize; ++c) {
6210             if (cone[c] == e) break;
6211           }
6212           if (support[s] < fMax) {
6213             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%4;
6214           } else {
6215             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
6216           }
6217         }
6218         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6219 #if 1
6220         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6221         for (p = 0; p < supportSize; ++p) {
6222           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);
6223         }
6224 #endif
6225       }
6226     }
6227     /* Interior face edges have 2 vertices and 2+cells faces */
6228     for (f = fStart; f < fMax; ++f) {
6229       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};
6230       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
6231       const PetscInt *cone, *coneCell, *orntCell, *support;
6232       PetscInt        coneNew[2], coneSize, c, supportSize, s;
6233 
6234       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6235       for (r = 0; r < 4; ++r) {
6236         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
6237 
6238         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
6239         coneNew[1] = newv;
6240         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6241 #if 1
6242         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6243         for (p = 0; p < 2; ++p) {
6244           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);
6245         }
6246 #endif
6247         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6248         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6249         supportRef[0] = fStartNew + (f - fStart)*4 + r;
6250         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
6251         for (s = 0; s < supportSize; ++s) {
6252           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6253           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
6254           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
6255           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
6256           if (support[s] < cMax) {
6257             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
6258           } else {
6259             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + r;
6260           }
6261         }
6262         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6263 #if 1
6264         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6265         for (p = 0; p < 2+supportSize; ++p) {
6266           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);
6267         }
6268 #endif
6269       }
6270     }
6271     /* Interior cell edges have 2 vertices and 4 faces */
6272     for (c = cStart; c < cMax; ++c) {
6273       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};
6274       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
6275       const PetscInt *cone;
6276       PetscInt        coneNew[2], supportNew[4];
6277 
6278       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6279       for (r = 0; r < 6; ++r) {
6280         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
6281 
6282         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
6283         coneNew[1] = newv;
6284         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6285 #if 1
6286         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6287         for (p = 0; p < 2; ++p) {
6288           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);
6289         }
6290 #endif
6291         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
6292         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6293 #if 1
6294         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6295         for (p = 0; p < 4; ++p) {
6296           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);
6297         }
6298 #endif
6299       }
6300     }
6301     /* Hybrid edges have two vertices and the same faces */
6302     for (e = eMax; e < eEnd; ++e) {
6303       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
6304       const PetscInt *cone, *support, *fcone;
6305       PetscInt        coneNew[2], size, fsize, s;
6306 
6307       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6308       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
6309       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
6310       coneNew[0] = vStartNew + (cone[0] - vStart);
6311       coneNew[1] = vStartNew + (cone[1] - vStart);
6312       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6313 #if 1
6314       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6315       for (p = 0; p < 2; ++p) {
6316         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);
6317       }
6318 #endif
6319       for (s = 0; s < size; ++s) {
6320         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
6321         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
6322         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
6323         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
6324         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + c-2;
6325       }
6326       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6327 #if 1
6328       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6329       for (p = 0; p < size; ++p) {
6330         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);
6331       }
6332 #endif
6333     }
6334     /* Hybrid face edges have 2 vertices and 2+cells faces */
6335     for (f = fMax; f < fEnd; ++f) {
6336       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
6337       const PetscInt *cone, *support, *ccone, *cornt;
6338       PetscInt        coneNew[2], size, csize, s;
6339 
6340       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6341       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6342       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6343       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
6344       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
6345       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6346 #if 1
6347       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6348       for (p = 0; p < 2; ++p) {
6349         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);
6350       }
6351 #endif
6352       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 0;
6353       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 1;
6354       for (s = 0; s < size; ++s) {
6355         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
6356         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
6357         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
6358         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
6359         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]);
6360         supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + c-2;
6361       }
6362       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6363 #if 1
6364       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6365       for (p = 0; p < 2+size; ++p) {
6366         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);
6367       }
6368 #endif
6369     }
6370     /* Hybrid cell edges have 2 vertices and 4 faces */
6371     for (c = cMax; c < cEnd; ++c) {
6372       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
6373       const PetscInt *cone, *support;
6374       PetscInt        coneNew[2], size;
6375 
6376       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6377       ierr = DMPlexGetSupportSize(dm, c, &size);CHKERRQ(ierr);
6378       ierr = DMPlexGetSupport(dm, c, &support);CHKERRQ(ierr);
6379       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
6380       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
6381       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6382 #if 1
6383       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6384       for (p = 0; p < 2; ++p) {
6385         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);
6386       }
6387 #endif
6388       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 0;
6389       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 1;
6390       supportRef[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 2;
6391       supportRef[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 3;
6392       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6393 #if 1
6394       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6395       for (p = 0; p < 4; ++p) {
6396         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);
6397       }
6398 #endif
6399     }
6400     /* Interior vertices have identical supports */
6401     for (v = vStart; v < vEnd; ++v) {
6402       const PetscInt  newp = vStartNew + (v - vStart);
6403       const PetscInt *support, *cone;
6404       PetscInt        size, s;
6405 
6406       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6407       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6408       for (s = 0; s < size; ++s) {
6409         PetscInt r = 0;
6410 
6411         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6412         if (cone[1] == v) r = 1;
6413         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
6414         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (support[s] - eMax);
6415       }
6416       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6417 #if 1
6418       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6419       for (p = 0; p < size; ++p) {
6420         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);
6421       }
6422 #endif
6423     }
6424     /* Interior edge vertices have 2 + faces supports */
6425     for (e = eStart; e < eMax; ++e) {
6426       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
6427       const PetscInt *cone, *support;
6428       PetscInt        size, s;
6429 
6430       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
6431       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
6432       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
6433       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
6434       for (s = 0; s < size; ++s) {
6435         PetscInt r;
6436 
6437         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6438         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
6439         if (support[s] < fMax) {
6440           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*4 + r;
6441         } else {
6442           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (support[s] - fMax);
6443         }
6444       }
6445       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6446 #if 1
6447       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6448       for (p = 0; p < 2+size; ++p) {
6449         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);
6450       }
6451 #endif
6452     }
6453     /* Interior face vertices have 4 + cells supports */
6454     for (f = fStart; f < fMax; ++f) {
6455       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
6456       const PetscInt *cone, *support;
6457       PetscInt        size, s;
6458 
6459       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6460       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6461       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eMax - eStart)*2 +  (f - fStart)*4 + r;
6462       for (s = 0; s < size; ++s) {
6463         PetscInt r;
6464 
6465         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6466         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
6467         if (support[s] < cMax) {
6468           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (support[s] - cStart)*6 + r;
6469         } else {
6470           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax       - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (support[s] - cMax);
6471         }
6472       }
6473       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6474 #if 1
6475       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6476       for (p = 0; p < 4+size; ++p) {
6477         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);
6478       }
6479 #endif
6480     }
6481     /* Cell vertices have 6 supports */
6482     for (c = cStart; c < cMax; ++c) {
6483       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
6484       PetscInt       supportNew[6];
6485 
6486       for (r = 0; r < 6; ++r) {
6487         supportNew[r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
6488       }
6489       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6490     }
6491     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6492     break;
6493   default:
6494     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6495   }
6496   PetscFunctionReturn(0);
6497 }
6498 
6499 static PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6500 {
6501   PetscSection          coordSection, coordSectionNew;
6502   Vec                   coordinates, coordinatesNew;
6503   PetscScalar          *coords, *coordsNew;
6504   const PetscInt        numVertices = depthSize ? depthSize[0] : 0;
6505   PetscInt              dim, spaceDim, depth, bs, coordSizeNew, cStart, cEnd, cMax;
6506   PetscInt              c, vStart, vStartNew, vEnd, v, eStart, eEnd, eMax, e, fStart, fEnd, fMax, f;
6507   PetscInt              cStartNew, cEndNew, vEndNew, *parentId = NULL;
6508   VecType               vtype;
6509   PetscBool             isperiodic, localize = PETSC_FALSE, needcoords = PETSC_FALSE;
6510   const PetscReal      *maxCell, *L;
6511   const DMBoundaryType *bd;
6512   PetscErrorCode        ierr;
6513 
6514   PetscFunctionBegin;
6515   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6516   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6517   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6518   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6519   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6520   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6521   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, NULL);CHKERRQ(ierr);
6522   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, NULL, NULL, &vStartNew);CHKERRQ(ierr);
6523   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, NULL, NULL, &vEndNew);CHKERRQ(ierr);
6524   ierr = DMGetPeriodicity(dm, &isperiodic, &maxCell, &L, &bd);CHKERRQ(ierr);
6525   /* Determine if we need to localize coordinates when generating them */
6526   if (isperiodic && !maxCell) {
6527     ierr = DMGetCoordinatesLocalized(dm, &localize);CHKERRQ(ierr);
6528     if (!localize) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Cannot refine if coordinates have not been localized");
6529   }
6530   if (isperiodic) {
6531     ierr = PetscOptionsBegin(PetscObjectComm((PetscObject)dm),((PetscObject)dm)->prefix,"DMPlex coords refinement options","DM");CHKERRQ(ierr);
6532     ierr = PetscOptionsBool("-dm_plex_refine_localize","Automatically localize from parent cells",NULL,localize,&localize,NULL);CHKERRQ(ierr);
6533     ierr = PetscOptionsEnd();CHKERRQ(ierr);
6534     if (localize) {
6535       ierr = DMLocalizeCoordinates(dm);CHKERRQ(ierr);
6536     }
6537   }
6538   ierr = DMSetPeriodicity(rdm, isperiodic,  maxCell,  L,  bd);CHKERRQ(ierr);
6539 
6540   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6541   ierr = PetscSectionGetFieldComponents(coordSection, 0, &spaceDim);CHKERRQ(ierr);
6542   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
6543   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
6544   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, spaceDim);CHKERRQ(ierr);
6545 
6546   if (localize) {
6547     PetscInt p, r, newp, *pi;
6548 
6549     /* New coordinates will be already localized on the cell */
6550     ierr = PetscSectionSetChart(coordSectionNew, 0, vStartNew+numVertices);CHKERRQ(ierr);
6551 
6552     /* We need the parentId to properly localize coordinates */
6553     ierr = PetscMalloc1(cEndNew-cStartNew,&pi);CHKERRQ(ierr);
6554     switch (refiner) {
6555     case REFINER_NOOP:
6556       break;
6557     case REFINER_SIMPLEX_1D:
6558       for (p = cStart; p < cEnd; ++p) {
6559         for (r = 0; r < 2; ++r) {
6560           newp     = (p - cStart)*2 + r;
6561           pi[newp] = p;
6562         }
6563       }
6564       break;
6565     case REFINER_SIMPLEX_2D:
6566       for (p = cStart; p < cEnd; ++p) {
6567         for (r = 0; r < 4; ++r) {
6568           newp     = (p - cStart)*4 + r;
6569           pi[newp] = p;
6570         }
6571       }
6572       break;
6573     case REFINER_HEX_2D:
6574       for (p = cStart; p < cEnd; ++p) {
6575         for (r = 0; r < 4; ++r) {
6576           newp     = (p - cStart)*4 + r;
6577           pi[newp] = p;
6578         }
6579       }
6580       break;
6581     case REFINER_SIMPLEX_TO_HEX_2D:
6582       for (p = cStart; p < cEnd; ++p) {
6583         for (r = 0; r < 3; ++r) {
6584           newp     = (p - cStart)*3 + r;
6585           pi[newp] = p;
6586         }
6587       }
6588       break;
6589     case REFINER_HYBRID_SIMPLEX_2D:
6590       for (p = cStart; p < cMax; ++p) {
6591         for (r = 0; r < 4; ++r) {
6592           newp     = (p - cStart)*4 + r;
6593           pi[newp] = p;
6594         }
6595       }
6596       for (p = cMax; p < cEnd; ++p) {
6597         for (r = 0; r < 2; ++r) {
6598           newp     = (cMax - cStart)*4 + (p - cMax)*2 + r;
6599           pi[newp] = p;
6600         }
6601       }
6602       break;
6603     case REFINER_HYBRID_HEX_2D:
6604       for (p = cStart; p < cMax; ++p) {
6605         for (r = 0; r < 4; ++r) {
6606           newp     = (p - cStart)*4 + r;
6607           pi[newp] = p;
6608         }
6609       }
6610       for (p = cMax; p < cEnd; ++p) {
6611         for (r = 0; r < 2; ++r) {
6612           newp     = (cMax - cStart)*4 + (p - cMax)*2 + r;
6613           pi[newp] = p;
6614         }
6615       }
6616       break;
6617     case REFINER_SIMPLEX_3D:
6618       for (p = cStart; p < cEnd; ++p) {
6619         for (r = 0; r < 8; ++r) {
6620           newp     = (p - cStart)*8 + r;
6621           pi[newp] = p;
6622         }
6623       }
6624       break;
6625     case REFINER_HYBRID_SIMPLEX_3D:
6626       for (p = cStart; p < cMax; ++p) {
6627         for (r = 0; r < 8; ++r) {
6628           newp     = (p - cStart)*8 + r;
6629           pi[newp] = p;
6630         }
6631       }
6632       for (p = cMax; p < cEnd; ++p) {
6633         for (r = 0; r < 4; ++r) {
6634           newp     = (cMax - cStart)*8 + (p - cMax)*4 + r;
6635           pi[newp] = p;
6636         }
6637       }
6638       break;
6639     case REFINER_SIMPLEX_TO_HEX_3D:
6640       for (p = cStart; p < cEnd; ++p) {
6641         for (r = 0; r < 4; ++r) {
6642           newp     = (p - cStart)*4 + r;
6643           pi[newp] = p;
6644         }
6645       }
6646       break;
6647     case REFINER_HEX_3D:
6648       for (p = cStart; p < cEnd; ++p) {
6649         for (r = 0; r < 8; ++r) {
6650           newp = (p - cStart)*8 + r;
6651           pi[newp] = p;
6652         }
6653       }
6654       break;
6655     case REFINER_HYBRID_HEX_3D:
6656       for (p = cStart; p < cMax; ++p) {
6657         for (r = 0; r < 8; ++r) {
6658           newp = (p - cStart)*8 + r;
6659           pi[newp] = p;
6660         }
6661       }
6662       for (p = cMax; p < cEnd; ++p) {
6663         for (r = 0; r < 4; ++r) {
6664           newp = (cMax - cStart)*8 + (p - cMax)*4 + r;
6665           pi[newp] = p;
6666         }
6667       }
6668       break;
6669     default:
6670       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6671     }
6672     parentId = pi;
6673   } else {
6674     ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+numVertices);CHKERRQ(ierr);
6675   }
6676   if (cMax < 0) cMax = cEnd;
6677   if (fMax < 0) fMax = fEnd;
6678   if (eMax < 0) eMax = eEnd;
6679 
6680   /* All vertices have the spaceDim coordinates */
6681   if (localize) {
6682     PetscInt c;
6683 
6684     for (c = cStartNew; c < cEndNew; ++c) {
6685       PetscInt *cone = NULL;
6686       PetscInt  closureSize, coneSize = 0, p, pdof;
6687 
6688       ierr = PetscSectionGetDof(coordSection, parentId[c], &pdof); CHKERRQ(ierr);
6689       if (pdof) { /* localize on all cells that are refinement of a localized parent cell */
6690         ierr = DMPlexGetTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6691         for (p = 0; p < closureSize*2; p += 2) {
6692           const PetscInt point = cone[p];
6693           if ((point >= vStartNew) && (point < vEndNew)) coneSize++;
6694         }
6695         ierr = DMPlexRestoreTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6696         ierr = PetscSectionSetDof(coordSectionNew, c, coneSize*spaceDim);CHKERRQ(ierr);
6697         ierr = PetscSectionSetFieldDof(coordSectionNew, c, 0, coneSize*spaceDim);CHKERRQ(ierr);
6698       }
6699     }
6700   }
6701   for (v = vStartNew; v < vStartNew+numVertices; ++v) {
6702     ierr = PetscSectionSetDof(coordSectionNew, v, spaceDim);CHKERRQ(ierr);
6703     ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, spaceDim);CHKERRQ(ierr);
6704   }
6705   ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
6706   ierr = DMSetCoordinateSection(rdm, PETSC_DETERMINE, coordSectionNew);CHKERRQ(ierr);
6707   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6708   ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
6709   ierr = VecCreate(PETSC_COMM_SELF, &coordinatesNew);CHKERRQ(ierr);
6710   ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
6711   ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
6712   ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr);
6713   ierr = VecSetBlockSize(coordinatesNew, bs);CHKERRQ(ierr);
6714   ierr = VecGetType(coordinates, &vtype);CHKERRQ(ierr);
6715   ierr = VecSetType(coordinatesNew, vtype);CHKERRQ(ierr);
6716   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
6717   ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6718 
6719   switch (refiner) {
6720   case REFINER_NOOP: break;
6721   case REFINER_SIMPLEX_TO_HEX_3D:
6722   case REFINER_HEX_3D:
6723   case REFINER_HYBRID_HEX_3D:
6724     /* Face vertices have the average of corner coordinates */
6725     for (f = fStart; f < fMax; ++f) {
6726       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
6727       PetscInt      *cone = NULL;
6728       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
6729 
6730       ierr = DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6731       for (p = 0; p < closureSize*2; p += 2) {
6732         const PetscInt point = cone[p];
6733         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
6734       }
6735       if (localize) {
6736         const PetscInt *support = NULL;
6737         PetscInt       *rStar = NULL;
6738         PetscInt        supportSize, rStarSize, coff, s, ccoff[8];
6739         PetscBool       cellfound = PETSC_FALSE;
6740 
6741         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
6742         ierr = DMPlexGetSupportSize(dm,f,&supportSize);CHKERRQ(ierr);
6743         ierr = DMPlexGetSupport(dm,f,&support);CHKERRQ(ierr);
6744         /* Compute average of coordinates for each cell sharing the face */
6745         for (s = 0; s < supportSize; ++s) {
6746           PetscScalar     coordsNewAux[3] = { 0.0, 0.0, 0.0 };
6747           PetscInt       *cellCone = NULL;
6748           PetscInt        cellClosureSize, cellConeSize = 0, cdof;
6749           const PetscInt  cell = support[s];
6750           PetscBool       copyoff = PETSC_FALSE;
6751 
6752           ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
6753           for (p = 0; p < cellClosureSize*2; p += 2) {
6754             const PetscInt point = cellCone[p];
6755             if ((point >= vStart) && (point < vEnd)) cellCone[cellConeSize++] = point;
6756           }
6757           ierr = PetscSectionGetDof(coordSection, cell, &cdof);CHKERRQ(ierr);
6758           if (!cdof) { /* the parent cell does not have localized coordinates */
6759             cellfound = PETSC_TRUE;
6760             for (v = 0; v < coneSize; ++v) {
6761               ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
6762               for (d = 0; d < spaceDim; ++d) coordsNewAux[d] += coords[off[v]+d];
6763             }
6764             for (d = 0; d < spaceDim; ++d) coordsNewAux[d] /= coneSize;
6765           } else {
6766             ierr = PetscSectionGetOffset(coordSection, cell, &coff);CHKERRQ(ierr);
6767             for (p = 0; p < coneSize; ++p) {
6768               const PetscInt tv = cone[p];
6769               PetscInt       cv, voff;
6770               PetscBool      locv = PETSC_TRUE;
6771 
6772               for (cv = 0; cv < cellConeSize; ++cv) {
6773                 if (cellCone[cv] == tv) {
6774                   ccoff[p] = spaceDim*cv + coff;
6775                   break;
6776                 }
6777               }
6778               if (cv == cellConeSize) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map vertex %D\n",tv);
6779 
6780               ierr = PetscSectionGetOffset(coordSection, cone[p], &voff);CHKERRQ(ierr);
6781               for (d = 0; d < spaceDim; ++d) {
6782                 coordsNewAux[d] += coords[ccoff[p]+d];
6783                 if (!cellfound && coords[voff+d] != coords[ccoff[p]+d]) locv = PETSC_FALSE;
6784               }
6785               if (locv && !cellfound) {
6786                 cellfound = PETSC_TRUE;
6787                 copyoff   = PETSC_TRUE;
6788               }
6789             }
6790             for (d = 0; d < spaceDim; ++d) coordsNewAux[d] /= coneSize;
6791 
6792             /* Found a valid face for the "vertex" part of the Section (physical space)
6793                i.e., a face that has at least one corner in the physical space */
6794             if (copyoff) for (p = 0; p < coneSize; ++p) off[p] = ccoff[p];
6795           }
6796 
6797           /* Localize new coordinates on each refined cell */
6798           for (v = 0; v < rStarSize*2; v += 2) {
6799             if ((rStar[v] >= cStartNew) && (rStar[v] < cEndNew) && parentId[rStar[v]-cStartNew] == cell) {
6800               PetscInt       *rcone = NULL, rclosureSize, lid, rcdof, rcoff;
6801               const PetscInt  rcell = rStar[v];
6802 
6803               ierr = PetscSectionGetDof(coordSectionNew, rcell, &rcdof);CHKERRQ(ierr);
6804               if (!rcdof) continue;
6805               ierr = PetscSectionGetOffset(coordSectionNew, rcell, &rcoff);CHKERRQ(ierr);
6806               ierr = DMPlexGetTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
6807               for (p = 0, lid = 0; p < rclosureSize*2; p += 2) {
6808                 if (rcone[p] == newv) {
6809                   for (d = 0; d < spaceDim; d++) coordsNew[rcoff + lid*spaceDim + d] = coordsNewAux[d];
6810                   break;
6811                 }
6812                 if (rcone[p] >= vStartNew && rcone[p] < vEndNew) lid++;
6813               }
6814               ierr = DMPlexRestoreTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
6815               if (p == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
6816             }
6817           }
6818           ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
6819         }
6820         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
6821         if (!cellfound) {
6822           /* Could not find a valid face for the vertex part, we will get this vertex later (final reduction) */
6823           needcoords = PETSC_TRUE;
6824           coneSize   = 0;
6825         }
6826       } else {
6827         for (v = 0; v < coneSize; ++v) {
6828           ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
6829         }
6830       }
6831       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6832       if (coneSize) {
6833         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
6834         for (v = 0; v < coneSize; ++v) {ierr = DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);CHKERRQ(ierr);}
6835         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
6836       } else {
6837         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = PETSC_MIN_REAL;
6838       }
6839       ierr = DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6840     }
6841   case REFINER_SIMPLEX_TO_HEX_2D:
6842   case REFINER_HEX_2D:
6843   case REFINER_HYBRID_HEX_2D:
6844   case REFINER_SIMPLEX_1D:
6845     /* Cell vertices have the average of corner coordinates */
6846     for (c = cStart; c < cMax; ++c) {
6847       const PetscInt newv = vStartNew + (vEnd - vStart) + (dim > 1 ? (eMax - eStart) : 0) + (c - cStart) + (dim > 2 ? (fMax - fStart) : 0);
6848       PetscInt      *cone = NULL;
6849       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d, cdof = 0;
6850 
6851       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6852       for (p = 0; p < closureSize*2; p += 2) {
6853         const PetscInt point = cone[p];
6854         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
6855       }
6856       if (localize) {
6857         ierr = PetscSectionGetDof(coordSection, c, &cdof);CHKERRQ(ierr);
6858       }
6859       if (cdof) {
6860         PetscInt coff;
6861 
6862         ierr = PetscSectionGetOffset(coordSection, c, &coff);CHKERRQ(ierr);
6863         for (v = 0; v < coneSize; ++v) off[v] = spaceDim*v + coff;
6864       } else {
6865         for (v = 0; v < coneSize; ++v) {
6866           ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
6867         }
6868       }
6869       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6870       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
6871       for (v = 0; v < coneSize; ++v) {ierr = DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);CHKERRQ(ierr);}
6872       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
6873       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6874 
6875       /* Localize new coordinates on each refined cell */
6876       if (cdof) {
6877         PetscInt *rStar = NULL, rStarSize;
6878 
6879         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
6880         for (v = 0; v < rStarSize*2; v += 2) {
6881           if ((rStar[v] >= cStartNew) && (rStar[v] < cEndNew)) {
6882             PetscInt *cone = NULL, closureSize, lid, coff, rc, rcdof;
6883 
6884             rc   = rStar[v];
6885             ierr = PetscSectionGetDof(coordSectionNew, rc, &rcdof);CHKERRQ(ierr);
6886             if (!rcdof) continue;
6887             ierr = PetscSectionGetOffset(coordSectionNew, rc, &coff);CHKERRQ(ierr);
6888             ierr = DMPlexGetTransitiveClosure(rdm, rc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6889             for (p = 0, lid = 0; p < closureSize*2; p += 2) {
6890               if (cone[p] == newv) {
6891                 for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = coordsNew[offnew + d];
6892                 break;
6893               }
6894               if (cone[p] >= vStartNew && cone[p] < vEndNew) lid++;
6895             }
6896             if (p == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
6897             ierr = DMPlexRestoreTransitiveClosure(rdm, rc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6898           }
6899         }
6900         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
6901       }
6902     }
6903   case REFINER_SIMPLEX_2D:
6904   case REFINER_HYBRID_SIMPLEX_2D:
6905   case REFINER_SIMPLEX_3D:
6906   case REFINER_HYBRID_SIMPLEX_3D:
6907     /* Edge vertices have the average of endpoint coordinates */
6908     for (e = eStart; e < eMax; ++e) {
6909       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
6910       const PetscInt *cone;
6911       PetscInt        coneSize, offA, offB, offnew, d;
6912 
6913       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
6914       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
6915       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6916       if (localize) {
6917         PetscInt   coff, toffA = -1, toffB = -1, voffA, voffB;
6918         PetscInt  *eStar = NULL, eStarSize;
6919         PetscInt  *rStar = NULL, rStarSize;
6920         PetscBool  cellfound = PETSC_FALSE;
6921 
6922         offA = offB = -1;
6923         ierr = PetscSectionGetOffset(coordSection, cone[0], &voffA);CHKERRQ(ierr);
6924         ierr = PetscSectionGetOffset(coordSection, cone[1], &voffB);CHKERRQ(ierr);
6925         ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &eStarSize, &eStar);CHKERRQ(ierr);
6926         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
6927         for (v = 0; v < eStarSize*2; v += 2) {
6928           if ((eStar[v] >= cStart) && (eStar[v] < cEnd)) {
6929             PetscScalar     coordsNewAux[3];
6930             PetscInt       *cellCone = NULL;
6931             PetscInt        cellClosureSize, s, cv, cdof;
6932             PetscBool       locvA = PETSC_TRUE, locvB = PETSC_TRUE;
6933             const PetscInt  cell = eStar[v];
6934 
6935             ierr = PetscSectionGetDof(coordSection, cell, &cdof);CHKERRQ(ierr);
6936             if (!cdof) {
6937               /* Found a valid edge for the "vertex" part of the Section */
6938               offA = voffA;
6939               offB = voffB;
6940               cellfound = PETSC_TRUE;
6941             } else {
6942               ierr = PetscSectionGetOffset(coordSection, cell, &coff);CHKERRQ(ierr);
6943               ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
6944               for (s = 0, cv = 0; s < cellClosureSize*2; s += 2) {
6945                 const PetscInt point = cellCone[s];
6946                 if ((point >= vStart) && (point < vEnd)) {
6947                   if (point == cone[0]) toffA = spaceDim*cv + coff;
6948                   else if (point == cone[1]) toffB = spaceDim*cv + coff;
6949                   cv++;
6950                 }
6951               }
6952               ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
6953               for (d = 0; d < spaceDim; ++d) {
6954                 coordsNewAux[d] = 0.5*(coords[toffA+d] + coords[toffB+d]);
6955                 if (coords[toffA+d] != coords[voffA+d]) locvA = PETSC_FALSE;
6956                 if (coords[toffB+d] != coords[voffB+d]) locvB = PETSC_FALSE;
6957               }
6958               /* Found a valid edge for the "vertex" part of the Section */
6959               if (!cellfound && (locvA || locvB)) {
6960                 cellfound = PETSC_TRUE;
6961                 offA = toffA;
6962                 offB = toffB;
6963               }
6964             }
6965 
6966             /* Localize new coordinates on each refined cell */
6967             for (s = 0; s < rStarSize*2; s += 2) {
6968               if ((rStar[s] >= cStartNew) && (rStar[s] < cEndNew) && parentId[rStar[s]-cStartNew] == cell) {
6969                 PetscInt       *rcone = NULL, rclosureSize, lid, p, rcdof;
6970                 const PetscInt  rcell = rStar[s];
6971 
6972                 ierr = PetscSectionGetDof(coordSectionNew, rcell, &rcdof);CHKERRQ(ierr);
6973                 if (!rcdof) continue;
6974                 ierr = PetscSectionGetOffset(coordSectionNew, rcell, &coff);CHKERRQ(ierr);
6975                 ierr = DMPlexGetTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
6976                 for (p = 0, lid = 0; p < rclosureSize*2; p += 2) {
6977                   if (rcone[p] == newv) {
6978                     for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = coordsNewAux[d];
6979                     break;
6980                   }
6981                   if (rcone[p] >= vStartNew && rcone[p] < vEndNew) lid++;
6982                 }
6983                 ierr = DMPlexRestoreTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
6984                 if (p == rclosureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
6985               }
6986             }
6987           }
6988         }
6989         ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &eStarSize, &eStar);CHKERRQ(ierr);
6990         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
6991         if (!cellfound) {
6992           /* Could not find a valid edge for the vertex part, we will get this vertex later (final reduction) */
6993           needcoords = PETSC_TRUE;
6994         }
6995       } else {
6996         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6997         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6998       }
6999       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
7000       if (offA != -1 && offB != -1) {
7001         ierr = DMLocalizeCoordinate_Internal(dm, spaceDim, &coords[offA], &coords[offB], &coordsNew[offnew]);CHKERRQ(ierr);
7002         for (d = 0; d < spaceDim; ++d) {
7003           coordsNew[offnew+d] = 0.5*(coords[offA+d] + coordsNew[offnew+d]);
7004         }
7005       } else {
7006         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = PETSC_MIN_REAL;
7007       }
7008     }
7009     /* Old vertices have the same coordinates */
7010     for (v = vStart; v < vEnd; ++v) {
7011       const PetscInt newv = vStartNew + (v - vStart);
7012       PetscInt       off, offnew, d;
7013 
7014       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
7015       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
7016       for (d = 0; d < spaceDim; ++d) {
7017         coordsNew[offnew+d] = coords[off+d];
7018       }
7019 
7020       /* Localize new coordinates on each refined cell */
7021       if (localize) {
7022         PetscInt  p;
7023         PetscInt *rStar = NULL, rStarSize;
7024 
7025         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
7026         for (p = 0; p < rStarSize*2; p += 2) {
7027           if ((rStar[p] >= cStartNew) && (rStar[p] < cEndNew)) {
7028             PetscScalar  ocoords[3];
7029             PetscInt    *cone = NULL, closureSize, lid, coff, s, oc, cdof;
7030 
7031             c    = rStar[p];
7032             oc   = parentId[c-cStartNew];
7033             ierr = PetscSectionGetDof(coordSectionNew, c, &cdof);CHKERRQ(ierr);
7034             if (!cdof) continue;
7035             ierr = PetscSectionGetDof(coordSection, oc, &cdof);CHKERRQ(ierr);
7036             if (!cdof) continue;
7037             ierr = PetscSectionGetOffset(coordSection, oc, &coff);CHKERRQ(ierr);
7038             ierr = DMPlexGetTransitiveClosure(dm, oc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
7039             for (s = 0, lid = 0; s < closureSize*2; s += 2) {
7040               if (cone[s] == v) {
7041                 for (d = 0; d < spaceDim; d++) ocoords[d] = coords[coff + lid*spaceDim + d];
7042                 break;
7043               }
7044               if (cone[s] >= vStart && cone[s] < vEnd) lid++;
7045             }
7046             if (s == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map old vertex %D\n",v);
7047             ierr = DMPlexRestoreTransitiveClosure(dm, oc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
7048 
7049             ierr = PetscSectionGetOffset(coordSectionNew, c, &coff);CHKERRQ(ierr);
7050             ierr = DMPlexGetTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
7051             for (s = 0, lid = 0; s < closureSize*2; s += 2) {
7052               if (cone[s] == newv) {
7053                 for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = ocoords[d];
7054                 break;
7055               }
7056               if (cone[s] >= vStartNew && cone[s] < vEndNew) lid++;
7057             }
7058             if (s == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
7059             ierr = DMPlexRestoreTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
7060           }
7061         }
7062         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
7063       }
7064     }
7065     break;
7066   default:
7067     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7068   }
7069   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
7070   ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
7071   ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
7072 
7073   /* Final reduction (if needed) if we are localizing */
7074   if (localize) {
7075     PetscBool gred;
7076 
7077     ierr = MPIU_Allreduce(&needcoords, &gred, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)rdm));CHKERRQ(ierr);
7078     if (gred) {
7079       DM                 cdm;
7080       Vec                aux;
7081       PetscSF            sf;
7082       const PetscScalar *lArray;
7083       PetscScalar       *gArray;
7084 
7085       ierr = DMGetCoordinateDM(rdm, &cdm);CHKERRQ(ierr);
7086       ierr = DMCreateGlobalVector(cdm, &aux);CHKERRQ(ierr);
7087       ierr = DMGetDefaultSF(cdm, &sf);CHKERRQ(ierr);
7088       ierr = VecGetArrayRead(coordinatesNew, &lArray);CHKERRQ(ierr);
7089       ierr = VecSet(aux, PETSC_MIN_REAL);CHKERRQ(ierr);
7090       ierr = VecGetArray(aux, &gArray);CHKERRQ(ierr);
7091       ierr = PetscSFReduceBegin(sf, MPIU_SCALAR, lArray, gArray, MPIU_MAX);CHKERRQ(ierr);
7092       ierr = PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_MAX);CHKERRQ(ierr);
7093       ierr = VecRestoreArrayRead(coordinatesNew, &lArray);CHKERRQ(ierr);
7094       ierr = VecRestoreArray(aux, &gArray);CHKERRQ(ierr);
7095       ierr = DMGlobalToLocalBegin(cdm, aux, INSERT_VALUES, coordinatesNew);CHKERRQ(ierr);
7096       ierr = DMGlobalToLocalEnd(cdm, aux, INSERT_VALUES, coordinatesNew);CHKERRQ(ierr);
7097       ierr = VecDestroy(&aux);CHKERRQ(ierr);
7098     }
7099   }
7100   ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
7101   ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
7102   ierr = PetscFree(parentId);CHKERRQ(ierr);
7103   PetscFunctionReturn(0);
7104 }
7105 
7106 /*@
7107   DMPlexCreateProcessSF - Create an SF which just has process connectivity
7108 
7109   Collective on DM
7110 
7111   Input Parameters:
7112 + dm      - The DM
7113 - sfPoint - The PetscSF which encodes point connectivity
7114 
7115   Output Parameters:
7116 + processRanks - A list of process neighbors, or NULL
7117 - sfProcess    - An SF encoding the process connectivity, or NULL
7118 
7119   Level: developer
7120 
7121 .seealso: PetscSFCreate(), DMPlexCreateTwoSidedProcessSF()
7122 @*/
7123 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
7124 {
7125   PetscInt           numRoots, numLeaves, l;
7126   const PetscInt    *localPoints;
7127   const PetscSFNode *remotePoints;
7128   PetscInt          *localPointsNew;
7129   PetscSFNode       *remotePointsNew;
7130   PetscInt          *ranks, *ranksNew;
7131   PetscMPIInt        size;
7132   PetscErrorCode     ierr;
7133 
7134   PetscFunctionBegin;
7135   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7136   PetscValidHeaderSpecific(sfPoint, PETSCSF_CLASSID, 2);
7137   if (processRanks) {PetscValidPointer(processRanks, 3);}
7138   if (sfProcess)    {PetscValidPointer(sfProcess, 4);}
7139   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) dm), &size);CHKERRQ(ierr);
7140   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
7141   ierr = PetscMalloc1(numLeaves, &ranks);CHKERRQ(ierr);
7142   for (l = 0; l < numLeaves; ++l) {
7143     ranks[l] = remotePoints[l].rank;
7144   }
7145   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
7146   ierr = PetscMalloc1(numLeaves, &ranksNew);CHKERRQ(ierr);
7147   ierr = PetscMalloc1(numLeaves, &localPointsNew);CHKERRQ(ierr);
7148   ierr = PetscMalloc1(numLeaves, &remotePointsNew);CHKERRQ(ierr);
7149   for (l = 0; l < numLeaves; ++l) {
7150     ranksNew[l]              = ranks[l];
7151     localPointsNew[l]        = l;
7152     remotePointsNew[l].index = 0;
7153     remotePointsNew[l].rank  = ranksNew[l];
7154   }
7155   ierr = PetscFree(ranks);CHKERRQ(ierr);
7156   if (processRanks) {ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);}
7157   else              {ierr = PetscFree(ranksNew);CHKERRQ(ierr);}
7158   if (sfProcess) {
7159     ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
7160     ierr = PetscObjectSetName((PetscObject) *sfProcess, "Process SF");CHKERRQ(ierr);
7161     ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
7162     ierr = PetscSFSetGraph(*sfProcess, size, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7163   }
7164   PetscFunctionReturn(0);
7165 }
7166 
7167 static PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7168 {
7169   PetscSF            sf, sfNew, sfProcess;
7170   IS                 processRanks;
7171   MPI_Datatype       depthType;
7172   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
7173   const PetscInt    *localPoints, *neighbors;
7174   const PetscSFNode *remotePoints;
7175   PetscInt          *localPointsNew;
7176   PetscSFNode       *remotePointsNew;
7177   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
7178   PetscInt           ldepth, depth, numNeighbors, pStartNew, pEndNew, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r, n;
7179   PetscInt           cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
7180   PetscErrorCode     ierr;
7181 
7182   PetscFunctionBegin;
7183   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
7184   ierr = DMPlexGetDepth(dm, &ldepth);CHKERRQ(ierr);
7185   ierr = MPIU_Allreduce(&ldepth, &depth, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
7186   if ((ldepth >= 0) && (depth != ldepth)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent Plex depth %d != %d", ldepth, depth);
7187   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7188   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7189   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7190   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7191   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7192   cMax = cMax < 0 ? cEnd : cMax;
7193   fMax = fMax < 0 ? fEnd : fMax;
7194   eMax = eMax < 0 ? eEnd : eMax;
7195   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
7196   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
7197   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
7198   /* Calculate size of new SF */
7199   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
7200   if (numRoots < 0) PetscFunctionReturn(0);
7201   for (l = 0; l < numLeaves; ++l) {
7202     const PetscInt p = localPoints[l];
7203 
7204     switch (refiner) {
7205     case REFINER_SIMPLEX_1D:
7206       if ((p >= vStart) && (p < vEnd)) {
7207         /* Interior vertices stay the same */
7208         ++numLeavesNew;
7209       } else if ((p >= cStart && p < cMax)) {
7210         /* Interior cells add new cells and interior vertices */
7211         numLeavesNew += 2 + 1;
7212       }
7213       break;
7214     case REFINER_SIMPLEX_2D:
7215     case REFINER_HYBRID_SIMPLEX_2D:
7216       if ((p >= vStart) && (p < vEnd)) {
7217         /* Interior vertices stay the same */
7218         ++numLeavesNew;
7219       } else if ((p >= fStart) && (p < fMax)) {
7220         /* Interior faces add new faces and vertex */
7221         numLeavesNew += 2 + 1;
7222       } else if ((p >= fMax) && (p < fEnd)) {
7223         /* Hybrid faces stay the same */
7224         ++numLeavesNew;
7225       } else if ((p >= cStart) && (p < cMax)) {
7226         /* Interior cells add new cells and interior faces */
7227         numLeavesNew += 4 + 3;
7228       } else if ((p >= cMax) && (p < cEnd)) {
7229         /* Hybrid cells add new cells and hybrid face */
7230         numLeavesNew += 2 + 1;
7231       }
7232       break;
7233     case REFINER_SIMPLEX_TO_HEX_2D:
7234       if ((p >= vStart) && (p < vEnd)) {
7235         /* Interior vertices stay the same */
7236         ++numLeavesNew;
7237       } else if ((p >= fStart) && (p < fEnd)) {
7238         /* Interior faces add new faces and vertex */
7239         numLeavesNew += 2 + 1;
7240       } else if ((p >= cStart) && (p < cEnd)) {
7241         /* Interior cells add new cells, interior faces, and vertex */
7242         numLeavesNew += 3 + 3 + 1;
7243       }
7244       break;
7245     case REFINER_HEX_2D:
7246     case REFINER_HYBRID_HEX_2D:
7247       if ((p >= vStart) && (p < vEnd)) {
7248         /* Interior vertices stay the same */
7249         ++numLeavesNew;
7250       } else if ((p >= fStart) && (p < fMax)) {
7251         /* Interior faces add new faces and vertex */
7252         numLeavesNew += 2 + 1;
7253       } else if ((p >= fMax) && (p < fEnd)) {
7254         /* Hybrid faces stay the same */
7255         ++numLeavesNew;
7256       } else if ((p >= cStart) && (p < cMax)) {
7257         /* Interior cells add new cells, interior faces, and vertex */
7258         numLeavesNew += 4 + 4 + 1;
7259       } else if ((p >= cMax) && (p < cEnd)) {
7260         /* Hybrid cells add new cells and hybrid face */
7261         numLeavesNew += 2 + 1;
7262       }
7263       break;
7264     case REFINER_SIMPLEX_3D:
7265     case REFINER_HYBRID_SIMPLEX_3D:
7266       if ((p >= vStart) && (p < vEnd)) {
7267         /* Interior vertices stay the same */
7268         ++numLeavesNew;
7269       } else if ((p >= eStart) && (p < eMax)) {
7270         /* Interior edges add new edges and vertex */
7271         numLeavesNew += 2 + 1;
7272       } else if ((p >= eMax) && (p < eEnd)) {
7273         /* Hybrid edges stay the same */
7274         ++numLeavesNew;
7275       } else if ((p >= fStart) && (p < fMax)) {
7276         /* Interior faces add new faces and edges */
7277         numLeavesNew += 4 + 3;
7278       } else if ((p >= fMax) && (p < fEnd)) {
7279         /* Hybrid faces add new faces and edges */
7280         numLeavesNew += 2 + 1;
7281       } else if ((p >= cStart) && (p < cMax)) {
7282         /* Interior cells add new cells, faces, and edges */
7283         numLeavesNew += 8 + 8 + 1;
7284       } else if ((p >= cMax) && (p < cEnd)) {
7285         /* Hybrid cells add new cells and faces */
7286         numLeavesNew += 4 + 3;
7287       }
7288       break;
7289     case REFINER_SIMPLEX_TO_HEX_3D:
7290       if ((p >= vStart) && (p < vEnd)) {
7291         /* Interior vertices stay the same */
7292         ++numLeavesNew;
7293       } else if ((p >= eStart) && (p < eEnd)) {
7294         /* Interior edges add new edges and vertex */
7295         numLeavesNew += 2 + 1;
7296       } else if ((p >= fStart) && (p < fEnd)) {
7297         /* Interior faces add new faces, edges and a vertex */
7298         numLeavesNew += 3 + 3 + 1;
7299       } else if ((p >= cStart) && (p < cEnd)) {
7300         /* Interior cells add new cells, faces, edges and a vertex */
7301         numLeavesNew += 4 + 6 + 4 + 1;
7302       }
7303       break;
7304     case REFINER_HEX_3D:
7305     case REFINER_HYBRID_HEX_3D:
7306       if ((p >= vStart) && (p < vEnd)) {
7307         /* Old vertices stay the same */
7308         ++numLeavesNew;
7309       } else if ((p >= eStart) && (p < eMax)) {
7310         /* Interior edges add new edges, and vertex */
7311         numLeavesNew += 2 + 1;
7312       } else if ((p >= eMax) && (p < eEnd)) {
7313         /* Hybrid edges stay the same */
7314         ++numLeavesNew;
7315       } else if ((p >= fStart) && (p < fMax)) {
7316         /* Interior faces add new faces, edges, and vertex */
7317         numLeavesNew += 4 + 4 + 1;
7318       } else if ((p >= fMax) && (p < fEnd)) {
7319         /* Hybrid faces add new faces and edges */
7320         numLeavesNew += 2 + 1;
7321       } else if ((p >= cStart) && (p < cMax)) {
7322         /* Interior cells add new cells, faces, edges, and vertex */
7323         numLeavesNew += 8 + 12 + 6 + 1;
7324       } else if ((p >= cStart) && (p < cEnd)) {
7325         /* Hybrid cells add new cells, faces, and edges */
7326         numLeavesNew += 4 + 4 + 1;
7327       }
7328       break;
7329     default:
7330       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7331     }
7332   }
7333   /* Communicate depthSizes for each remote rank */
7334   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
7335   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
7336   ierr = PetscMalloc5((depth+1)*numNeighbors,&rdepthSize,numNeighbors,&rvStartNew,numNeighbors,&reStartNew,numNeighbors,&rfStartNew,numNeighbors,&rcStartNew);CHKERRQ(ierr);
7337   ierr = PetscMalloc7(depth+1,&depthSizeOld,(depth+1)*numNeighbors,&rdepthSizeOld,(depth+1)*numNeighbors,&rdepthMaxOld,numNeighbors,&rvStart,numNeighbors,&reStart,numNeighbors,&rfStart,numNeighbors,&rcStart);CHKERRQ(ierr);
7338   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
7339   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
7340   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7341   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7342   for (n = 0; n < numNeighbors; ++n) {
7343     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
7344   }
7345   depthSizeOld[depth]   = cMax;
7346   depthSizeOld[0]       = vMax;
7347   depthSizeOld[depth-1] = fMax;
7348   depthSizeOld[1]       = eMax;
7349 
7350   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7351   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7352 
7353   depthSizeOld[depth]   = cEnd - cStart;
7354   depthSizeOld[0]       = vEnd - vStart;
7355   depthSizeOld[depth-1] = fEnd - fStart;
7356   depthSizeOld[1]       = eEnd - eStart;
7357 
7358   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7359   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7360   for (n = 0; n < numNeighbors; ++n) {
7361     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
7362     rdepthMaxOld[n*(depth+1)+depth]   = rdepthMaxOld[n*(depth+1)+depth]   < 0 ? rdepthSizeOld[n*(depth+1)+depth]  +rcStart[n]: rdepthMaxOld[n*(depth+1)+depth];
7363     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];
7364     rdepthMaxOld[n*(depth+1)+1]       = rdepthMaxOld[n*(depth+1)+1]       < 0 ? rdepthSizeOld[n*(depth+1)+1]      +reStart[n]: rdepthMaxOld[n*(depth+1)+1];
7365   }
7366   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
7367   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
7368   /* Calculate new point SF */
7369   ierr = PetscMalloc1(numLeavesNew, &localPointsNew);CHKERRQ(ierr);
7370   ierr = PetscMalloc1(numLeavesNew, &remotePointsNew);CHKERRQ(ierr);
7371   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
7372   for (l = 0, m = 0; l < numLeaves; ++l) {
7373     PetscInt    p     = localPoints[l];
7374     PetscInt    rp    = remotePoints[l].index, n;
7375     PetscMPIInt rrank = remotePoints[l].rank;
7376 
7377     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
7378     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
7379     switch (refiner) {
7380     case REFINER_SIMPLEX_1D:
7381       if ((p >= vStart) && (p < vEnd)) {
7382         /* Old vertices stay the same */
7383         localPointsNew[m]        = vStartNew     + (p  - vStart);
7384         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7385         remotePointsNew[m].rank  = rrank;
7386         ++m;
7387       } else if ((p >= cStart) && (p < cMax)) {
7388         /* Old interior cells add new cells and vertex */
7389         for (r = 0; r < 2; ++r, ++m) {
7390           localPointsNew[m]        = cStartNew     + (p  - cStart)*2     + r;
7391           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*2 + r;
7392           remotePointsNew[m].rank  = rrank;
7393         }
7394         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - cStart);
7395         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rcStart[n]);
7396         remotePointsNew[m].rank  = rrank;
7397         ++m;
7398       }
7399       break;
7400     case REFINER_SIMPLEX_2D:
7401     case REFINER_HYBRID_SIMPLEX_2D:
7402       if ((p >= vStart) && (p < vEnd)) {
7403         /* Old vertices stay the same */
7404         localPointsNew[m]        = vStartNew     + (p  - vStart);
7405         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7406         remotePointsNew[m].rank  = rrank;
7407         ++m;
7408       } else if ((p >= fStart) && (p < fMax)) {
7409         /* Old interior faces add new faces and vertex */
7410         for (r = 0; r < 2; ++r, ++m) {
7411           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7412           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7413           remotePointsNew[m].rank  = rrank;
7414         }
7415         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7416         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7417         remotePointsNew[m].rank  = rrank;
7418         ++m;
7419       } else if ((p >= fMax) && (p < fEnd)) {
7420         /* Old hybrid faces stay the same */
7421         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
7422         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
7423         remotePointsNew[m].rank  = rrank;
7424         ++m;
7425       } else if ((p >= cStart) && (p < cMax)) {
7426         /* Old interior cells add new cells and interior faces */
7427         for (r = 0; r < 4; ++r, ++m) {
7428           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7429           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7430           remotePointsNew[m].rank  = rrank;
7431         }
7432         for (r = 0; r < 3; ++r, ++m) {
7433           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
7434           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
7435           remotePointsNew[m].rank  = rrank;
7436         }
7437       } else if ((p >= cMax) && (p < cEnd)) {
7438         /* Old hybrid cells add new cells and hybrid face */
7439         for (r = 0; r < 2; ++r, ++m) {
7440           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7441           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7442           remotePointsNew[m].rank  = rrank;
7443         }
7444         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
7445         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]);
7446         remotePointsNew[m].rank  = rrank;
7447         ++m;
7448       }
7449       break;
7450     case REFINER_SIMPLEX_TO_HEX_2D:
7451       if ((p >= vStart) && (p < vEnd)) {
7452         /* Old vertices stay the same */
7453         localPointsNew[m]        = vStartNew     + (p  - vStart);
7454         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7455         remotePointsNew[m].rank  = rrank;
7456         ++m;
7457       } else if ((p >= fStart) && (p < fEnd)) {
7458         /* Old interior faces add new faces and vertex */
7459         for (r = 0; r < 2; ++r, ++m) {
7460           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7461           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7462           remotePointsNew[m].rank  = rrank;
7463         }
7464         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7465         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7466         remotePointsNew[m].rank  = rrank;
7467         ++m;
7468       } else if ((p >= cStart) && (p < cEnd)) {
7469         /* Old interior cells add new cells, interior faces, and a vertex */
7470         for (r = 0; r < 3; ++r, ++m) {
7471           localPointsNew[m]        = cStartNew     + (p  - cStart)*3     + r;
7472           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*3 + r;
7473           remotePointsNew[m].rank  = rrank;
7474         }
7475         for (r = 0; r < 3; ++r, ++m) {
7476           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
7477           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
7478           remotePointsNew[m].rank  = rrank;
7479         }
7480         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (fEnd - fStart)                    + (p  - cStart);
7481         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
7482         remotePointsNew[m].rank  = rrank;
7483         ++m;
7484       }
7485       break;
7486     case REFINER_HEX_2D:
7487     case REFINER_HYBRID_HEX_2D:
7488       if ((p >= vStart) && (p < vEnd)) {
7489         /* Old vertices stay the same */
7490         localPointsNew[m]        = vStartNew     + (p  - vStart);
7491         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7492         remotePointsNew[m].rank  = rrank;
7493         ++m;
7494       } else if ((p >= fStart) && (p < fMax)) {
7495         /* Old interior faces add new faces and vertex */
7496         for (r = 0; r < 2; ++r, ++m) {
7497           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7498           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7499           remotePointsNew[m].rank  = rrank;
7500         }
7501         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7502         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7503         remotePointsNew[m].rank  = rrank;
7504         ++m;
7505       } else if ((p >= fMax) && (p < fEnd)) {
7506         /* Old hybrid faces stay the same */
7507         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
7508         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
7509         remotePointsNew[m].rank  = rrank;
7510         ++m;
7511       } else if ((p >= cStart) && (p < cMax)) {
7512         /* Old interior cells add new cells, interior faces, and vertex */
7513         for (r = 0; r < 4; ++r, ++m) {
7514           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7515           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7516           remotePointsNew[m].rank  = rrank;
7517         }
7518         for (r = 0; r < 4; ++r, ++m) {
7519           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*4     + r;
7520           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*4 + r;
7521           remotePointsNew[m].rank  = rrank;
7522         }
7523         localPointsNew[m]        = vStartNew     + (vEnd - vStart)               + (fMax                              - fStart)     + (p  - cStart);
7524         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0]  + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]);
7525         remotePointsNew[m].rank  = rrank;
7526         ++m;
7527       } else if ((p >= cStart) && (p < cMax)) {
7528         /* Old hybrid cells add new cells and hybrid face */
7529         for (r = 0; r < 2; ++r, ++m) {
7530           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7531           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7532           remotePointsNew[m].rank  = rrank;
7533         }
7534         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*4     + (p  - cMax);
7535         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]);
7536         remotePointsNew[m].rank  = rrank;
7537         ++m;
7538       }
7539       break;
7540     case REFINER_SIMPLEX_3D:
7541     case REFINER_HYBRID_SIMPLEX_3D:
7542       if ((p >= vStart) && (p < vEnd)) {
7543         /* Interior vertices stay the same */
7544         localPointsNew[m]        = vStartNew     + (p  - vStart);
7545         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7546         remotePointsNew[m].rank  = rrank;
7547         ++m;
7548       } else if ((p >= eStart) && (p < eMax)) {
7549         /* Interior edges add new edges and vertex */
7550         for (r = 0; r < 2; ++r, ++m) {
7551           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
7552           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
7553           remotePointsNew[m].rank  = rrank;
7554         }
7555         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
7556         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
7557         remotePointsNew[m].rank  = rrank;
7558         ++m;
7559       } else if ((p >= eMax) && (p < eEnd)) {
7560         /* Hybrid edges stay the same */
7561         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - eMax);
7562         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]);
7563         remotePointsNew[m].rank  = rrank;
7564         ++m;
7565       } else if ((p >= fStart) && (p < fMax)) {
7566         /* Interior faces add new faces and edges */
7567         for (r = 0; r < 4; ++r, ++m) {
7568           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
7569           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
7570           remotePointsNew[m].rank  = rrank;
7571         }
7572         for (r = 0; r < 3; ++r, ++m) {
7573           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*3     + r;
7574           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
7575           remotePointsNew[m].rank  = rrank;
7576         }
7577       } else if ((p >= fMax) && (p < fEnd)) {
7578         /* Hybrid faces add new faces and edges */
7579         for (r = 0; r < 2; ++r, ++m) {
7580           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fMax)*2                              + r;
7581           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;
7582           remotePointsNew[m].rank  = rrank;
7583         }
7584         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (eEnd                                    - eMax)                        + (p  - fMax);
7585         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]);
7586         remotePointsNew[m].rank  = rrank;
7587         ++m;
7588       } else if ((p >= cStart) && (p < cMax)) {
7589         /* Interior cells add new cells, faces, and edges */
7590         for (r = 0; r < 8; ++r, ++m) {
7591           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
7592           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
7593           remotePointsNew[m].rank  = rrank;
7594         }
7595         for (r = 0; r < 8; ++r, ++m) {
7596           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*8     + r;
7597           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*8 + r;
7598           remotePointsNew[m].rank  = rrank;
7599         }
7600         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (p  - cStart)*1     + 0;
7601         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;
7602         remotePointsNew[m].rank  = rrank;
7603         ++m;
7604       } else if ((p >= cMax) && (p < cEnd)) {
7605         /* Hybrid cells add new cells and faces */
7606         for (r = 0; r < 4; ++r, ++m) {
7607           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
7608           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
7609           remotePointsNew[m].rank  = rrank;
7610         }
7611         for (r = 0; r < 3; ++r, ++m) {
7612           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*2                              + (p  - cMax)*3                            + r;
7613           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;
7614           remotePointsNew[m].rank  = rrank;
7615         }
7616       }
7617       break;
7618     case REFINER_SIMPLEX_TO_HEX_3D:
7619       if ((p >= vStart) && (p < vEnd)) {
7620         /* Interior vertices stay the same */
7621         localPointsNew[m]        = vStartNew     + (p  - vStart);
7622         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7623         remotePointsNew[m].rank  = rrank;
7624         ++m;
7625       } else if ((p >= eStart) && (p < eEnd)) {
7626         /* Interior edges add new edges and vertex */
7627         for (r = 0; r < 2; ++r, ++m) {
7628           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
7629           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
7630           remotePointsNew[m].rank  = rrank;
7631         }
7632         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
7633         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
7634         remotePointsNew[m].rank  = rrank;
7635         ++m;
7636       } else if ((p >= fStart) && (p < fEnd)) {
7637         /* Interior faces add new faces, edges and a vertex */
7638         for (r = 0; r < 3; ++r, ++m) {
7639           localPointsNew[m]        = fStartNew     + (p  - fStart)*3     + r;
7640           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*3 + r;
7641           remotePointsNew[m].rank  = rrank;
7642         }
7643         for (r = 0; r < 3; ++r, ++m) {
7644           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2                + (p  - fStart)*3     + r;
7645           remotePointsNew[m].index = reStartNew[n] + (rdepthSizeOld[n*(depth+1)+1])*2 + (rp - rfStart[n])*3 + r;
7646           remotePointsNew[m].rank  = rrank;
7647         }
7648         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eEnd - eStart)              + (p - fStart);
7649         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+1] + (rp - rfStart[n]);
7650         remotePointsNew[m].rank  = rrank;
7651         ++m;
7652       } else if ((p >= cStart) && (p < cEnd)) {
7653         /* Interior cells add new cells, faces, edges, and a vertex */
7654         for (r = 0; r < 4; ++r, ++m) {
7655           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7656           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7657           remotePointsNew[m].rank  = rrank;
7658         }
7659         for (r = 0; r < 6; ++r, ++m) {
7660           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*3                    + (p  - cStart)*6     + r;
7661           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*3 + (rp - rcStart[n])*6 + r;
7662           remotePointsNew[m].rank  = rrank;
7663         }
7664         for (r = 0; r < 4; ++r, ++m) {
7665           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (fEnd - fStart)*3                    + (p  - cStart)*4 + r;
7666           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + rdepthSizeOld[n*(depth+1)+depth-1]*3 + (rp - rcStart[n])*4 + r;
7667           remotePointsNew[m].rank  = rrank;
7668         }
7669         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eEnd - eStart)              + (fEnd - fStart)                    + (p - cStart);
7670         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+1] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
7671         remotePointsNew[m].rank  = rrank;
7672         ++m;
7673       }
7674       break;
7675     case REFINER_HEX_3D:
7676     case REFINER_HYBRID_HEX_3D:
7677       if ((p >= vStart) && (p < vEnd)) {
7678         /* Interior vertices stay the same */
7679         localPointsNew[m]        = vStartNew     + (p  - vStart);
7680         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7681         remotePointsNew[m].rank  = rrank;
7682         ++m;
7683       } else if ((p >= eStart) && (p < eMax)) {
7684         /* Interior edges add new edges and vertex */
7685         for (r = 0; r < 2; ++r, ++m) {
7686           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
7687           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
7688           remotePointsNew[m].rank  = rrank;
7689         }
7690         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
7691         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
7692         remotePointsNew[m].rank  = rrank;
7693         ++m;
7694       } else if ((p >= eMax) && (p < eEnd)) {
7695         /* Hybrid edges stay the same */
7696         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (p  - eMax);
7697         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]);
7698         remotePointsNew[m].rank  = rrank;
7699         ++m;
7700       } else if ((p >= fStart) && (p < fMax)) {
7701         /* Interior faces add new faces, edges, and vertex */
7702         for (r = 0; r < 4; ++r, ++m) {
7703           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
7704           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
7705           remotePointsNew[m].rank  = rrank;
7706         }
7707         for (r = 0; r < 4; ++r, ++m) {
7708           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*4     + r;
7709           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*4 + r;
7710           remotePointsNew[m].rank  = rrank;
7711         }
7712         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax                        - eStart)     + (p  - fStart);
7713         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
7714         remotePointsNew[m].rank  = rrank;
7715         ++m;
7716       } else if ((p >= fMax) && (p < fEnd)) {
7717         /* Hybrid faces add new faces and edges */
7718         for (r = 0; r < 2; ++r, ++m) {
7719           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (p  - fMax)*2                              + r;
7720           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;
7721           remotePointsNew[m].rank  = rrank;
7722         }
7723         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (p  - fMax);
7724         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]);
7725         remotePointsNew[m].rank  = rrank;
7726         ++m;
7727       } else if ((p >= cStart) && (p < cMax)) {
7728         /* Interior cells add new cells, faces, edges, and vertex */
7729         for (r = 0; r < 8; ++r, ++m) {
7730           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
7731           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
7732           remotePointsNew[m].rank  = rrank;
7733         }
7734         for (r = 0; r < 12; ++r, ++m) {
7735           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*12     + r;
7736           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*12 + r;
7737           remotePointsNew[m].rank  = rrank;
7738         }
7739         for (r = 0; r < 6; ++r, ++m) {
7740           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (p  - cStart)*6     + r;
7741           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;
7742           remotePointsNew[m].rank  = rrank;
7743         }
7744         for (r = 0; r < 1; ++r, ++m) {
7745           localPointsNew[m]        = vStartNew     + (eMax                        - eStart)     + (fMax                              - fStart)     + (p  - cStart)     + r;
7746           remotePointsNew[m].index = rvStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]) + r;
7747           remotePointsNew[m].rank  = rrank;
7748         }
7749       } else if ((p >= cMax) && (p < cEnd)) {
7750         /* Hybrid cells add new cells, faces, and edges */
7751         for (r = 0; r < 4; ++r, ++m) {
7752           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
7753           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
7754           remotePointsNew[m].rank  = rrank;
7755         }
7756         for (r = 0; r < 4; ++r, ++m) {
7757           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (fEnd                                          - fMax)*2                              + (p  - cMax)*4                            + r;
7758           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;
7759           remotePointsNew[m].rank  = rrank;
7760         }
7761         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (fEnd                                          - fMax)                              + (p  - cMax);
7762         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]);
7763         remotePointsNew[m].rank  = rrank;
7764         ++m;
7765       }
7766       break;
7767     default:
7768       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7769     }
7770   }
7771   if (m != numLeavesNew) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of leaf point %d should be %d", m, numLeavesNew);
7772   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
7773   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
7774   {
7775     PetscSFNode *rp, *rtmp;
7776     PetscInt    *lp, *idx, *ltmp, i;
7777 
7778     /* SF needs sorted leaves to correct calculate Gather */
7779     ierr = PetscMalloc1(numLeavesNew,&idx);CHKERRQ(ierr);
7780     ierr = PetscMalloc1(numLeavesNew, &lp);CHKERRQ(ierr);
7781     ierr = PetscMalloc1(numLeavesNew, &rp);CHKERRQ(ierr);
7782     for (i = 0; i < numLeavesNew; ++i) {
7783       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);
7784       idx[i] = i;
7785     }
7786     ierr = PetscSortIntWithPermutation(numLeavesNew, localPointsNew, idx);CHKERRQ(ierr);
7787     for (i = 0; i < numLeavesNew; ++i) {
7788       lp[i] = localPointsNew[idx[i]];
7789       rp[i] = remotePointsNew[idx[i]];
7790     }
7791     ltmp            = localPointsNew;
7792     localPointsNew  = lp;
7793     rtmp            = remotePointsNew;
7794     remotePointsNew = rp;
7795     ierr = PetscFree(idx);CHKERRQ(ierr);
7796     ierr = PetscFree(ltmp);CHKERRQ(ierr);
7797     ierr = PetscFree(rtmp);CHKERRQ(ierr);
7798   }
7799   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7800   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
7801   ierr = PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
7802   PetscFunctionReturn(0);
7803 }
7804 
7805 static PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7806 {
7807   PetscInt       numLabels, l;
7808   PetscInt       depth, newp, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r;
7809   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
7810   PetscErrorCode ierr;
7811 
7812   PetscFunctionBegin;
7813   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7814   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7815   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7816   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7817   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7818   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
7819   ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
7820   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7821   switch (refiner) {
7822   case REFINER_NOOP:
7823   case REFINER_SIMPLEX_1D:
7824   case REFINER_SIMPLEX_2D:
7825   case REFINER_SIMPLEX_TO_HEX_2D:
7826   case REFINER_HEX_2D:
7827   case REFINER_SIMPLEX_3D:
7828   case REFINER_HEX_3D:
7829   case REFINER_SIMPLEX_TO_HEX_3D:
7830     break;
7831   case REFINER_HYBRID_SIMPLEX_3D:
7832   case REFINER_HYBRID_HEX_3D:
7833     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
7834   case REFINER_HYBRID_SIMPLEX_2D:
7835   case REFINER_HYBRID_HEX_2D:
7836     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7837     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7838     break;
7839   default:
7840     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7841   }
7842   for (l = 0; l < numLabels; ++l) {
7843     DMLabel         label, labelNew;
7844     const char     *lname;
7845     PetscBool       isDepth;
7846     IS              valueIS;
7847     const PetscInt *values;
7848     PetscInt        defVal;
7849     PetscInt        numValues, val;
7850 
7851     ierr = DMGetLabelName(dm, l, &lname);CHKERRQ(ierr);
7852     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
7853     if (isDepth) continue;
7854     ierr = DMCreateLabel(rdm, lname);CHKERRQ(ierr);
7855     ierr = DMGetLabel(dm, lname, &label);CHKERRQ(ierr);
7856     ierr = DMGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
7857     ierr = DMLabelGetDefaultValue(label,&defVal);CHKERRQ(ierr);
7858     ierr = DMLabelSetDefaultValue(labelNew,defVal);CHKERRQ(ierr);
7859     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
7860     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
7861     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
7862     for (val = 0; val < numValues; ++val) {
7863       IS              pointIS;
7864       const PetscInt *points;
7865       PetscInt        numPoints, n;
7866 
7867       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
7868       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
7869       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
7870       /* Ensure refined label is created with same number of strata as
7871        * original (even if no entries here). */
7872       ierr = DMLabelAddStratum(labelNew, values[val]);CHKERRQ(ierr);
7873       for (n = 0; n < numPoints; ++n) {
7874         const PetscInt p = points[n];
7875         switch (refiner) {
7876         case REFINER_SIMPLEX_1D:
7877           if ((p >= vStart) && (p < vEnd)) {
7878             /* Old vertices stay the same */
7879             newp = vStartNew + (p - vStart);
7880             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7881           } else if ((p >= cStart) && (p < cEnd)) {
7882             /* Old cells add new cells and vertex */
7883             newp = vStartNew + (vEnd - vStart) + (p - cStart);
7884             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7885             for (r = 0; r < 2; ++r) {
7886               newp = cStartNew + (p - cStart)*2 + r;
7887               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7888             }
7889           }
7890           break;
7891         case REFINER_SIMPLEX_2D:
7892           if ((p >= vStart) && (p < vEnd)) {
7893             /* Old vertices stay the same */
7894             newp = vStartNew + (p - vStart);
7895             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7896           } else if ((p >= fStart) && (p < fEnd)) {
7897             /* Old faces add new faces and vertex */
7898             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7899             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7900             for (r = 0; r < 2; ++r) {
7901               newp = fStartNew + (p - fStart)*2 + r;
7902               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7903             }
7904           } else if ((p >= cStart) && (p < cEnd)) {
7905             /* Old cells add new cells and interior faces */
7906             for (r = 0; r < 4; ++r) {
7907               newp = cStartNew + (p - cStart)*4 + r;
7908               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7909             }
7910             for (r = 0; r < 3; ++r) {
7911               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7912               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7913             }
7914           }
7915           break;
7916         case REFINER_SIMPLEX_TO_HEX_2D:
7917           if ((p >= vStart) && (p < vEnd)) {
7918             /* Old vertices stay the same */
7919             newp = vStartNew + (p - vStart);
7920             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7921           } else if ((p >= fStart) && (p < fEnd)) {
7922             /* Old faces add new faces and vertex */
7923             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7924             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7925             for (r = 0; r < 2; ++r) {
7926               newp = fStartNew + (p - fStart)*2 + r;
7927               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7928             }
7929           } else if ((p >= cStart) && (p < cEnd)) {
7930             /* Old cells add new cells, interior faces, and a vertex */
7931             for (r = 0; r < 3; ++r) {
7932               newp = cStartNew + (p - cStart)*3 + r;
7933               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7934             }
7935             for (r = 0; r < 3; ++r) {
7936               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7937               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7938             }
7939             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + p;
7940             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7941           }
7942           break;
7943         case REFINER_HEX_2D:
7944           if ((p >= vStart) && (p < vEnd)) {
7945             /* Old vertices stay the same */
7946             newp = vStartNew + (p - vStart);
7947             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7948           } else if ((p >= fStart) && (p < fEnd)) {
7949             /* Old faces add new faces and vertex */
7950             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7951             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7952             for (r = 0; r < 2; ++r) {
7953               newp = fStartNew + (p - fStart)*2 + r;
7954               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7955             }
7956           } else if ((p >= cStart) && (p < cEnd)) {
7957             /* Old cells add new cells and interior faces and vertex */
7958             for (r = 0; r < 4; ++r) {
7959               newp = cStartNew + (p - cStart)*4 + r;
7960               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7961             }
7962             for (r = 0; r < 4; ++r) {
7963               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
7964               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7965             }
7966             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
7967             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7968           }
7969           break;
7970         case REFINER_HYBRID_SIMPLEX_2D:
7971           if ((p >= vStart) && (p < vEnd)) {
7972             /* Old vertices stay the same */
7973             newp = vStartNew + (p - vStart);
7974             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7975           } else if ((p >= fStart) && (p < fMax)) {
7976             /* Old interior faces add new faces and vertex */
7977             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7978             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7979             for (r = 0; r < 2; ++r) {
7980               newp = fStartNew + (p - fStart)*2 + r;
7981               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7982             }
7983           } else if ((p >= fMax) && (p < fEnd)) {
7984             /* Old hybrid faces stay the same */
7985             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7986             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7987           } else if ((p >= cStart) && (p < cMax)) {
7988             /* Old interior cells add new cells and interior faces */
7989             for (r = 0; r < 4; ++r) {
7990               newp = cStartNew + (p - cStart)*4 + r;
7991               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7992             }
7993             for (r = 0; r < 3; ++r) {
7994               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7995               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7996             }
7997           } else if ((p >= cMax) && (p < cEnd)) {
7998             /* Old hybrid cells add new cells and hybrid face */
7999             for (r = 0; r < 2; ++r) {
8000               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
8001               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8002             }
8003             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
8004             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8005           }
8006           break;
8007         case REFINER_HYBRID_HEX_2D:
8008           if ((p >= vStart) && (p < vEnd)) {
8009             /* Old vertices stay the same */
8010             newp = vStartNew + (p - vStart);
8011             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8012           } else if ((p >= fStart) && (p < fMax)) {
8013             /* Old interior faces add new faces and vertex */
8014             newp = vStartNew + (vEnd - vStart) + (p - fStart);
8015             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8016             for (r = 0; r < 2; ++r) {
8017               newp = fStartNew + (p - fStart)*2 + r;
8018               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8019             }
8020           } else if ((p >= fMax) && (p < fEnd)) {
8021             /* Old hybrid faces stay the same */
8022             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
8023             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8024           } else if ((p >= cStart) && (p < cMax)) {
8025             /* Old interior cells add new cells, interior faces, and vertex */
8026             for (r = 0; r < 4; ++r) {
8027               newp = cStartNew + (p - cStart)*4 + r;
8028               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8029             }
8030             for (r = 0; r < 4; ++r) {
8031               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
8032               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8033             }
8034             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
8035             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8036           } else if ((p >= cMax) && (p < cEnd)) {
8037             /* Old hybrid cells add new cells and hybrid face */
8038             for (r = 0; r < 2; ++r) {
8039               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
8040               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8041             }
8042             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (p - cMax);
8043             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8044           }
8045           break;
8046         case REFINER_SIMPLEX_3D:
8047           if ((p >= vStart) && (p < vEnd)) {
8048             /* Old vertices stay the same */
8049             newp = vStartNew + (p - vStart);
8050             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8051           } else if ((p >= eStart) && (p < eEnd)) {
8052             /* Old edges add new edges and vertex */
8053             for (r = 0; r < 2; ++r) {
8054               newp = eStartNew + (p - eStart)*2 + r;
8055               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8056             }
8057             newp = vStartNew + (vEnd - vStart) + (p - eStart);
8058             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8059           } else if ((p >= fStart) && (p < fEnd)) {
8060             /* Old faces add new faces and edges */
8061             for (r = 0; r < 4; ++r) {
8062               newp = fStartNew + (p - fStart)*4 + r;
8063               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8064             }
8065             for (r = 0; r < 3; ++r) {
8066               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
8067               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8068             }
8069           } else if ((p >= cStart) && (p < cEnd)) {
8070             /* Old cells add new cells and interior faces and edges */
8071             for (r = 0; r < 8; ++r) {
8072               newp = cStartNew + (p - cStart)*8 + r;
8073               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8074             }
8075             for (r = 0; r < 8; ++r) {
8076               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*8 + r;
8077               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8078             }
8079             for (r = 0; r < 1; ++r) {
8080               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*1 + r;
8081               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8082             }
8083           }
8084           break;
8085         case REFINER_SIMPLEX_TO_HEX_3D:
8086           if ((p >= vStart) && (p < vEnd)) {
8087             /* Old vertices stay the same */
8088             newp = vStartNew + (p - vStart);
8089             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8090           } else if ((p >= eStart) && (p < eEnd)) {
8091             /* Old edges add new edges and vertex */
8092             for (r = 0; r < 2; ++r) {
8093               newp = eStartNew + (p - eStart)*2 + r;
8094               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8095             }
8096             newp = vStartNew + (vEnd - vStart) + (p - eStart);
8097             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8098           } else if ((p >= fStart) && (p < fEnd)) {
8099             /* Old faces add new faces, edges and a vertex */
8100             for (r = 0; r < 3; ++r) {
8101               newp = fStartNew + (p - fStart)*3 + r;
8102               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8103             }
8104             for (r = 0; r < 3; ++r) {
8105               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
8106               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8107             }
8108           } else if ((p >= cStart) && (p < cEnd)) {
8109             /* Old cells add new cells and interior faces and edges and a vertex */
8110             for (r = 0; r < 4; ++r) {
8111               newp = cStartNew + (p - cStart)*4 + r;
8112               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8113             }
8114             for (r = 0; r < 6; ++r) {
8115               newp = fStartNew + (fEnd - fStart)*3 + (p - cStart)*6 + r;
8116               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8117             }
8118             for (r = 0; r < 4; ++r) {
8119               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*4 + r;
8120               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8121             }
8122             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + p - cStart;
8123             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8124           }
8125           break;
8126         case REFINER_HYBRID_SIMPLEX_3D:
8127           if ((p >= vStart) && (p < vEnd)) {
8128             /* Interior vertices stay the same */
8129             newp = vStartNew + (p - vStart);
8130             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8131           } else if ((p >= eStart) && (p < eMax)) {
8132             /* Interior edges add new edges and vertex */
8133             for (r = 0; r < 2; ++r) {
8134               newp = eStartNew + (p - eStart)*2 + r;
8135               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8136             }
8137             newp = vStartNew + (vEnd - vStart) + (p - eStart);
8138             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8139           } else if ((p >= eMax) && (p < eEnd)) {
8140             /* Hybrid edges stay the same */
8141             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - eMax);
8142             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8143           } else if ((p >= fStart) && (p < fMax)) {
8144             /* Interior faces add new faces and edges */
8145             for (r = 0; r < 4; ++r) {
8146               newp = fStartNew + (p - fStart)*4 + r;
8147               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8148             }
8149             for (r = 0; r < 3; ++r) {
8150               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
8151               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8152             }
8153           } else if ((p >= fMax) && (p < fEnd)) {
8154             /* Hybrid faces add new faces and edges */
8155             for (r = 0; r < 2; ++r) {
8156               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (p - fMax)*2 + r;
8157               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8158             }
8159             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - fMax);
8160             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8161           } else if ((p >= cStart) && (p < cMax)) {
8162             /* Interior cells add new cells, faces, and edges */
8163             for (r = 0; r < 8; ++r) {
8164               newp = cStartNew + (p - cStart)*8 + r;
8165               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8166             }
8167             for (r = 0; r < 8; ++r) {
8168               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*8 + r;
8169               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8170             }
8171             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart);
8172             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8173           } else if ((p >= cMax) && (p < cEnd)) {
8174             /* Hybrid cells add new cells and faces */
8175             for (r = 0; r < 4; ++r) {
8176               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
8177               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8178             }
8179             for (r = 0; r < 3; ++r) {
8180               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
8181               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8182             }
8183           }
8184           break;
8185         case REFINER_HEX_3D:
8186           if ((p >= vStart) && (p < vEnd)) {
8187             /* Old vertices stay the same */
8188             newp = vStartNew + (p - vStart);
8189             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8190           } else if ((p >= eStart) && (p < eEnd)) {
8191             /* Old edges add new edges and vertex */
8192             for (r = 0; r < 2; ++r) {
8193               newp = eStartNew + (p - eStart)*2 + r;
8194               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8195             }
8196             newp = vStartNew + (vEnd - vStart) + (p - eStart);
8197             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8198           } else if ((p >= fStart) && (p < fEnd)) {
8199             /* Old faces add new faces, edges, and vertex */
8200             for (r = 0; r < 4; ++r) {
8201               newp = fStartNew + (p - fStart)*4 + r;
8202               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8203             }
8204             for (r = 0; r < 4; ++r) {
8205               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*4 + r;
8206               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8207             }
8208             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (p - fStart);
8209             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8210           } else if ((p >= cStart) && (p < cEnd)) {
8211             /* Old cells add new cells, faces, edges, and vertex */
8212             for (r = 0; r < 8; ++r) {
8213               newp = cStartNew + (p - cStart)*8 + r;
8214               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8215             }
8216             for (r = 0; r < 12; ++r) {
8217               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*12 + r;
8218               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8219             }
8220             for (r = 0; r < 6; ++r) {
8221               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (p - cStart)*6 + r;
8222               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8223             }
8224             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (p - cStart);
8225             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8226           }
8227           break;
8228         case REFINER_HYBRID_HEX_3D:
8229           if ((p >= vStart) && (p < vEnd)) {
8230             /* Interior vertices stay the same */
8231             newp = vStartNew + (p - vStart);
8232             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8233           } else if ((p >= eStart) && (p < eMax)) {
8234             /* Interior edges add new edges and vertex */
8235             for (r = 0; r < 2; ++r) {
8236               newp = eStartNew + (p - eStart)*2 + r;
8237               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8238             }
8239             newp = vStartNew + (vEnd - vStart) + (p - eStart);
8240             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8241           } else if ((p >= eMax) && (p < eEnd)) {
8242             /* Hybrid edges stay the same */
8243             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - eMax);
8244             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8245           } else if ((p >= fStart) && (p < fMax)) {
8246             /* Interior faces add new faces, edges, and vertex */
8247             for (r = 0; r < 4; ++r) {
8248               newp = fStartNew + (p - fStart)*4 + r;
8249               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8250             }
8251             for (r = 0; r < 4; ++r) {
8252               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*4 + r;
8253               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8254             }
8255             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (p - fStart);
8256             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8257           } else if ((p >= fMax) && (p < fEnd)) {
8258             /* Hybrid faces add new faces and edges */
8259             for (r = 0; r < 2; ++r) {
8260               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (p - fMax)*2 + r;
8261               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8262             }
8263             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - fMax);
8264             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8265           } else if ((p >= cStart) && (p < cMax)) {
8266             /* Interior cells add new cells, faces, edges, and vertex */
8267             for (r = 0; r < 8; ++r) {
8268               newp = cStartNew + (p - cStart)*8 + r;
8269               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8270             }
8271             for (r = 0; r < 12; ++r) {
8272               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*12 + r;
8273               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8274             }
8275             for (r = 0; r < 6; ++r) {
8276               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (p - cStart)*6 + r;
8277               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8278             }
8279             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (p - cStart);
8280             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8281           } else if ((p >= cMax) && (p < cEnd)) {
8282             /* Hybrid cells add new cells, faces, and edges */
8283             for (r = 0; r < 4; ++r) {
8284               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
8285               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8286             }
8287             for (r = 0; r < 4; ++r) {
8288               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (p - cMax)*4 + r;
8289               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8290             }
8291             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (fEnd - fMax) + (p - cMax);
8292             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8293           }
8294           break;
8295         default:
8296           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
8297         }
8298       }
8299       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
8300       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
8301     }
8302     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
8303     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
8304     if (0) {
8305       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
8306     }
8307   }
8308   PetscFunctionReturn(0);
8309 }
8310 
8311 /* This will only work for interpolated meshes */
8312 PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
8313 {
8314   DM             rdm;
8315   PetscInt      *depthSize;
8316   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
8317   PetscErrorCode ierr;
8318 
8319   PetscFunctionBegin;
8320   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
8321   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
8322   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
8323   ierr = DMSetDimension(rdm, dim);CHKERRQ(ierr);
8324   /* Calculate number of new points of each depth */
8325   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
8326   if (depth >= 0 && dim != depth) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Mesh must be interpolated for regular refinement");
8327   ierr = PetscMalloc1(depth+1, &depthSize);CHKERRQ(ierr);
8328   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
8329   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
8330   /* Step 1: Set chart */
8331   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
8332   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
8333   /* Step 2: Set cone/support sizes (automatically stratifies) */
8334   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
8335   /* Step 3: Setup refined DM */
8336   ierr = DMSetUp(rdm);CHKERRQ(ierr);
8337   /* Step 4: Set cones and supports (automatically symmetrizes) */
8338   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
8339   /* Step 5: Create pointSF */
8340   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
8341   /* Step 6: Create labels */
8342   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
8343   /* Step 7: Set coordinates */
8344   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
8345   ierr = PetscFree(depthSize);CHKERRQ(ierr);
8346 
8347   *dmRefined = rdm;
8348   PetscFunctionReturn(0);
8349 }
8350 
8351 /*@
8352   DMPlexCreateCoarsePointIS - Creates an IS covering the coarse DM chart with the fine points as data
8353 
8354   Input Parameter:
8355 . dm - The coarse DM
8356 
8357   Output Parameter:
8358 . fpointIS - The IS of all the fine points which exist in the original coarse mesh
8359 
8360   Level: developer
8361 
8362 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexCreateSubpointIS()
8363 @*/
8364 PetscErrorCode DMPlexCreateCoarsePointIS(DM dm, IS *fpointIS)
8365 {
8366   CellRefiner    cellRefiner;
8367   PetscInt      *depthSize, *fpoints;
8368   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
8369   PetscInt       depth, pStart, pEnd, p, vStart, vEnd, v;
8370   PetscErrorCode ierr;
8371 
8372   PetscFunctionBegin;
8373   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
8374   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
8375   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8376   ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr);
8377   ierr = PetscMalloc1(depth+1, &depthSize);CHKERRQ(ierr);
8378   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
8379   if (cellRefiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
8380   ierr = PetscMalloc1(pEnd-pStart,&fpoints);CHKERRQ(ierr);
8381   for (p = 0; p < pEnd-pStart; ++p) fpoints[p] = -1;
8382   switch (cellRefiner) {
8383   case REFINER_SIMPLEX_1D:
8384   case REFINER_SIMPLEX_2D:
8385   case REFINER_HYBRID_SIMPLEX_2D:
8386   case REFINER_HEX_2D:
8387   case REFINER_HYBRID_HEX_2D:
8388   case REFINER_SIMPLEX_3D:
8389   case REFINER_HYBRID_SIMPLEX_3D:
8390   case REFINER_HEX_3D:
8391   case REFINER_HYBRID_HEX_3D:
8392     for (v = vStart; v < vEnd; ++v) fpoints[v-pStart] = vStartNew + (v - vStart);
8393     break;
8394   default:
8395     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", cellRefiner);
8396   }
8397   ierr = ISCreateGeneral(PETSC_COMM_SELF, pEnd-pStart, fpoints, PETSC_OWN_POINTER, fpointIS);CHKERRQ(ierr);
8398   ierr = PetscFree(depthSize);CHKERRQ(ierr);
8399   PetscFunctionReturn(0);
8400 }
8401 
8402 /*@
8403   DMPlexSetRefinementUniform - Set the flag for uniform refinement
8404 
8405   Input Parameters:
8406 + dm - The DM
8407 - refinementUniform - The flag for uniform refinement
8408 
8409   Level: developer
8410 
8411 .seealso: DMRefine(), DMPlexGetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
8412 @*/
8413 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
8414 {
8415   DM_Plex *mesh = (DM_Plex*) dm->data;
8416 
8417   PetscFunctionBegin;
8418   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8419   mesh->refinementUniform = refinementUniform;
8420   PetscFunctionReturn(0);
8421 }
8422 
8423 /*@
8424   DMPlexGetRefinementUniform - Retrieve the flag for uniform refinement
8425 
8426   Input Parameter:
8427 . dm - The DM
8428 
8429   Output Parameter:
8430 . refinementUniform - The flag for uniform refinement
8431 
8432   Level: developer
8433 
8434 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
8435 @*/
8436 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
8437 {
8438   DM_Plex *mesh = (DM_Plex*) dm->data;
8439 
8440   PetscFunctionBegin;
8441   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8442   PetscValidPointer(refinementUniform,  2);
8443   *refinementUniform = mesh->refinementUniform;
8444   PetscFunctionReturn(0);
8445 }
8446 
8447 /*@
8448   DMPlexSetRefinementLimit - Set the maximum cell volume for refinement
8449 
8450   Input Parameters:
8451 + dm - The DM
8452 - refinementLimit - The maximum cell volume in the refined mesh
8453 
8454   Level: developer
8455 
8456 .seealso: DMRefine(), DMPlexGetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
8457 @*/
8458 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
8459 {
8460   DM_Plex *mesh = (DM_Plex*) dm->data;
8461 
8462   PetscFunctionBegin;
8463   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8464   mesh->refinementLimit = refinementLimit;
8465   PetscFunctionReturn(0);
8466 }
8467 
8468 /*@
8469   DMPlexGetRefinementLimit - Retrieve the maximum cell volume for refinement
8470 
8471   Input Parameter:
8472 . dm - The DM
8473 
8474   Output Parameter:
8475 . refinementLimit - The maximum cell volume in the refined mesh
8476 
8477   Level: developer
8478 
8479 .seealso: DMRefine(), DMPlexSetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
8480 @*/
8481 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
8482 {
8483   DM_Plex *mesh = (DM_Plex*) dm->data;
8484 
8485   PetscFunctionBegin;
8486   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8487   PetscValidPointer(refinementLimit,  2);
8488   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
8489   *refinementLimit = mesh->refinementLimit;
8490   PetscFunctionReturn(0);
8491 }
8492 
8493 /*@
8494   DMPlexSetRefinementFunction - Set the function giving the maximum cell volume for refinement
8495 
8496   Input Parameters:
8497 + dm - The DM
8498 - refinementFunc - Function giving the maximum cell volume in the refined mesh
8499 
8500   Note: The calling sequence is refinementFunc(coords, limit)
8501 $ coords - Coordinates of the current point, usually a cell centroid
8502 $ limit  - The maximum cell volume for a cell containing this point
8503 
8504   Level: developer
8505 
8506 .seealso: DMRefine(), DMPlexGetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
8507 @*/
8508 PetscErrorCode DMPlexSetRefinementFunction(DM dm, PetscErrorCode (*refinementFunc)(const PetscReal [], PetscReal *))
8509 {
8510   DM_Plex *mesh = (DM_Plex*) dm->data;
8511 
8512   PetscFunctionBegin;
8513   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8514   mesh->refinementFunc = refinementFunc;
8515   PetscFunctionReturn(0);
8516 }
8517 
8518 /*@
8519   DMPlexGetRefinementFunction - Get the function giving the maximum cell volume for refinement
8520 
8521   Input Parameter:
8522 . dm - The DM
8523 
8524   Output Parameter:
8525 . refinementFunc - Function giving the maximum cell volume in the refined mesh
8526 
8527   Note: The calling sequence is refinementFunc(coords, limit)
8528 $ coords - Coordinates of the current point, usually a cell centroid
8529 $ limit  - The maximum cell volume for a cell containing this point
8530 
8531   Level: developer
8532 
8533 .seealso: DMRefine(), DMPlexSetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
8534 @*/
8535 PetscErrorCode DMPlexGetRefinementFunction(DM dm, PetscErrorCode (**refinementFunc)(const PetscReal [], PetscReal *))
8536 {
8537   DM_Plex *mesh = (DM_Plex*) dm->data;
8538 
8539   PetscFunctionBegin;
8540   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8541   PetscValidPointer(refinementFunc,  2);
8542   *refinementFunc = mesh->refinementFunc;
8543   PetscFunctionReturn(0);
8544 }
8545 
8546 PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
8547 {
8548   PetscInt       dim, cStart, cEnd, coneSize, cMax, fMax;
8549   PetscErrorCode ierr;
8550 
8551   PetscFunctionBegin;
8552   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
8553   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8554   if (cEnd <= cStart) {*cellRefiner = REFINER_NOOP; PetscFunctionReturn(0);}
8555   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
8556   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, NULL, NULL);CHKERRQ(ierr);
8557   switch (dim) {
8558   case 1:
8559     switch (coneSize) {
8560     case 2:
8561       *cellRefiner = REFINER_SIMPLEX_1D;
8562       break;
8563     default:
8564       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
8565     }
8566     break;
8567   case 2:
8568     switch (coneSize) {
8569     case 3:
8570       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_2D;
8571       else *cellRefiner = REFINER_SIMPLEX_2D;
8572       break;
8573     case 4:
8574       if (cMax >= 0 && fMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_2D;
8575       else *cellRefiner = REFINER_HEX_2D;
8576       break;
8577     default:
8578       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
8579     }
8580     break;
8581   case 3:
8582     switch (coneSize) {
8583     case 4:
8584       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_3D;
8585       else *cellRefiner = REFINER_SIMPLEX_3D;
8586       break;
8587     case 6:
8588       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_3D;
8589       else *cellRefiner = REFINER_HEX_3D;
8590       break;
8591     default:
8592       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
8593     }
8594     break;
8595   default:
8596     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
8597   }
8598   PetscFunctionReturn(0);
8599 }
8600 
8601 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
8602 {
8603   PetscBool      isUniform;
8604   PetscErrorCode ierr;
8605 
8606   PetscFunctionBegin;
8607   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
8608   if (isUniform) {
8609     CellRefiner cellRefiner;
8610     PetscBool   localized;
8611 
8612     ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
8613     ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr);
8614     ierr = DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
8615     ierr = DMCopyBoundary(dm, *dmRefined);CHKERRQ(ierr);
8616     if (localized) {ierr = DMLocalizeCoordinates(*dmRefined);CHKERRQ(ierr);}
8617   } else {
8618     ierr = DMPlexRefine_Internal(dm, NULL, dmRefined);CHKERRQ(ierr);
8619   }
8620   PetscFunctionReturn(0);
8621 }
8622 
8623 PetscErrorCode DMRefineHierarchy_Plex(DM dm, PetscInt nlevels, DM dmRefined[])
8624 {
8625   DM             cdm = dm;
8626   PetscInt       r;
8627   PetscBool      isUniform, localized;
8628   PetscErrorCode ierr;
8629 
8630   PetscFunctionBegin;
8631   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
8632   ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
8633   if (isUniform) {
8634     for (r = 0; r < nlevels; ++r) {
8635       CellRefiner cellRefiner;
8636 
8637       ierr = DMPlexGetCellRefiner_Internal(cdm, &cellRefiner);CHKERRQ(ierr);
8638       ierr = DMPlexRefineUniform_Internal(cdm, cellRefiner, &dmRefined[r]);CHKERRQ(ierr);
8639       ierr = DMCopyBoundary(cdm, dmRefined[r]);CHKERRQ(ierr);
8640       if (localized) {ierr = DMLocalizeCoordinates(dmRefined[r]);CHKERRQ(ierr);}
8641       ierr = DMSetCoarseDM(dmRefined[r], cdm);CHKERRQ(ierr);
8642       ierr = DMPlexSetRegularRefinement(dmRefined[r], PETSC_TRUE);CHKERRQ(ierr);
8643       cdm  = dmRefined[r];
8644     }
8645   } else {
8646     for (r = 0; r < nlevels; ++r) {
8647       ierr = DMRefine(cdm, PetscObjectComm((PetscObject) dm), &dmRefined[r]);CHKERRQ(ierr);
8648       ierr = DMCopyBoundary(cdm, dmRefined[r]);CHKERRQ(ierr);
8649       if (localized) {ierr = DMLocalizeCoordinates(dmRefined[r]);CHKERRQ(ierr);}
8650       ierr = DMSetCoarseDM(dmRefined[r], cdm);CHKERRQ(ierr);
8651       cdm  = dmRefined[r];
8652     }
8653   }
8654   PetscFunctionReturn(0);
8655 }
8656