xref: /petsc/src/dm/impls/plex/plexrefine.c (revision 9f4d3c52fa2fe0bb72fec4f4e85d8e495867af35)
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 CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
376 {
377   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, e, r;
378   PetscErrorCode ierr;
379 
380   PetscFunctionBegin;
381   if (!refiner) PetscFunctionReturn(0);
382   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
383   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
384   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
385   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
386   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
387   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
388   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
389   switch (refiner) {
390   case REFINER_SIMPLEX_1D:
391     /* All cells have 2 vertices */
392     for (c = cStart; c < cEnd; ++c) {
393       for (r = 0; r < 2; ++r) {
394         const PetscInt newp = cStartNew + (c - cStart)*2 + r;
395 
396         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
397       }
398     }
399     /* Old vertices have identical supports */
400     for (v = vStart; v < vEnd; ++v) {
401       const PetscInt newp = vStartNew + (v - vStart);
402       PetscInt       size;
403 
404       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
405       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
406     }
407     /* Cell vertices have support 2 */
408     for (c = cStart; c < cEnd; ++c) {
409       const PetscInt newp = vStartNew + (vEnd - vStart) + (c - cStart);
410 
411       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
412     }
413     break;
414   case REFINER_SIMPLEX_2D:
415     /* All cells have 3 faces */
416     for (c = cStart; c < cEnd; ++c) {
417       for (r = 0; r < 4; ++r) {
418         const PetscInt newp = (c - cStart)*4 + r;
419 
420         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
421       }
422     }
423     /* Split faces have 2 vertices and the same cells as the parent */
424     for (f = fStart; f < fEnd; ++f) {
425       for (r = 0; r < 2; ++r) {
426         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
427         PetscInt       size;
428 
429         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
430         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
431         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
432       }
433     }
434     /* Interior faces have 2 vertices and 2 cells */
435     for (c = cStart; c < cEnd; ++c) {
436       for (r = 0; r < 3; ++r) {
437         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
438 
439         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
440         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
441       }
442     }
443     /* Old vertices have identical supports */
444     for (v = vStart; v < vEnd; ++v) {
445       const PetscInt newp = vStartNew + (v - vStart);
446       PetscInt       size;
447 
448       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
449       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
450     }
451     /* Face vertices have 2 + cells*2 supports */
452     for (f = fStart; f < fEnd; ++f) {
453       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
454       PetscInt       size;
455 
456       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
457       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
458     }
459     break;
460   case REFINER_SIMPLEX_TO_HEX_2D:
461     /* All cells have 4 faces */
462     for (c = cStart; c < cEnd; ++c) {
463       for (r = 0; r < 3; ++r) {
464         const PetscInt newp = (c - cStart)*3 + r;
465 
466         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
467       }
468     }
469     /* Split faces have 2 vertices and the same cells as the parent */
470     for (f = fStart; f < fEnd; ++f) {
471       for (r = 0; r < 2; ++r) {
472         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
473         PetscInt       size;
474 
475         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
476         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
477         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
478       }
479     }
480     /* Interior faces have 2 vertices and 2 cells */
481     for (c = cStart; c < cEnd; ++c) {
482       for (r = 0; r < 3; ++r) {
483         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
484 
485         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
486         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
487       }
488     }
489     /* Old vertices have identical supports */
490     for (v = vStart; v < vEnd; ++v) {
491       const PetscInt newp = vStartNew + (v - vStart);
492       PetscInt       size;
493 
494       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
495       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
496     }
497     /* Split-face vertices have cells + 2 supports */
498     for (f = fStart; f < fEnd; ++f) {
499       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
500       PetscInt       size;
501 
502       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
503       ierr = DMPlexSetSupportSize(rdm, newp, size + 2);CHKERRQ(ierr);
504     }
505     /* Interior vertices have 3 supports */
506     for (c = cStart; c < cEnd; ++c) {
507       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
508 
509       ierr = DMPlexSetSupportSize(rdm, newp, 3);CHKERRQ(ierr);
510     }
511     break;
512   case REFINER_HEX_2D:
513     /* All cells have 4 faces */
514     for (c = cStart; c < cEnd; ++c) {
515       for (r = 0; r < 4; ++r) {
516         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
517 
518         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
519       }
520     }
521     /* Split faces have 2 vertices and the same cells as the parent */
522     for (f = fStart; f < fEnd; ++f) {
523       for (r = 0; r < 2; ++r) {
524         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
525         PetscInt       size;
526 
527         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
528         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
529         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
530       }
531     }
532     /* Interior faces have 2 vertices and 2 cells */
533     for (c = cStart; c < cEnd; ++c) {
534       for (r = 0; r < 4; ++r) {
535         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
536 
537         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
538         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
539       }
540     }
541     /* Old vertices have identical supports */
542     for (v = vStart; v < vEnd; ++v) {
543       const PetscInt newp = vStartNew + (v - vStart);
544       PetscInt       size;
545 
546       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
547       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
548     }
549     /* Face vertices have 2 + cells supports */
550     for (f = fStart; f < fEnd; ++f) {
551       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
552       PetscInt       size;
553 
554       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
555       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
556     }
557     /* Cell vertices have 4 supports */
558     for (c = cStart; c < cEnd; ++c) {
559       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
560 
561       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
562     }
563     break;
564   case REFINER_HYBRID_SIMPLEX_2D:
565     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
566     cMax = PetscMin(cEnd, cMax);
567     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
568     fMax = PetscMin(fEnd, fMax);
569     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
570     /* Interior cells have 3 faces */
571     for (c = cStart; c < cMax; ++c) {
572       for (r = 0; r < 4; ++r) {
573         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
574 
575         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
576       }
577     }
578     /* Hybrid cells have 4 faces */
579     for (c = cMax; c < cEnd; ++c) {
580       for (r = 0; r < 2; ++r) {
581         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
582 
583         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
584       }
585     }
586     /* Interior split faces have 2 vertices and the same cells as the parent */
587     for (f = fStart; f < fMax; ++f) {
588       for (r = 0; r < 2; ++r) {
589         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
590         PetscInt       size;
591 
592         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
593         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
594         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
595       }
596     }
597     /* Interior cell faces have 2 vertices and 2 cells */
598     for (c = cStart; c < cMax; ++c) {
599       for (r = 0; r < 3; ++r) {
600         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
601 
602         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
603         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
604       }
605     }
606     /* Hybrid faces have 2 vertices and the same cells */
607     for (f = fMax; f < fEnd; ++f) {
608       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
609       PetscInt       size;
610 
611       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
612       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
613       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
614     }
615     /* Hybrid cell faces have 2 vertices and 2 cells */
616     for (c = cMax; c < cEnd; ++c) {
617       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
618 
619       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
620       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
621     }
622     /* Old vertices have identical supports */
623     for (v = vStart; v < vEnd; ++v) {
624       const PetscInt newp = vStartNew + (v - vStart);
625       PetscInt       size;
626 
627       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
628       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
629     }
630     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
631     for (f = fStart; f < fMax; ++f) {
632       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
633       const PetscInt *support;
634       PetscInt       size, newSize = 2, s;
635 
636       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
637       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
638       for (s = 0; s < size; ++s) {
639         if (support[s] >= cMax) newSize += 1;
640         else newSize += 2;
641       }
642       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
643     }
644     break;
645   case REFINER_HYBRID_HEX_2D:
646     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
647     cMax = PetscMin(cEnd, cMax);
648     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
649     fMax = PetscMin(fEnd, fMax);
650     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
651     /* Interior cells have 4 faces */
652     for (c = cStart; c < cMax; ++c) {
653       for (r = 0; r < 4; ++r) {
654         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
655 
656         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
657       }
658     }
659     /* Hybrid cells have 4 faces */
660     for (c = cMax; c < cEnd; ++c) {
661       for (r = 0; r < 2; ++r) {
662         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
663 
664         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
665       }
666     }
667     /* Interior split faces have 2 vertices and the same cells as the parent */
668     for (f = fStart; f < fMax; ++f) {
669       for (r = 0; r < 2; ++r) {
670         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
671         PetscInt       size;
672 
673         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
674         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
675         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
676       }
677     }
678     /* Interior cell faces have 2 vertices and 2 cells */
679     for (c = cStart; c < cMax; ++c) {
680       for (r = 0; r < 4; ++r) {
681         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
682 
683         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
684         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
685       }
686     }
687     /* Hybrid faces have 2 vertices and the same cells */
688     for (f = fMax; f < fEnd; ++f) {
689       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
690       PetscInt       size;
691 
692       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
693       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
694       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
695     }
696     /* Hybrid cell faces have 2 vertices and 2 cells */
697     for (c = cMax; c < cEnd; ++c) {
698       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
699 
700       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
701       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
702     }
703     /* Old vertices have identical supports */
704     for (v = vStart; v < vEnd; ++v) {
705       const PetscInt newp = vStartNew + (v - vStart);
706       PetscInt       size;
707 
708       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
709       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
710     }
711     /* Face vertices have 2 + cells supports */
712     for (f = fStart; f < fMax; ++f) {
713       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
714       PetscInt       size;
715 
716       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
717       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
718     }
719     /* Cell vertices have 4 supports */
720     for (c = cStart; c < cMax; ++c) {
721       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
722 
723       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
724     }
725     break;
726   case REFINER_SIMPLEX_3D:
727     /* All cells have 4 faces */
728     for (c = cStart; c < cEnd; ++c) {
729       for (r = 0; r < 8; ++r) {
730         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
731 
732         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
733       }
734     }
735     /* Split faces have 3 edges and the same cells as the parent */
736     for (f = fStart; f < fEnd; ++f) {
737       for (r = 0; r < 4; ++r) {
738         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
739         PetscInt       size;
740 
741         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
742         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
743         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
744       }
745     }
746     /* Interior cell faces have 3 edges and 2 cells */
747     for (c = cStart; c < cEnd; ++c) {
748       for (r = 0; r < 8; ++r) {
749         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + r;
750 
751         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
752         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
753       }
754     }
755     /* Split edges have 2 vertices and the same faces */
756     for (e = eStart; e < eEnd; ++e) {
757       for (r = 0; r < 2; ++r) {
758         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
759         PetscInt       size;
760 
761         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
762         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
763         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
764       }
765     }
766     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
767     for (f = fStart; f < fEnd; ++f) {
768       for (r = 0; r < 3; ++r) {
769         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
770         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
771         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;
772 
773         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
774         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
775         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
776         for (s = 0; s < supportSize; ++s) {
777           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
778           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
779           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
780           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
781           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
782           er = GetTriMidEdgeInverse_Static(ornt[c], r);
783           if (er == eint[c]) {
784             intFaces += 1;
785           } else {
786             intFaces += 2;
787           }
788         }
789         ierr = DMPlexSetSupportSize(rdm, newp, 2+intFaces);CHKERRQ(ierr);
790       }
791     }
792     /* Interior cell edges have 2 vertices and 4 faces */
793     for (c = cStart; c < cEnd; ++c) {
794       const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
795 
796       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
797       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
798     }
799     /* Old vertices have identical supports */
800     for (v = vStart; v < vEnd; ++v) {
801       const PetscInt newp = vStartNew + (v - vStart);
802       PetscInt       size;
803 
804       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
805       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
806     }
807     /* Edge vertices have 2 + faces*2 + cells*0/1 supports */
808     for (e = eStart; e < eEnd; ++e) {
809       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
810       PetscInt       size, *star = NULL, starSize, s, cellSize = 0;
811 
812       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
813       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
814       for (s = 0; s < starSize*2; s += 2) {
815         const PetscInt *cone, *ornt;
816         PetscInt        e01, e23;
817 
818         if ((star[s] >= cStart) && (star[s] < cEnd)) {
819           /* Check edge 0-1 */
820           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
821           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
822           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
823           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
824           /* Check edge 2-3 */
825           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
826           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
827           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
828           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
829           if ((e01 == e) || (e23 == e)) ++cellSize;
830         }
831       }
832       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
833       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2 + cellSize);CHKERRQ(ierr);
834     }
835     break;
836   case REFINER_HYBRID_SIMPLEX_3D:
837     ierr = DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 8*(cMax - cStart),
838                                  eStartNew + 2*(eMax - eStart) + 3*(fMax - fStart) + (cMax - cStart), PETSC_DETERMINE);CHKERRQ(ierr);
839     /* Interior cells have 4 faces */
840     for (c = cStart; c < cMax; ++c) {
841       for (r = 0; r < 8; ++r) {
842         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
843 
844         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
845       }
846     }
847     /* Hybrid cells have 5 faces */
848     for (c = cMax; c < cEnd; ++c) {
849       for (r = 0; r < 4; ++r) {
850         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;
851 
852         ierr = DMPlexSetConeSize(rdm, newp, 5);CHKERRQ(ierr);
853       }
854     }
855     /* Interior split faces have 3 edges and the same cells as the parent */
856     for (f = fStart; f < fMax; ++f) {
857       for (r = 0; r < 4; ++r) {
858         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
859         PetscInt       size;
860 
861         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
862         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
863         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
864       }
865     }
866     /* Interior cell faces have 3 edges and 2 cells */
867     for (c = cStart; c < cMax; ++c) {
868       for (r = 0; r < 8; ++r) {
869         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + r;
870 
871         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
872         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
873       }
874     }
875     /* Hybrid split faces have 4 edges and the same cells as the parent */
876     for (f = fMax; f < fEnd; ++f) {
877       for (r = 0; r < 2; ++r) {
878         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
879         PetscInt       size;
880 
881         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
882         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
883         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
884       }
885     }
886     /* Hybrid cells faces have 4 edges and 2 cells */
887     for (c = cMax; c < cEnd; ++c) {
888       for (r = 0; r < 3; ++r) {
889         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + r;
890 
891         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
892         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
893       }
894     }
895     /* Interior split edges have 2 vertices and the same faces */
896     for (e = eStart; e < eMax; ++e) {
897       for (r = 0; r < 2; ++r) {
898         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
899         PetscInt       size;
900 
901         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
902         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
903         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
904       }
905     }
906     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
907     for (f = fStart; f < fMax; ++f) {
908       for (r = 0; r < 3; ++r) {
909         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
910         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
911         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;
912 
913         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
914         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
915         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
916         for (s = 0; s < supportSize; ++s) {
917           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
918           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
919           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
920           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
921           if (support[s] < cMax) {
922             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
923             er = GetTriMidEdgeInverse_Static(ornt[c], r);
924             if (er == eint[c]) {
925               intFaces += 1;
926             } else {
927               intFaces += 2;
928             }
929           } else {
930             intFaces += 1;
931           }
932         }
933         ierr = DMPlexSetSupportSize(rdm, newp, 2+intFaces);CHKERRQ(ierr);
934       }
935     }
936     /* Interior cell edges have 2 vertices and 4 faces */
937     for (c = cStart; c < cMax; ++c) {
938       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
939 
940       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
941       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
942     }
943     /* Hybrid edges have 2 vertices and the same faces */
944     for (e = eMax; e < eEnd; ++e) {
945       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
946       PetscInt       size;
947 
948       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
949       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
950       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
951     }
952     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
953     for (f = fMax; f < fEnd; ++f) {
954       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
955       PetscInt       size;
956 
957       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
958       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
959       ierr = DMPlexSetSupportSize(rdm, newp, 2+2*size);CHKERRQ(ierr);
960     }
961     /* Interior vertices have identical supports */
962     for (v = vStart; v < vEnd; ++v) {
963       const PetscInt newp = vStartNew + (v - vStart);
964       PetscInt       size;
965 
966       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
967       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
968     }
969     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
970     for (e = eStart; e < eMax; ++e) {
971       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
972       const PetscInt *support;
973       PetscInt        size, *star = NULL, starSize, s, faceSize = 0, cellSize = 0;
974 
975       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
976       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
977       for (s = 0; s < size; ++s) {
978         if (support[s] < fMax) faceSize += 2;
979         else                   faceSize += 1;
980       }
981       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
982       for (s = 0; s < starSize*2; s += 2) {
983         const PetscInt *cone, *ornt;
984         PetscInt        e01, e23;
985 
986         if ((star[s] >= cStart) && (star[s] < cMax)) {
987           /* Check edge 0-1 */
988           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
989           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
990           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
991           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
992           /* Check edge 2-3 */
993           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
994           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
995           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
996           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
997           if ((e01 == e) || (e23 == e)) ++cellSize;
998         }
999       }
1000       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
1001       ierr = DMPlexSetSupportSize(rdm, newp, 2 + faceSize + cellSize);CHKERRQ(ierr);
1002     }
1003     break;
1004   case REFINER_SIMPLEX_TO_HEX_3D:
1005     /* All cells have 6 faces */
1006     for (c = cStart; c < cEnd; ++c) {
1007       for (r = 0; r < 4; ++r) {
1008         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
1009 
1010         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1011       }
1012     }
1013     /* Split faces have 4 edges and the same cells as the parent */
1014     for (f = fStart; f < fEnd; ++f) {
1015       for (r = 0; r < 3; ++r) {
1016         const PetscInt newp = fStartNew + (f - fStart)*3 + r;
1017         PetscInt       size;
1018 
1019         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1020         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1021         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1022       }
1023     }
1024     /* Interior cell faces have 4 edges and 2 cells */
1025     for (c = cStart; c < cEnd; ++c) {
1026       for (r = 0; r < 6; ++r) {
1027         const PetscInt newp = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + r;
1028 
1029         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1030         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1031       }
1032     }
1033     /* Split edges have 2 vertices and the same faces */
1034     for (e = eStart; e < eEnd; ++e) {
1035       for (r = 0; r < 2; ++r) {
1036         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1037         PetscInt       size;
1038 
1039         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1040         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1041         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1042       }
1043     }
1044     /* Face edges have 2 vertices and 2 + cell faces supports */
1045     for (f = fStart; f < fEnd; ++f) {
1046       for (r = 0; r < 3; ++r) {
1047         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
1048         PetscInt        size;
1049 
1050         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1051         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1052         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1053       }
1054     }
1055     /* Interior cell edges have 2 vertices and 3 faces */
1056     for (c = cStart; c < cEnd; ++c) {
1057       for (r = 0; r < 4; ++r) {
1058         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + r;
1059 
1060         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1061         ierr = DMPlexSetSupportSize(rdm, newp, 3);CHKERRQ(ierr);
1062       }
1063     }
1064     /* Old vertices have identical supports */
1065     for (v = vStart; v < vEnd; ++v) {
1066       const PetscInt newp = vStartNew + (v - vStart);
1067       PetscInt       size;
1068 
1069       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1070       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1071     }
1072     /* Edge vertices have 2 + faces supports */
1073     for (e = eStart; e < eEnd; ++e) {
1074       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1075       PetscInt       size;
1076 
1077       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1078       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1079     }
1080     /* Face vertices have 3 + cells supports */
1081     for (f = fStart; f < fEnd; ++f) {
1082       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + f - fStart;
1083       PetscInt       size;
1084 
1085       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1086       ierr = DMPlexSetSupportSize(rdm, newp, 3 + size);CHKERRQ(ierr);
1087     }
1088     /* Interior cell vertices have 4 supports */
1089     for (c = cStart; c < cEnd; ++c) {
1090       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + fEnd - fStart + c - cStart;
1091 
1092       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1093     }
1094     break;
1095   case REFINER_HEX_3D:
1096     /* All cells have 6 faces */
1097     for (c = cStart; c < cEnd; ++c) {
1098       for (r = 0; r < 8; ++r) {
1099         const PetscInt newp = (c - cStart)*8 + r;
1100 
1101         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1102       }
1103     }
1104     /* Split faces have 4 edges and the same cells as the parent */
1105     for (f = fStart; f < fEnd; ++f) {
1106       for (r = 0; r < 4; ++r) {
1107         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
1108         PetscInt       size;
1109 
1110         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1111         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1112         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1113       }
1114     }
1115     /* Interior faces have 4 edges and 2 cells */
1116     for (c = cStart; c < cEnd; ++c) {
1117       for (r = 0; r < 12; ++r) {
1118         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
1119 
1120         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1121         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1122       }
1123     }
1124     /* Split edges have 2 vertices and the same faces as the parent */
1125     for (e = eStart; e < eEnd; ++e) {
1126       for (r = 0; r < 2; ++r) {
1127         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1128         PetscInt       size;
1129 
1130         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1131         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1132         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1133       }
1134     }
1135     /* Face edges have 2 vertices and 2+cells faces */
1136     for (f = fStart; f < fEnd; ++f) {
1137       for (r = 0; r < 4; ++r) {
1138         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
1139         PetscInt       size;
1140 
1141         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1142         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1143         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1144       }
1145     }
1146     /* Cell edges have 2 vertices and 4 faces */
1147     for (c = cStart; c < cEnd; ++c) {
1148       for (r = 0; r < 6; ++r) {
1149         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
1150 
1151         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1152         ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1153       }
1154     }
1155     /* Old vertices have identical supports */
1156     for (v = vStart; v < vEnd; ++v) {
1157       const PetscInt newp = vStartNew + (v - vStart);
1158       PetscInt       size;
1159 
1160       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1161       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1162     }
1163     /* Edge vertices have 2 + faces supports */
1164     for (e = eStart; e < eEnd; ++e) {
1165       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1166       PetscInt       size;
1167 
1168       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1169       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1170     }
1171     /* Face vertices have 4 + cells supports */
1172     for (f = fStart; f < fEnd; ++f) {
1173       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
1174       PetscInt       size;
1175 
1176       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1177       ierr = DMPlexSetSupportSize(rdm, newp, 4 + size);CHKERRQ(ierr);
1178     }
1179     /* Cell vertices have 6 supports */
1180     for (c = cStart; c < cEnd; ++c) {
1181       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
1182 
1183       ierr = DMPlexSetSupportSize(rdm, newp, 6);CHKERRQ(ierr);
1184     }
1185     break;
1186   case REFINER_HYBRID_HEX_3D:
1187     ierr = DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 12*(cMax - cStart),
1188                                  eStartNew + 2*(eMax - eStart) + 4*(fMax - fStart) + 6*(cMax - cStart), PETSC_DETERMINE);CHKERRQ(ierr);
1189     /* Interior cells have 6 faces */
1190     for (c = cStart; c < cMax; ++c) {
1191       for (r = 0; r < 8; ++r) {
1192         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
1193 
1194         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1195       }
1196     }
1197     /* Hybrid cells have 6 faces */
1198     for (c = cMax; c < cEnd; ++c) {
1199       for (r = 0; r < 4; ++r) {
1200         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;
1201 
1202         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1203       }
1204     }
1205     /* Interior split faces have 4 edges and the same cells as the parent */
1206     for (f = fStart; f < fMax; ++f) {
1207       for (r = 0; r < 4; ++r) {
1208         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
1209         PetscInt       size;
1210 
1211         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1212         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1213         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1214       }
1215     }
1216     /* Interior cell faces have 4 edges and 2 cells */
1217     for (c = cStart; c < cMax; ++c) {
1218       for (r = 0; r < 12; ++r) {
1219         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
1220 
1221         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1222         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1223       }
1224     }
1225     /* Hybrid split faces have 4 edges and the same cells as the parent */
1226     for (f = fMax; f < fEnd; ++f) {
1227       for (r = 0; r < 2; ++r) {
1228         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
1229         PetscInt       size;
1230 
1231         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1232         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1233         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1234       }
1235     }
1236     /* Hybrid cells faces have 4 edges and 2 cells */
1237     for (c = cMax; c < cEnd; ++c) {
1238       for (r = 0; r < 4; ++r) {
1239         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + r;
1240 
1241         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1242         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1243       }
1244     }
1245     /* Interior split edges have 2 vertices and the same faces as the parent */
1246     for (e = eStart; e < eMax; ++e) {
1247       for (r = 0; r < 2; ++r) {
1248         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1249         PetscInt       size;
1250 
1251         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1252         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1253         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1254       }
1255     }
1256     /* Interior face edges have 2 vertices and 2+cells faces */
1257     for (f = fStart; f < fMax; ++f) {
1258       for (r = 0; r < 4; ++r) {
1259         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
1260         PetscInt       size;
1261 
1262         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1263         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1264         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1265       }
1266     }
1267     /* Interior cell edges have 2 vertices and 4 faces */
1268     for (c = cStart; c < cMax; ++c) {
1269       for (r = 0; r < 6; ++r) {
1270         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
1271 
1272         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1273         ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1274       }
1275     }
1276     /* Hybrid edges have 2 vertices and the same faces */
1277     for (e = eMax; e < eEnd; ++e) {
1278       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
1279       PetscInt       size;
1280 
1281       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1282       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1283       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1284     }
1285     /* Hybrid face edges have 2 vertices and 2+cells faces */
1286     for (f = fMax; f < fEnd; ++f) {
1287       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
1288       PetscInt       size;
1289 
1290       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1291       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1292       ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1293     }
1294     /* Hybrid cell edges have 2 vertices and 4 faces */
1295     for (c = cMax; c < cEnd; ++c) {
1296       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
1297 
1298       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1299       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1300     }
1301     /* Interior vertices have identical supports */
1302     for (v = vStart; v < vEnd; ++v) {
1303       const PetscInt newp = vStartNew + (v - vStart);
1304       PetscInt       size;
1305 
1306       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1307       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1308     }
1309     /* Interior edge vertices have 2 + faces supports */
1310     for (e = eStart; e < eMax; ++e) {
1311       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1312       PetscInt       size;
1313 
1314       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1315       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1316     }
1317     /* Interior face vertices have 4 + cells supports */
1318     for (f = fStart; f < fMax; ++f) {
1319       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
1320       PetscInt       size;
1321 
1322       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1323       ierr = DMPlexSetSupportSize(rdm, newp, 4 + size);CHKERRQ(ierr);
1324     }
1325     /* Interior cell vertices have 6 supports */
1326     for (c = cStart; c < cMax; ++c) {
1327       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
1328 
1329       ierr = DMPlexSetSupportSize(rdm, newp, 6);CHKERRQ(ierr);
1330     }
1331     break;
1332   default:
1333     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
1334   }
1335   PetscFunctionReturn(0);
1336 }
1337 
1338 static PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
1339 {
1340   const PetscInt *faces, cellInd[4] = {0, 1, 2, 3};
1341   PetscInt        cStart,    cEnd,    cMax,    vStart,    vEnd, vMax, fStart,    fEnd,    fMax,    eStart,    eEnd,    eMax;
1342   PetscInt        cStartNew, cEndNew, cMaxNew, vStartNew, vEndNew,    fStartNew, fEndNew, fMaxNew, eStartNew, eEndNew, eMaxNew;
1343   PetscInt        depth, maxSupportSize, *supportRef, c, f, e, v, r, p;
1344   PetscErrorCode  ierr;
1345 
1346   PetscFunctionBegin;
1347   if (!refiner) PetscFunctionReturn(0);
1348   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1349   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
1350   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
1351   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1352   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
1353   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
1354   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
1355   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
1356   switch (refiner) {
1357   case REFINER_SIMPLEX_1D:
1358     /* Max support size of refined mesh is 2 */
1359     ierr = PetscMalloc1(2, &supportRef);CHKERRQ(ierr);
1360     /* All cells have 2 vertices */
1361     for (c = cStart; c < cEnd; ++c) {
1362       const PetscInt  newv = vStartNew + (vEnd - vStart) + (c - cStart);
1363 
1364       for (r = 0; r < 2; ++r) {
1365         const PetscInt newp = cStartNew + (c - cStart)*2 + r;
1366         const PetscInt *cone;
1367         PetscInt        coneNew[2];
1368 
1369         ierr             = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1370         coneNew[0]       = vStartNew + (cone[0] - vStart);
1371         coneNew[1]       = vStartNew + (cone[1] - vStart);
1372         coneNew[(r+1)%2] = newv;
1373         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1374 #if 1
1375         if ((newp < cStartNew) || (newp >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp, cStartNew, cEndNew);
1376         for (p = 0; p < 2; ++p) {
1377           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);
1378         }
1379 #endif
1380       }
1381     }
1382     /* Old vertices have identical supports */
1383     for (v = vStart; v < vEnd; ++v) {
1384       const PetscInt  newp = vStartNew + (v - vStart);
1385       const PetscInt *support, *cone;
1386       PetscInt        size, s;
1387 
1388       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1389       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1390       for (s = 0; s < size; ++s) {
1391         PetscInt r = 0;
1392 
1393         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1394         if (cone[1] == v) r = 1;
1395         supportRef[s] = cStartNew + (support[s] - cStart)*2 + r;
1396       }
1397       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1398 #if 1
1399       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1400       for (p = 0; p < size; ++p) {
1401         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);
1402       }
1403 #endif
1404     }
1405     /* Cell vertices have support of 2 cells */
1406     for (c = cStart; c < cEnd; ++c) {
1407       const PetscInt  newp = vStartNew + (vEnd - vStart) + (c - cStart);
1408 
1409       supportRef[0] = cStartNew + (c - cStart)*2 + 0;
1410       supportRef[1] = cStartNew + (c - cStart)*2 + 1;
1411       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1412 #if 1
1413       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1414       for (p = 0; p < 2; ++p) {
1415         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);
1416       }
1417 #endif
1418     }
1419     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1420     break;
1421   case REFINER_SIMPLEX_2D:
1422     /*
1423      2
1424      |\
1425      | \
1426      |  \
1427      |   \
1428      | C  \
1429      |     \
1430      |      \
1431      2---1---1
1432      |\  D  / \
1433      | 2   0   \
1434      |A \ /  B  \
1435      0---0-------1
1436      */
1437     /* All cells have 3 faces */
1438     for (c = cStart; c < cEnd; ++c) {
1439       const PetscInt  newp = cStartNew + (c - cStart)*4;
1440       const PetscInt *cone, *ornt;
1441       PetscInt        coneNew[3], orntNew[3];
1442 
1443       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1444       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1445       /* A triangle */
1446       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1447       orntNew[0] = ornt[0];
1448       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1449       orntNew[1] = -2;
1450       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1451       orntNew[2] = ornt[2];
1452       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1453       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1454 #if 1
1455       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);
1456       for (p = 0; p < 3; ++p) {
1457         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);
1458       }
1459 #endif
1460       /* B triangle */
1461       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1462       orntNew[0] = ornt[0];
1463       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1464       orntNew[1] = ornt[1];
1465       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1466       orntNew[2] = -2;
1467       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1468       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1469 #if 1
1470       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);
1471       for (p = 0; p < 3; ++p) {
1472         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);
1473       }
1474 #endif
1475       /* C triangle */
1476       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1477       orntNew[0] = -2;
1478       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1479       orntNew[1] = ornt[1];
1480       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1481       orntNew[2] = ornt[2];
1482       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1483       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1484 #if 1
1485       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);
1486       for (p = 0; p < 3; ++p) {
1487         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);
1488       }
1489 #endif
1490       /* D triangle */
1491       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1492       orntNew[0] = 0;
1493       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1494       orntNew[1] = 0;
1495       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1496       orntNew[2] = 0;
1497       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1498       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1499 #if 1
1500       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);
1501       for (p = 0; p < 3; ++p) {
1502         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);
1503       }
1504 #endif
1505     }
1506     /* Split faces have 2 vertices and the same cells as the parent */
1507     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1508     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
1509     for (f = fStart; f < fEnd; ++f) {
1510       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1511 
1512       for (r = 0; r < 2; ++r) {
1513         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1514         const PetscInt *cone, *ornt, *support;
1515         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1516 
1517         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1518         coneNew[0]       = vStartNew + (cone[0] - vStart);
1519         coneNew[1]       = vStartNew + (cone[1] - vStart);
1520         coneNew[(r+1)%2] = newv;
1521         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1522 #if 1
1523         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1524         for (p = 0; p < 2; ++p) {
1525           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);
1526         }
1527 #endif
1528         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1529         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1530         for (s = 0; s < supportSize; ++s) {
1531           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1532           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1533           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1534           for (c = 0; c < coneSize; ++c) {
1535             if (cone[c] == f) break;
1536           }
1537           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1538         }
1539         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1540 #if 1
1541         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1542         for (p = 0; p < supportSize; ++p) {
1543           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);
1544         }
1545 #endif
1546       }
1547     }
1548     /* Interior faces have 2 vertices and 2 cells */
1549     for (c = cStart; c < cEnd; ++c) {
1550       const PetscInt *cone;
1551 
1552       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1553       for (r = 0; r < 3; ++r) {
1554         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
1555         PetscInt       coneNew[2];
1556         PetscInt       supportNew[2];
1557 
1558         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
1559         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
1560         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1561 #if 1
1562         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1563         for (p = 0; p < 2; ++p) {
1564           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);
1565         }
1566 #endif
1567         supportNew[0] = (c - cStart)*4 + (r+1)%3;
1568         supportNew[1] = (c - cStart)*4 + 3;
1569         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1570 #if 1
1571         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1572         for (p = 0; p < 2; ++p) {
1573           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);
1574         }
1575 #endif
1576       }
1577     }
1578     /* Old vertices have identical supports */
1579     for (v = vStart; v < vEnd; ++v) {
1580       const PetscInt  newp = vStartNew + (v - vStart);
1581       const PetscInt *support, *cone;
1582       PetscInt        size, s;
1583 
1584       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1585       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1586       for (s = 0; s < size; ++s) {
1587         PetscInt r = 0;
1588 
1589         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1590         if (cone[1] == v) r = 1;
1591         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1592       }
1593       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1594 #if 1
1595       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1596       for (p = 0; p < size; ++p) {
1597         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);
1598       }
1599 #endif
1600     }
1601     /* Face vertices have 2 + cells*2 supports */
1602     for (f = fStart; f < fEnd; ++f) {
1603       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1604       const PetscInt *cone, *support;
1605       PetscInt        size, s;
1606 
1607       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1608       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1609       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1610       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1611       for (s = 0; s < size; ++s) {
1612         PetscInt r = 0;
1613 
1614         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1615         if      (cone[1] == f) r = 1;
1616         else if (cone[2] == f) r = 2;
1617         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
1618         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
1619       }
1620       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1621 #if 1
1622       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1623       for (p = 0; p < 2+size*2; ++p) {
1624         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);
1625       }
1626 #endif
1627     }
1628     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1629     break;
1630   case REFINER_SIMPLEX_TO_HEX_2D:
1631     /*
1632      2
1633      |\
1634      | \
1635      |  \
1636      |   \
1637      | C  \
1638      |     \
1639      2      1
1640      |\    / \
1641      | 2  1   \
1642      |  \/     \
1643      |   |      \
1644      |A  |   B   \
1645      |   0        \
1646      |   |         \
1647      0---0----------1
1648      */
1649     /* All cells have 4 faces */
1650     for (c = cStart; c < cEnd; ++c) {
1651       const PetscInt  newp = cStartNew + (c - cStart)*3;
1652       const PetscInt *cone, *ornt;
1653       PetscInt        coneNew[4], orntNew[4];
1654 
1655       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1656       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1657       /* A quad */
1658       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1659       orntNew[0] = ornt[0];
1660       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1661       orntNew[1] = 0;
1662       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1663       orntNew[2] = -2;
1664       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1665       orntNew[3] = ornt[2];
1666       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1667       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1668 #if 1
1669       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);
1670       for (p = 0; p < 4; ++p) {
1671         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);
1672       }
1673 #endif
1674       /* B quad */
1675       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1676       orntNew[0] = ornt[0];
1677       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1678       orntNew[1] = ornt[1];
1679       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1680       orntNew[2] = 0;
1681       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1682       orntNew[3] = -2;
1683       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1684       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1685 #if 1
1686       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);
1687       for (p = 0; p < 4; ++p) {
1688         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);
1689       }
1690 #endif
1691       /* C quad */
1692       coneNew[0] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1693       orntNew[0] = ornt[1];
1694       coneNew[1] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1695       orntNew[1] = ornt[2];
1696       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1697       orntNew[2] = 0;
1698       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1699       orntNew[3] = -2;
1700       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1701       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1702 #if 1
1703       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);
1704       for (p = 0; p < 4; ++p) {
1705         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);
1706       }
1707 #endif
1708     }
1709     /* Split faces have 2 vertices and the same cells as the parent */
1710     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1711     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
1712     for (f = fStart; f < fEnd; ++f) {
1713       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1714 
1715       for (r = 0; r < 2; ++r) {
1716         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1717         const PetscInt *cone, *ornt, *support;
1718         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1719 
1720         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1721         coneNew[0]       = vStartNew + (cone[0] - vStart);
1722         coneNew[1]       = vStartNew + (cone[1] - vStart);
1723         coneNew[(r+1)%2] = newv;
1724         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1725 #if 1
1726         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1727         for (p = 0; p < 2; ++p) {
1728           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);
1729         }
1730 #endif
1731         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1732         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1733         for (s = 0; s < supportSize; ++s) {
1734           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1735           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1736           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1737           for (c = 0; c < coneSize; ++c) {
1738             if (cone[c] == f) break;
1739           }
1740           supportRef[s] = cStartNew + (support[s] - cStart)*3 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1741         }
1742         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1743 #if 1
1744         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1745         for (p = 0; p < supportSize; ++p) {
1746           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);
1747         }
1748 #endif
1749       }
1750     }
1751     /* Interior faces have 2 vertices and 2 cells */
1752     for (c = cStart; c < cEnd; ++c) {
1753       const PetscInt *cone;
1754 
1755       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1756       for (r = 0; r < 3; ++r) {
1757         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
1758         PetscInt       coneNew[2];
1759         PetscInt       supportNew[2];
1760 
1761         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
1762         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
1763         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1764 #if 1
1765         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1766         for (p = 0; p < 2; ++p) {
1767           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);
1768         }
1769 #endif
1770         supportNew[0] = (c - cStart)*3 + r%3;
1771         supportNew[1] = (c - cStart)*3 + (r+1)%3;
1772         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1773 #if 1
1774         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1775         for (p = 0; p < 2; ++p) {
1776           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);
1777         }
1778 #endif
1779       }
1780     }
1781     /* Old vertices have identical supports */
1782     for (v = vStart; v < vEnd; ++v) {
1783       const PetscInt  newp = vStartNew + (v - vStart);
1784       const PetscInt *support, *cone;
1785       PetscInt        size, s;
1786 
1787       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1788       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1789       for (s = 0; s < size; ++s) {
1790         PetscInt r = 0;
1791 
1792         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1793         if (cone[1] == v) r = 1;
1794         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1795       }
1796       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1797 #if 1
1798       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1799       for (p = 0; p < size; ++p) {
1800         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);
1801       }
1802 #endif
1803     }
1804     /* Split-face vertices have cells + 2 supports */
1805     for (f = fStart; f < fEnd; ++f) {
1806       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1807       const PetscInt *cone, *support;
1808       PetscInt        size, s;
1809 
1810       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1811       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1812       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1813       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1814       for (s = 0; s < size; ++s) {
1815         PetscInt r = 0;
1816 
1817         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1818         if      (cone[1] == f) r = 1;
1819         else if (cone[2] == f) r = 2;
1820         supportRef[2+s+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
1821       }
1822       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1823 #if 1
1824       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1825       for (p = 0; p < 2+size; ++p) {
1826         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);
1827       }
1828 #endif
1829     }
1830     /* Interior vertices vertices have 3 supports */
1831     for (c = cStart; c < cEnd; ++c) {
1832       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
1833 
1834       supportRef[0] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 0;
1835       supportRef[1] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 1;
1836       supportRef[2] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 2;
1837       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1838     }
1839     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1840     break;
1841   case REFINER_HEX_2D:
1842     /*
1843      3---------2---------2
1844      |         |         |
1845      |    D    2    C    |
1846      |         |         |
1847      3----3----0----1----1
1848      |         |         |
1849      |    A    0    B    |
1850      |         |         |
1851      0---------0---------1
1852      */
1853     /* All cells have 4 faces */
1854     for (c = cStart; c < cEnd; ++c) {
1855       const PetscInt  newp = (c - cStart)*4;
1856       const PetscInt *cone, *ornt;
1857       PetscInt        coneNew[4], orntNew[4];
1858 
1859       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1860       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1861       /* A quad */
1862       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1863       orntNew[0] = ornt[0];
1864       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
1865       orntNew[1] = 0;
1866       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
1867       orntNew[2] = -2;
1868       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
1869       orntNew[3] = ornt[3];
1870       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1871       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1872 #if 1
1873       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);
1874       for (p = 0; p < 4; ++p) {
1875         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);
1876       }
1877 #endif
1878       /* B quad */
1879       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1880       orntNew[0] = ornt[0];
1881       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1882       orntNew[1] = ornt[1];
1883       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
1884       orntNew[2] = -2;
1885       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
1886       orntNew[3] = -2;
1887       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1888       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1889 #if 1
1890       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);
1891       for (p = 0; p < 4; ++p) {
1892         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);
1893       }
1894 #endif
1895       /* C quad */
1896       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
1897       orntNew[0] = 0;
1898       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1899       orntNew[1] = ornt[1];
1900       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1901       orntNew[2] = ornt[2];
1902       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
1903       orntNew[3] = -2;
1904       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1905       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1906 #if 1
1907       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);
1908       for (p = 0; p < 4; ++p) {
1909         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);
1910       }
1911 #endif
1912       /* D quad */
1913       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
1914       orntNew[0] = 0;
1915       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
1916       orntNew[1] = 0;
1917       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1918       orntNew[2] = ornt[2];
1919       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
1920       orntNew[3] = ornt[3];
1921       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1922       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1923 #if 1
1924       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);
1925       for (p = 0; p < 4; ++p) {
1926         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);
1927       }
1928 #endif
1929     }
1930     /* Split faces have 2 vertices and the same cells as the parent */
1931     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1932     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
1933     for (f = fStart; f < fEnd; ++f) {
1934       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1935 
1936       for (r = 0; r < 2; ++r) {
1937         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1938         const PetscInt *cone, *ornt, *support;
1939         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1940 
1941         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1942         coneNew[0]       = vStartNew + (cone[0] - vStart);
1943         coneNew[1]       = vStartNew + (cone[1] - vStart);
1944         coneNew[(r+1)%2] = newv;
1945         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1946 #if 1
1947         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1948         for (p = 0; p < 2; ++p) {
1949           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);
1950         }
1951 #endif
1952         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1953         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1954         for (s = 0; s < supportSize; ++s) {
1955           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1956           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1957           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1958           for (c = 0; c < coneSize; ++c) {
1959             if (cone[c] == f) break;
1960           }
1961           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
1962         }
1963         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1964 #if 1
1965         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1966         for (p = 0; p < supportSize; ++p) {
1967           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);
1968         }
1969 #endif
1970       }
1971     }
1972     /* Interior faces have 2 vertices and 2 cells */
1973     for (c = cStart; c < cEnd; ++c) {
1974       const PetscInt *cone;
1975       PetscInt        coneNew[2], supportNew[2];
1976 
1977       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1978       for (r = 0; r < 4; ++r) {
1979         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
1980 
1981 	if (r==1 || r==2) {
1982           coneNew[0] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
1983           coneNew[1] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
1984 	} else {
1985           coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
1986           coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
1987 	}
1988 	ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1989 #if 1
1990         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1991         for (p = 0; p < 2; ++p) {
1992           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);
1993         }
1994 #endif
1995         supportNew[0] = (c - cStart)*4 + r;
1996         supportNew[1] = (c - cStart)*4 + (r+1)%4;
1997         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1998 #if 1
1999         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2000         for (p = 0; p < 2; ++p) {
2001           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);
2002         }
2003 #endif
2004       }
2005     }
2006     /* Old vertices have identical supports */
2007     for (v = vStart; v < vEnd; ++v) {
2008       const PetscInt  newp = vStartNew + (v - vStart);
2009       const PetscInt *support, *cone;
2010       PetscInt        size, s;
2011 
2012       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2013       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2014       for (s = 0; s < size; ++s) {
2015         PetscInt r = 0;
2016 
2017         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2018         if (cone[1] == v) r = 1;
2019         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2020       }
2021       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2022 #if 1
2023       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2024       for (p = 0; p < size; ++p) {
2025         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);
2026       }
2027 #endif
2028     }
2029     /* Face vertices have 2 + cells supports */
2030     for (f = fStart; f < fEnd; ++f) {
2031       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2032       const PetscInt *cone, *support;
2033       PetscInt        size, s;
2034 
2035       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2036       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2037       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2038       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2039       for (s = 0; s < size; ++s) {
2040         PetscInt r = 0;
2041 
2042         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2043         if      (cone[1] == f) r = 1;
2044         else if (cone[2] == f) r = 2;
2045         else if (cone[3] == f) r = 3;
2046         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
2047       }
2048       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2049 #if 1
2050       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2051       for (p = 0; p < 2+size; ++p) {
2052         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);
2053       }
2054 #endif
2055     }
2056     /* Cell vertices have 4 supports */
2057     for (c = cStart; c < cEnd; ++c) {
2058       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
2059       PetscInt       supportNew[4];
2060 
2061       for (r = 0; r < 4; ++r) {
2062         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
2063       }
2064       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2065     }
2066     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2067     break;
2068   case REFINER_HYBRID_SIMPLEX_2D:
2069     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
2070     cMax = PetscMin(cEnd, cMax);
2071     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
2072     fMax = PetscMin(fEnd, fMax);
2073     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);CHKERRQ(ierr);
2074     /* Interior cells have 3 faces */
2075     for (c = cStart; c < cMax; ++c) {
2076       const PetscInt  newp = cStartNew + (c - cStart)*4;
2077       const PetscInt *cone, *ornt;
2078       PetscInt        coneNew[3], orntNew[3];
2079 
2080       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2081       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2082       /* A triangle */
2083       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2084       orntNew[0] = ornt[0];
2085       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
2086       orntNew[1] = -2;
2087       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2088       orntNew[2] = ornt[2];
2089       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2090       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2091 #if 1
2092       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);
2093       for (p = 0; p < 3; ++p) {
2094         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);
2095       }
2096 #endif
2097       /* B triangle */
2098       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2099       orntNew[0] = ornt[0];
2100       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2101       orntNew[1] = ornt[1];
2102       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
2103       orntNew[2] = -2;
2104       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2105       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2106 #if 1
2107       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);
2108       for (p = 0; p < 3; ++p) {
2109         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);
2110       }
2111 #endif
2112       /* C triangle */
2113       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
2114       orntNew[0] = -2;
2115       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2116       orntNew[1] = ornt[1];
2117       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2118       orntNew[2] = ornt[2];
2119       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2120       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2121 #if 1
2122       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);
2123       for (p = 0; p < 3; ++p) {
2124         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);
2125       }
2126 #endif
2127       /* D triangle */
2128       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
2129       orntNew[0] = 0;
2130       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
2131       orntNew[1] = 0;
2132       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
2133       orntNew[2] = 0;
2134       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2135       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2136 #if 1
2137       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);
2138       for (p = 0; p < 3; ++p) {
2139         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);
2140       }
2141 #endif
2142     }
2143     /*
2144      2----3----3
2145      |         |
2146      |    B    |
2147      |         |
2148      0----4--- 1
2149      |         |
2150      |    A    |
2151      |         |
2152      0----2----1
2153      */
2154     /* Hybrid cells have 4 faces */
2155     for (c = cMax; c < cEnd; ++c) {
2156       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
2157       const PetscInt *cone, *ornt;
2158       PetscInt        coneNew[4], orntNew[4], r;
2159 
2160       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2161       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2162       r    = (ornt[0] < 0 ? 1 : 0);
2163       /* A quad */
2164       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + r;
2165       orntNew[0]   = ornt[0];
2166       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + r;
2167       orntNew[1]   = ornt[1];
2168       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2+r] - fMax);
2169       orntNew[2+r] = 0;
2170       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
2171       orntNew[3-r] = 0;
2172       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2173       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2174 #if 1
2175       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);
2176       for (p = 0; p < 4; ++p) {
2177         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);
2178       }
2179 #endif
2180       /* B quad */
2181       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + 1-r;
2182       orntNew[0]   = ornt[0];
2183       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + 1-r;
2184       orntNew[1]   = ornt[1];
2185       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
2186       orntNew[2+r] = 0;
2187       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3-r] - fMax);
2188       orntNew[3-r] = 0;
2189       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2190       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2191 #if 1
2192       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);
2193       for (p = 0; p < 4; ++p) {
2194         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);
2195       }
2196 #endif
2197     }
2198     /* Interior split faces have 2 vertices and the same cells as the parent */
2199     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2200     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2201     for (f = fStart; f < fMax; ++f) {
2202       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
2203 
2204       for (r = 0; r < 2; ++r) {
2205         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2206         const PetscInt *cone, *ornt, *support;
2207         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2208 
2209         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2210         coneNew[0]       = vStartNew + (cone[0] - vStart);
2211         coneNew[1]       = vStartNew + (cone[1] - vStart);
2212         coneNew[(r+1)%2] = newv;
2213         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2214 #if 1
2215         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2216         for (p = 0; p < 2; ++p) {
2217           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);
2218         }
2219 #endif
2220         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2221         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2222         for (s = 0; s < supportSize; ++s) {
2223           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2224           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2225           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2226           for (c = 0; c < coneSize; ++c) if (cone[c] == f) break;
2227           if (support[s] >= cMax) {
2228             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[c] < 0 ? 1-r : r);
2229           } else {
2230             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
2231           }
2232         }
2233         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2234 #if 1
2235         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2236         for (p = 0; p < supportSize; ++p) {
2237           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);
2238         }
2239 #endif
2240       }
2241     }
2242     /* Interior cell faces have 2 vertices and 2 cells */
2243     for (c = cStart; c < cMax; ++c) {
2244       const PetscInt *cone;
2245 
2246       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2247       for (r = 0; r < 3; ++r) {
2248         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
2249         PetscInt       coneNew[2];
2250         PetscInt       supportNew[2];
2251 
2252         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
2253         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
2254         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2255 #if 1
2256         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2257         for (p = 0; p < 2; ++p) {
2258           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);
2259         }
2260 #endif
2261         supportNew[0] = (c - cStart)*4 + (r+1)%3;
2262         supportNew[1] = (c - cStart)*4 + 3;
2263         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2264 #if 1
2265         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2266         for (p = 0; p < 2; ++p) {
2267           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);
2268         }
2269 #endif
2270       }
2271     }
2272     /* Interior hybrid faces have 2 vertices and the same cells */
2273     for (f = fMax; f < fEnd; ++f) {
2274       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
2275       const PetscInt *cone, *ornt;
2276       const PetscInt *support;
2277       PetscInt        coneNew[2];
2278       PetscInt        supportNew[2];
2279       PetscInt        size, s, r;
2280 
2281       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2282       coneNew[0] = vStartNew + (cone[0] - vStart);
2283       coneNew[1] = vStartNew + (cone[1] - vStart);
2284       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2285 #if 1
2286       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2287       for (p = 0; p < 2; ++p) {
2288         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);
2289       }
2290 #endif
2291       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2292       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2293       for (s = 0; s < size; ++s) {
2294         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2295         ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2296         for (r = 0; r < 2; ++r) {
2297           if (cone[r+2] == f) break;
2298         }
2299         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[0] < 0 ? 1-r : r);
2300       }
2301       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2302 #if 1
2303       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2304       for (p = 0; p < size; ++p) {
2305         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);
2306       }
2307 #endif
2308     }
2309     /* Cell hybrid faces have 2 vertices and 2 cells */
2310     for (c = cMax; c < cEnd; ++c) {
2311       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
2312       const PetscInt *cone;
2313       PetscInt        coneNew[2];
2314       PetscInt        supportNew[2];
2315 
2316       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2317       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
2318       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
2319       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2320 #if 1
2321       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2322       for (p = 0; p < 2; ++p) {
2323         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);
2324       }
2325 #endif
2326       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
2327       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
2328       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2329 #if 1
2330       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2331       for (p = 0; p < 2; ++p) {
2332         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);
2333       }
2334 #endif
2335     }
2336     /* Old vertices have identical supports */
2337     for (v = vStart; v < vEnd; ++v) {
2338       const PetscInt  newp = vStartNew + (v - vStart);
2339       const PetscInt *support, *cone;
2340       PetscInt        size, s;
2341 
2342       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2343       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2344       for (s = 0; s < size; ++s) {
2345         if (support[s] >= fMax) {
2346           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
2347         } else {
2348           PetscInt r = 0;
2349 
2350           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2351           if (cone[1] == v) r = 1;
2352           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2353         }
2354       }
2355       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2356 #if 1
2357       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2358       for (p = 0; p < size; ++p) {
2359         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);
2360       }
2361 #endif
2362     }
2363     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
2364     for (f = fStart; f < fMax; ++f) {
2365       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2366       const PetscInt *cone, *support;
2367       PetscInt        size, newSize = 2, s;
2368 
2369       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2370       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2371       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2372       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2373       for (s = 0; s < size; ++s) {
2374         PetscInt r = 0;
2375 
2376         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2377         if (support[s] >= cMax) {
2378           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
2379 
2380           newSize += 1;
2381         } else {
2382           if      (cone[1] == f) r = 1;
2383           else if (cone[2] == f) r = 2;
2384           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
2385           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
2386 
2387           newSize += 2;
2388         }
2389       }
2390       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2391 #if 1
2392       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2393       for (p = 0; p < newSize; ++p) {
2394         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);
2395       }
2396 #endif
2397     }
2398     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2399     break;
2400   case REFINER_HYBRID_HEX_2D:
2401     /* Hybrid Hex 2D */
2402     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
2403     cMax = PetscMin(cEnd, cMax);
2404     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
2405     fMax = PetscMin(fEnd, fMax);
2406     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);CHKERRQ(ierr);
2407     /* Interior cells have 4 faces */
2408     for (c = cStart; c < cMax; ++c) {
2409       const PetscInt  newp = cStartNew + (c - cStart)*4;
2410       const PetscInt *cone, *ornt;
2411       PetscInt        coneNew[4], orntNew[4];
2412 
2413       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2414       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2415       /* A quad */
2416       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2417       orntNew[0] = ornt[0];
2418       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
2419       orntNew[1] = 0;
2420       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
2421       orntNew[2] = -2;
2422       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
2423       orntNew[3] = ornt[3];
2424       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2425       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2426 #if 1
2427       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);
2428       for (p = 0; p < 4; ++p) {
2429         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);
2430       }
2431 #endif
2432       /* B quad */
2433       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2434       orntNew[0] = ornt[0];
2435       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2436       orntNew[1] = ornt[1];
2437       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
2438       orntNew[2] = 0;
2439       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
2440       orntNew[3] = -2;
2441       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2442       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2443 #if 1
2444       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);
2445       for (p = 0; p < 4; ++p) {
2446         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);
2447       }
2448 #endif
2449       /* C quad */
2450       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
2451       orntNew[0] = -2;
2452       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2453       orntNew[1] = ornt[1];
2454       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2455       orntNew[2] = ornt[2];
2456       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
2457       orntNew[3] = 0;
2458       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2459       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2460 #if 1
2461       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);
2462       for (p = 0; p < 4; ++p) {
2463         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);
2464       }
2465 #endif
2466       /* D quad */
2467       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
2468       orntNew[0] = 0;
2469       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
2470       orntNew[1] = -2;
2471       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2472       orntNew[2] = ornt[2];
2473       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
2474       orntNew[3] = ornt[3];
2475       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2476       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2477 #if 1
2478       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);
2479       for (p = 0; p < 4; ++p) {
2480         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);
2481       }
2482 #endif
2483     }
2484     /*
2485      2----3----3
2486      |         |
2487      |    B    |
2488      |         |
2489      0----4--- 1
2490      |         |
2491      |    A    |
2492      |         |
2493      0----2----1
2494      */
2495     /* Hybrid cells have 4 faces */
2496     for (c = cMax; c < cEnd; ++c) {
2497       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
2498       const PetscInt *cone, *ornt;
2499       PetscInt        coneNew[4], orntNew[4];
2500 
2501       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2502       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2503       /* A quad */
2504       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2505       orntNew[0] = ornt[0];
2506       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2507       orntNew[1] = ornt[1];
2508       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[2] - fMax);
2509       orntNew[2] = 0;
2510       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
2511       orntNew[3] = 0;
2512       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2513       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2514 #if 1
2515       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);
2516       for (p = 0; p < 4; ++p) {
2517         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);
2518       }
2519 #endif
2520       /* B quad */
2521       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2522       orntNew[0] = ornt[0];
2523       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2524       orntNew[1] = ornt[1];
2525       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
2526       orntNew[2] = 0;
2527       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[3] - fMax);
2528       orntNew[3] = 0;
2529       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2530       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2531 #if 1
2532       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);
2533       for (p = 0; p < 4; ++p) {
2534         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);
2535       }
2536 #endif
2537     }
2538     /* Interior split faces have 2 vertices and the same cells as the parent */
2539     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2540     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2541     for (f = fStart; f < fMax; ++f) {
2542       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
2543 
2544       for (r = 0; r < 2; ++r) {
2545         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2546         const PetscInt *cone, *ornt, *support;
2547         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2548 
2549         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2550         coneNew[0]       = vStartNew + (cone[0] - vStart);
2551         coneNew[1]       = vStartNew + (cone[1] - vStart);
2552         coneNew[(r+1)%2] = newv;
2553         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2554 #if 1
2555         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2556         for (p = 0; p < 2; ++p) {
2557           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);
2558         }
2559 #endif
2560         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2561         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2562         for (s = 0; s < supportSize; ++s) {
2563           if (support[s] >= cMax) {
2564             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
2565           } else {
2566             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2567             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2568             ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2569             for (c = 0; c < coneSize; ++c) {
2570               if (cone[c] == f) break;
2571             }
2572             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
2573           }
2574         }
2575         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2576 #if 1
2577         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2578         for (p = 0; p < supportSize; ++p) {
2579           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);
2580         }
2581 #endif
2582       }
2583     }
2584     /* Interior cell faces have 2 vertices and 2 cells */
2585     for (c = cStart; c < cMax; ++c) {
2586       const PetscInt *cone;
2587 
2588       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2589       for (r = 0; r < 4; ++r) {
2590         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
2591         PetscInt       coneNew[2], supportNew[2];
2592 
2593         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2594         coneNew[1] = vStartNew + (vEnd - vStart) + (fMax    - fStart) + (c - cStart);
2595         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2596 #if 1
2597         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2598         for (p = 0; p < 2; ++p) {
2599           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);
2600         }
2601 #endif
2602         supportNew[0] = (c - cStart)*4 + r;
2603         supportNew[1] = (c - cStart)*4 + (r+1)%4;
2604         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2605 #if 1
2606         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2607         for (p = 0; p < 2; ++p) {
2608           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);
2609         }
2610 #endif
2611       }
2612     }
2613     /* Hybrid faces have 2 vertices and the same cells */
2614     for (f = fMax; f < fEnd; ++f) {
2615       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
2616       const PetscInt *cone, *support;
2617       PetscInt        coneNew[2], supportNew[2];
2618       PetscInt        size, s, r;
2619 
2620       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2621       coneNew[0] = vStartNew + (cone[0] - vStart);
2622       coneNew[1] = vStartNew + (cone[1] - vStart);
2623       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2624 #if 1
2625       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2626       for (p = 0; p < 2; ++p) {
2627         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);
2628       }
2629 #endif
2630       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2631       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2632       for (s = 0; s < size; ++s) {
2633         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2634         for (r = 0; r < 2; ++r) {
2635           if (cone[r+2] == f) break;
2636         }
2637         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
2638       }
2639       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2640 #if 1
2641       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2642       for (p = 0; p < size; ++p) {
2643         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);
2644       }
2645 #endif
2646     }
2647     /* Cell hybrid faces have 2 vertices and 2 cells */
2648     for (c = cMax; c < cEnd; ++c) {
2649       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
2650       const PetscInt *cone;
2651       PetscInt        coneNew[2], supportNew[2];
2652 
2653       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2654       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
2655       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
2656       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2657 #if 1
2658       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2659       for (p = 0; p < 2; ++p) {
2660         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);
2661       }
2662 #endif
2663       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
2664       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
2665       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2666 #if 1
2667       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2668       for (p = 0; p < 2; ++p) {
2669         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);
2670       }
2671 #endif
2672     }
2673     /* Old vertices have identical supports */
2674     for (v = vStart; v < vEnd; ++v) {
2675       const PetscInt  newp = vStartNew + (v - vStart);
2676       const PetscInt *support, *cone;
2677       PetscInt        size, s;
2678 
2679       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2680       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2681       for (s = 0; s < size; ++s) {
2682         if (support[s] >= fMax) {
2683           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (support[s] - fMax);
2684         } else {
2685           PetscInt r = 0;
2686 
2687           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2688           if (cone[1] == v) r = 1;
2689           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2690         }
2691       }
2692       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2693 #if 1
2694       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2695       for (p = 0; p < size; ++p) {
2696         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);
2697       }
2698 #endif
2699     }
2700     /* Face vertices have 2 + cells supports */
2701     for (f = fStart; f < fMax; ++f) {
2702       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2703       const PetscInt *cone, *support;
2704       PetscInt        size, s;
2705 
2706       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2707       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2708       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2709       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2710       for (s = 0; s < size; ++s) {
2711         PetscInt r = 0;
2712 
2713         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2714         if (support[s] >= cMax) {
2715           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (support[s] - cMax);
2716         } else {
2717           if      (cone[1] == f) r = 1;
2718           else if (cone[2] == f) r = 2;
2719           else if (cone[3] == f) r = 3;
2720           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*4 + r;
2721         }
2722       }
2723       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2724 #if 1
2725       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2726       for (p = 0; p < 2+size; ++p) {
2727         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);
2728       }
2729 #endif
2730     }
2731     /* Cell vertices have 4 supports */
2732     for (c = cStart; c < cMax; ++c) {
2733       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
2734       PetscInt       supportNew[4];
2735 
2736       for (r = 0; r < 4; ++r) {
2737         supportNew[r] = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
2738       }
2739       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2740     }
2741     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2742     break;
2743   case REFINER_SIMPLEX_3D:
2744     /* All cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
2745     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
2746     for (c = cStart; c < cEnd; ++c) {
2747       const PetscInt  newp = cStartNew + (c - cStart)*8;
2748       const PetscInt *cone, *ornt;
2749       PetscInt        coneNew[4], orntNew[4];
2750 
2751       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2752       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2753       /* A tetrahedron: {0, a, c, d} */
2754       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
2755       orntNew[0] = ornt[0];
2756       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
2757       orntNew[1] = ornt[1];
2758       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
2759       orntNew[2] = ornt[2];
2760       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
2761       orntNew[3] = 0;
2762       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2763       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2764 #if 1
2765       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);
2766       for (p = 0; p < 4; ++p) {
2767         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);
2768       }
2769 #endif
2770       /* B tetrahedron: {a, 1, b, e} */
2771       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
2772       orntNew[0] = ornt[0];
2773       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
2774       orntNew[1] = ornt[1];
2775       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
2776       orntNew[2] = 0;
2777       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
2778       orntNew[3] = ornt[3];
2779       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2780       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2781 #if 1
2782       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);
2783       for (p = 0; p < 4; ++p) {
2784         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);
2785       }
2786 #endif
2787       /* C tetrahedron: {c, b, 2, f} */
2788       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
2789       orntNew[0] = ornt[0];
2790       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
2791       orntNew[1] = 0;
2792       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
2793       orntNew[2] = ornt[2];
2794       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
2795       orntNew[3] = ornt[3];
2796       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2797       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2798 #if 1
2799       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);
2800       for (p = 0; p < 4; ++p) {
2801         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);
2802       }
2803 #endif
2804       /* D tetrahedron: {d, e, f, 3} */
2805       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
2806       orntNew[0] = 0;
2807       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
2808       orntNew[1] = ornt[1];
2809       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
2810       orntNew[2] = ornt[2];
2811       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
2812       orntNew[3] = ornt[3];
2813       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2814       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2815 #if 1
2816       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);
2817       for (p = 0; p < 4; ++p) {
2818         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);
2819       }
2820 #endif
2821       /* A' tetrahedron: {c, d, a, f} */
2822       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
2823       orntNew[0] = -3;
2824       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
2825       orntNew[1] = ornt[2] < 0 ? -(GetTriMidEdge_Static(ornt[2], 0)+1) : GetTriMidEdge_Static(ornt[2], 0);
2826       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
2827       orntNew[2] = 0;
2828       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
2829       orntNew[3] = 2;
2830       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
2831       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
2832 #if 1
2833       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);
2834       for (p = 0; p < 4; ++p) {
2835         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);
2836       }
2837 #endif
2838       /* B' tetrahedron: {e, b, a, f} */
2839       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
2840       orntNew[0] = -2;
2841       coneNew[1] = fStartNew + (cone[3] - fStart)*4 + 3;
2842       orntNew[1] = ornt[3] < 0 ? -(GetTriMidEdge_Static(ornt[3], 1)+1) : GetTriMidEdge_Static(ornt[3], 1);
2843       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
2844       orntNew[2] = 0;
2845       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
2846       orntNew[3] = 0;
2847       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
2848       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
2849 #if 1
2850       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);
2851       for (p = 0; p < 4; ++p) {
2852         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);
2853       }
2854 #endif
2855       /* C' tetrahedron: {f, a, c, b} */
2856       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
2857       orntNew[0] = -2;
2858       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
2859       orntNew[1] = -2;
2860       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
2861       orntNew[2] = -1;
2862       coneNew[3] = fStartNew + (cone[0] - fStart)*4 + 3;
2863       orntNew[3] = ornt[0] < 0 ? -(GetTriMidEdge_Static(ornt[0], 2)+1) : GetTriMidEdge_Static(ornt[0], 2);
2864       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
2865       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
2866 #if 1
2867       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);
2868       for (p = 0; p < 4; ++p) {
2869         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);
2870       }
2871 #endif
2872       /* D' tetrahedron: {f, a, e, d} */
2873       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
2874       orntNew[0] = -2;
2875       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
2876       orntNew[1] = -1;
2877       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
2878       orntNew[2] = -2;
2879       coneNew[3] = fStartNew + (cone[1] - fStart)*4 + 3;
2880       orntNew[3] = ornt[1] < 0 ? -(GetTriMidEdge_Static(ornt[1], 1)+1) : GetTriMidEdge_Static(ornt[1], 1);
2881       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
2882       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
2883 #if 1
2884       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);
2885       for (p = 0; p < 4; ++p) {
2886         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);
2887       }
2888 #endif
2889     }
2890     /* Split faces have 3 edges and the same cells as the parent */
2891     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2892     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2893     for (f = fStart; f < fEnd; ++f) {
2894       const PetscInt  newp = fStartNew + (f - fStart)*4;
2895       const PetscInt *cone, *ornt, *support;
2896       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
2897 
2898       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2899       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
2900       /* A triangle */
2901       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
2902       orntNew[0] = ornt[0];
2903       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
2904       orntNew[1] = -2;
2905       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
2906       orntNew[2] = ornt[2];
2907       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2908       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2909 #if 1
2910       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);
2911       for (p = 0; p < 3; ++p) {
2912         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);
2913       }
2914 #endif
2915       /* B triangle */
2916       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
2917       orntNew[0] = ornt[0];
2918       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
2919       orntNew[1] = ornt[1];
2920       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
2921       orntNew[2] = -2;
2922       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2923       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2924 #if 1
2925       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);
2926       for (p = 0; p < 3; ++p) {
2927         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);
2928       }
2929 #endif
2930       /* C triangle */
2931       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
2932       orntNew[0] = -2;
2933       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
2934       orntNew[1] = ornt[1];
2935       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
2936       orntNew[2] = ornt[2];
2937       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2938       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2939 #if 1
2940       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);
2941       for (p = 0; p < 3; ++p) {
2942         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);
2943       }
2944 #endif
2945       /* D triangle */
2946       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
2947       orntNew[0] = 0;
2948       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
2949       orntNew[1] = 0;
2950       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
2951       orntNew[2] = 0;
2952       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2953       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2954 #if 1
2955       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);
2956       for (p = 0; p < 3; ++p) {
2957         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);
2958       }
2959 #endif
2960       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2961       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2962       for (r = 0; r < 4; ++r) {
2963         for (s = 0; s < supportSize; ++s) {
2964           PetscInt subf;
2965           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2966           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2967           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2968           for (c = 0; c < coneSize; ++c) {
2969             if (cone[c] == f) break;
2970           }
2971           subf = GetTriSubfaceInverse_Static(ornt[c], r);
2972           supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
2973         }
2974         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
2975 #if 1
2976         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);
2977         for (p = 0; p < supportSize; ++p) {
2978           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);
2979         }
2980 #endif
2981       }
2982     }
2983     /* Interior faces have 3 edges and 2 cells */
2984     for (c = cStart; c < cEnd; ++c) {
2985       PetscInt        newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8;
2986       const PetscInt *cone, *ornt;
2987       PetscInt        coneNew[3], orntNew[3];
2988       PetscInt        supportNew[2];
2989 
2990       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2991       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2992       /* Face A: {c, a, d} */
2993       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
2994       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2995       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
2996       orntNew[1] = ornt[1] < 0 ? -2 : 0;
2997       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 2);
2998       orntNew[2] = ornt[2] < 0 ? -2 : 0;
2999       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3000       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3001 #if 1
3002       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3003       for (p = 0; p < 3; ++p) {
3004         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);
3005       }
3006 #endif
3007       supportNew[0] = (c - cStart)*8 + 0;
3008       supportNew[1] = (c - cStart)*8 + 0+4;
3009       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3010 #if 1
3011       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3012       for (p = 0; p < 2; ++p) {
3013         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);
3014       }
3015 #endif
3016       ++newp;
3017       /* Face B: {a, b, e} */
3018       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3019       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3020       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 0);
3021       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3022       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3023       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3024       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3025       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3026 #if 1
3027       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3028       for (p = 0; p < 3; ++p) {
3029         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);
3030       }
3031 #endif
3032       supportNew[0] = (c - cStart)*8 + 1;
3033       supportNew[1] = (c - cStart)*8 + 1+4;
3034       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3035 #if 1
3036       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3037       for (p = 0; p < 2; ++p) {
3038         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);
3039       }
3040 #endif
3041       ++newp;
3042       /* Face C: {c, f, b} */
3043       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3044       orntNew[0] = ornt[2] < 0 ? -2 : 0;
3045       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3046       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3047       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 1);
3048       orntNew[2] = ornt[0] < 0 ? -2 : 0;
3049       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3050       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3051 #if 1
3052       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3053       for (p = 0; p < 3; ++p) {
3054         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);
3055       }
3056 #endif
3057       supportNew[0] = (c - cStart)*8 + 2;
3058       supportNew[1] = (c - cStart)*8 + 2+4;
3059       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3060 #if 1
3061       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3062       for (p = 0; p < 2; ++p) {
3063         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);
3064       }
3065 #endif
3066       ++newp;
3067       /* Face D: {d, e, f} */
3068       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 0);
3069       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3070       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3071       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3072       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3073       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3074       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3075       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3076 #if 1
3077       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3078       for (p = 0; p < 3; ++p) {
3079         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);
3080       }
3081 #endif
3082       supportNew[0] = (c - cStart)*8 + 3;
3083       supportNew[1] = (c - cStart)*8 + 3+4;
3084       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3085 #if 1
3086       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3087       for (p = 0; p < 2; ++p) {
3088         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);
3089       }
3090 #endif
3091       ++newp;
3092       /* Face E: {d, f, a} */
3093       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3094       orntNew[0] = ornt[2] < 0 ? 0 : -2;
3095       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3096       orntNew[1] = -2;
3097       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3098       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3099       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3100       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3101 #if 1
3102       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3103       for (p = 0; p < 3; ++p) {
3104         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);
3105       }
3106 #endif
3107       supportNew[0] = (c - cStart)*8 + 0+4;
3108       supportNew[1] = (c - cStart)*8 + 3+4;
3109       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3110 #if 1
3111       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3112       for (p = 0; p < 2; ++p) {
3113         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);
3114       }
3115 #endif
3116       ++newp;
3117       /* Face F: {c, a, f} */
3118       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3119       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3120       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3121       orntNew[1] = 0;
3122       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3123       orntNew[2] = ornt[2] < 0 ? 0 : -2;
3124       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3125       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3126 #if 1
3127       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3128       for (p = 0; p < 3; ++p) {
3129         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);
3130       }
3131 #endif
3132       supportNew[0] = (c - cStart)*8 + 0+4;
3133       supportNew[1] = (c - cStart)*8 + 2+4;
3134       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3135 #if 1
3136       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3137       for (p = 0; p < 2; ++p) {
3138         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);
3139       }
3140 #endif
3141       ++newp;
3142       /* Face G: {e, a, f} */
3143       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3144       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3145       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3146       orntNew[1] = 0;
3147       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3148       orntNew[2] = ornt[3] < 0 ? 0 : -2;
3149       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3150       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3151 #if 1
3152       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3153       for (p = 0; p < 3; ++p) {
3154         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);
3155       }
3156 #endif
3157       supportNew[0] = (c - cStart)*8 + 1+4;
3158       supportNew[1] = (c - cStart)*8 + 3+4;
3159       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3160 #if 1
3161       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3162       for (p = 0; p < 2; ++p) {
3163         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);
3164       }
3165 #endif
3166       ++newp;
3167       /* Face H: {a, b, f} */
3168       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3169       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3170       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3171       orntNew[1] = ornt[3] < 0 ? 0 : -2;
3172       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3173       orntNew[2] = -2;
3174       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3175       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3176 #if 1
3177       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3178       for (p = 0; p < 3; ++p) {
3179         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);
3180       }
3181 #endif
3182       supportNew[0] = (c - cStart)*8 + 1+4;
3183       supportNew[1] = (c - cStart)*8 + 2+4;
3184       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3185 #if 1
3186       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3187       for (p = 0; p < 2; ++p) {
3188         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);
3189       }
3190 #endif
3191       ++newp;
3192     }
3193     /* Split Edges have 2 vertices and the same faces as the parent */
3194     for (e = eStart; e < eEnd; ++e) {
3195       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
3196 
3197       for (r = 0; r < 2; ++r) {
3198         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
3199         const PetscInt *cone, *ornt, *support;
3200         PetscInt        coneNew[2], coneSize, c, supportSize, s;
3201 
3202         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3203         coneNew[0]       = vStartNew + (cone[0] - vStart);
3204         coneNew[1]       = vStartNew + (cone[1] - vStart);
3205         coneNew[(r+1)%2] = newv;
3206         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3207 #if 1
3208         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3209         for (p = 0; p < 2; ++p) {
3210           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);
3211         }
3212 #endif
3213         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
3214         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3215         for (s = 0; s < supportSize; ++s) {
3216           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3217           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3218           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3219           for (c = 0; c < coneSize; ++c) {
3220             if (cone[c] == e) break;
3221           }
3222           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
3223         }
3224         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3225 #if 1
3226         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3227         for (p = 0; p < supportSize; ++p) {
3228           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);
3229         }
3230 #endif
3231       }
3232     }
3233     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
3234     for (f = fStart; f < fEnd; ++f) {
3235       const PetscInt *cone, *ornt, *support;
3236       PetscInt        coneSize, supportSize, s;
3237 
3238       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3239       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3240       for (r = 0; r < 3; ++r) {
3241         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
3242         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
3243         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
3244                                     -1, -1,  1,  6,  0,  4,
3245                                      2,  5,  3,  4, -1, -1,
3246                                     -1, -1,  3,  6,  2,  7};
3247 
3248         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3249         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
3250         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
3251         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3252 #if 1
3253         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3254         for (p = 0; p < 2; ++p) {
3255           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);
3256         }
3257 #endif
3258         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
3259         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
3260         for (s = 0; s < supportSize; ++s) {
3261           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3262           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3263           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3264           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
3265           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
3266           er = GetTriMidEdgeInverse_Static(ornt[c], r);
3267           if (er == eint[c]) {
3268             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
3269           } else {
3270             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
3271             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
3272           }
3273         }
3274         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3275 #if 1
3276         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3277         for (p = 0; p < intFaces; ++p) {
3278           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);
3279         }
3280 #endif
3281       }
3282     }
3283     /* Interior edges have 2 vertices and 4 faces */
3284     for (c = cStart; c < cEnd; ++c) {
3285       const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3286       const PetscInt *cone, *ornt, *fcone;
3287       PetscInt        coneNew[2], supportNew[4], find;
3288 
3289       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3290       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3291       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
3292       find = GetTriEdge_Static(ornt[0], 0);
3293       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3294       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
3295       find = GetTriEdge_Static(ornt[2], 1);
3296       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3297       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3298 #if 1
3299       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3300       for (p = 0; p < 2; ++p) {
3301         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);
3302       }
3303 #endif
3304       supportNew[0] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 4;
3305       supportNew[1] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 5;
3306       supportNew[2] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 6;
3307       supportNew[3] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 7;
3308       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3309 #if 1
3310       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3311       for (p = 0; p < 4; ++p) {
3312         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);
3313       }
3314 #endif
3315     }
3316     /* Old vertices have identical supports */
3317     for (v = vStart; v < vEnd; ++v) {
3318       const PetscInt  newp = vStartNew + (v - vStart);
3319       const PetscInt *support, *cone;
3320       PetscInt        size, s;
3321 
3322       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
3323       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
3324       for (s = 0; s < size; ++s) {
3325         PetscInt r = 0;
3326 
3327         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3328         if (cone[1] == v) r = 1;
3329         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
3330       }
3331       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3332 #if 1
3333       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3334       for (p = 0; p < size; ++p) {
3335         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);
3336       }
3337 #endif
3338     }
3339     /* Edge vertices have 2 + face*2 + 0/1 supports */
3340     for (e = eStart; e < eEnd; ++e) {
3341       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
3342       const PetscInt *cone, *support;
3343       PetscInt       *star = NULL, starSize, cellSize = 0, coneSize, size, s;
3344 
3345       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
3346       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3347       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
3348       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
3349       for (s = 0; s < size; ++s) {
3350         PetscInt r = 0;
3351 
3352         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3353         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3354         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
3355         supportRef[2+s*2+0] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
3356         supportRef[2+s*2+1] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
3357       }
3358       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
3359       for (s = 0; s < starSize*2; s += 2) {
3360         const PetscInt *cone, *ornt;
3361         PetscInt        e01, e23;
3362 
3363         if ((star[s] >= cStart) && (star[s] < cEnd)) {
3364           /* Check edge 0-1 */
3365           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
3366           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
3367           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
3368           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
3369           /* Check edge 2-3 */
3370           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
3371           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
3372           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
3373           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
3374           if ((e01 == e) || (e23 == e)) {supportRef[2+size*2+cellSize++] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (star[s] - cStart);}
3375         }
3376       }
3377       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
3378       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3379 #if 1
3380       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3381       for (p = 0; p < 2+size*2+cellSize; ++p) {
3382         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);
3383       }
3384 #endif
3385     }
3386     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3387     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
3388     break;
3389   case REFINER_HYBRID_SIMPLEX_3D:
3390     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
3391     /* Interior cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
3392     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
3393     for (c = cStart; c < cMax; ++c) {
3394       const PetscInt  newp = cStartNew + (c - cStart)*8;
3395       const PetscInt *cone, *ornt;
3396       PetscInt        coneNew[4], orntNew[4];
3397 
3398       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3399       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3400       /* A tetrahedron: {0, a, c, d} */
3401       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
3402       orntNew[0] = ornt[0];
3403       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
3404       orntNew[1] = ornt[1];
3405       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
3406       orntNew[2] = ornt[2];
3407       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
3408       orntNew[3] = 0;
3409       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3410       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3411 #if 1
3412       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);
3413       for (p = 0; p < 4; ++p) {
3414         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);
3415       }
3416 #endif
3417       /* B tetrahedron: {a, 1, b, e} */
3418       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
3419       orntNew[0] = ornt[0];
3420       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
3421       orntNew[1] = ornt[1];
3422       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
3423       orntNew[2] = 0;
3424       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
3425       orntNew[3] = ornt[3];
3426       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3427       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3428 #if 1
3429       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);
3430       for (p = 0; p < 4; ++p) {
3431         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);
3432       }
3433 #endif
3434       /* C tetrahedron: {c, b, 2, f} */
3435       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
3436       orntNew[0] = ornt[0];
3437       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
3438       orntNew[1] = 0;
3439       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
3440       orntNew[2] = ornt[2];
3441       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
3442       orntNew[3] = ornt[3];
3443       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3444       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3445 #if 1
3446       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);
3447       for (p = 0; p < 4; ++p) {
3448         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);
3449       }
3450 #endif
3451       /* D tetrahedron: {d, e, f, 3} */
3452       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
3453       orntNew[0] = 0;
3454       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
3455       orntNew[1] = ornt[1];
3456       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
3457       orntNew[2] = ornt[2];
3458       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
3459       orntNew[3] = ornt[3];
3460       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3461       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3462 #if 1
3463       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);
3464       for (p = 0; p < 4; ++p) {
3465         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);
3466       }
3467 #endif
3468       /* A' tetrahedron: {d, a, c, f} */
3469       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
3470       orntNew[0] = -3;
3471       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
3472       orntNew[1] = ornt[2] < 0 ? -(GetTriMidEdge_Static(ornt[2], 0)+1) : GetTriMidEdge_Static(ornt[2], 0);
3473       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
3474       orntNew[2] = 0;
3475       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
3476       orntNew[3] = 2;
3477       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
3478       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
3479 #if 1
3480       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);
3481       for (p = 0; p < 4; ++p) {
3482         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);
3483       }
3484 #endif
3485       /* B' tetrahedron: {e, b, a, f} */
3486       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
3487       orntNew[0] = -3;
3488       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
3489       orntNew[1] = 1;
3490       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
3491       orntNew[2] = 0;
3492       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + 3;
3493       orntNew[3] = ornt[3] < 0 ? -(GetTriMidEdge_Static(ornt[3], 0)+1) : GetTriMidEdge_Static(ornt[3], 0);
3494       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
3495       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
3496 #if 1
3497       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);
3498       for (p = 0; p < 4; ++p) {
3499         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);
3500       }
3501 #endif
3502       /* C' tetrahedron: {b, f, c, a} */
3503       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
3504       orntNew[0] = -3;
3505       coneNew[1] = fStartNew + (cone[0] - fStart)*4 + 3;
3506       orntNew[1] = ornt[0] < 0 ? -(GetTriMidEdge_Static(ornt[0], 2)+1) : GetTriMidEdge_Static(ornt[0], 2);
3507       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
3508       orntNew[2] = -3;
3509       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
3510       orntNew[3] = -2;
3511       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
3512       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
3513 #if 1
3514       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);
3515       for (p = 0; p < 4; ++p) {
3516         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);
3517       }
3518 #endif
3519       /* D' tetrahedron: {f, e, d, a} */
3520       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
3521       orntNew[0] = -3;
3522       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
3523       orntNew[1] = -3;
3524       coneNew[2] = fStartNew + (cone[1] - fStart)*4 + 3;
3525       orntNew[2] = ornt[1] < 0 ? -(GetTriMidEdge_Static(ornt[1], 0)+1) : GetTriMidEdge_Static(ornt[1], 0);
3526       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
3527       orntNew[3] = -3;
3528       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
3529       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
3530 #if 1
3531       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);
3532       for (p = 0; p < 4; ++p) {
3533         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);
3534       }
3535 #endif
3536     }
3537     /* Hybrid cells have 5 faces */
3538     for (c = cMax; c < cEnd; ++c) {
3539       const PetscInt  newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4;
3540       const PetscInt *cone, *ornt, *fornt;
3541       PetscInt        coneNew[5], orntNew[5], o, of, i;
3542 
3543       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3544       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3545       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
3546       o = ornt[0] < 0 ? -1 : 1;
3547       for (r = 0; r < 3; ++r) {
3548         coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], r);
3549         orntNew[0] = ornt[0];
3550         coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], r);
3551         orntNew[1] = ornt[1];
3552         of = fornt[GetTriEdge_Static(ornt[0], r)]       < 0 ? -1 : 1;
3553         i  = GetTriEdgeInverse_Static(ornt[0], r)       + 2;
3554         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], r)]       - fMax)*2 + (o*of < 0 ? 1 : 0);
3555         orntNew[i] = 0;
3556         i  = GetTriEdgeInverse_Static(ornt[0], (r+1)%3) + 2;
3557         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + GetTriSubface_Static(ornt[0], r);
3558         orntNew[i] = 0;
3559         of = fornt[GetTriEdge_Static(ornt[0], (r+2)%3)] < 0 ? -1 : 1;
3560         i  = GetTriEdgeInverse_Static(ornt[0], (r+2)%3) + 2;
3561         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);
3562         orntNew[i] = 0;
3563         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
3564         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
3565 #if 1
3566         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);
3567         for (p = 0; p < 2; ++p) {
3568           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);
3569         }
3570         for (p = 2; p < 5; ++p) {
3571           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);
3572         }
3573 #endif
3574       }
3575       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + 3;
3576       orntNew[0] = 0;
3577       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + 3;
3578       orntNew[1] = 0;
3579       coneNew[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
3580       orntNew[2] = 0;
3581       coneNew[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
3582       orntNew[3] = 0;
3583       coneNew[4] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
3584       orntNew[4] = 0;
3585       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3586       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3587 #if 1
3588       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);
3589       for (p = 0; p < 2; ++p) {
3590         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);
3591       }
3592       for (p = 2; p < 5; ++p) {
3593         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);
3594       }
3595 #endif
3596     }
3597     /* Split faces have 3 edges and the same cells as the parent */
3598     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3599     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
3600     for (f = fStart; f < fMax; ++f) {
3601       const PetscInt  newp = fStartNew + (f - fStart)*4;
3602       const PetscInt *cone, *ornt, *support;
3603       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
3604 
3605       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3606       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3607       /* A triangle */
3608       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
3609       orntNew[0] = ornt[0];
3610       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
3611       orntNew[1] = -2;
3612       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
3613       orntNew[2] = ornt[2];
3614       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3615       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3616 #if 1
3617       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);
3618       for (p = 0; p < 3; ++p) {
3619         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);
3620       }
3621 #endif
3622       /* B triangle */
3623       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
3624       orntNew[0] = ornt[0];
3625       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
3626       orntNew[1] = ornt[1];
3627       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
3628       orntNew[2] = -2;
3629       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3630       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3631 #if 1
3632       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);
3633       for (p = 0; p < 3; ++p) {
3634         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);
3635       }
3636 #endif
3637       /* C triangle */
3638       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
3639       orntNew[0] = -2;
3640       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
3641       orntNew[1] = ornt[1];
3642       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
3643       orntNew[2] = ornt[2];
3644       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3645       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3646 #if 1
3647       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);
3648       for (p = 0; p < 3; ++p) {
3649         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);
3650       }
3651 #endif
3652       /* D triangle */
3653       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
3654       orntNew[0] = 0;
3655       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
3656       orntNew[1] = 0;
3657       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
3658       orntNew[2] = 0;
3659       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3660       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3661 #if 1
3662       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);
3663       for (p = 0; p < 3; ++p) {
3664         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);
3665       }
3666 #endif
3667       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3668       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3669       for (r = 0; r < 4; ++r) {
3670         for (s = 0; s < supportSize; ++s) {
3671           PetscInt subf;
3672           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3673           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3674           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3675           for (c = 0; c < coneSize; ++c) {
3676             if (cone[c] == f) break;
3677           }
3678           subf = GetTriSubfaceInverse_Static(ornt[c], r);
3679           if (support[s] < cMax) {
3680             supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
3681           } else {
3682             supportRef[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (r==3 ? r : subf);
3683           }
3684         }
3685         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
3686 #if 1
3687         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);
3688         for (p = 0; p < supportSize; ++p) {
3689           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);
3690         }
3691 #endif
3692       }
3693     }
3694     /* Interior cell faces have 3 edges and 2 cells */
3695     for (c = cStart; c < cMax; ++c) {
3696       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8;
3697       const PetscInt *cone, *ornt;
3698       PetscInt        coneNew[3], orntNew[3];
3699       PetscInt        supportNew[2];
3700 
3701       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3702       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3703       /* Face A: {c, a, d} */
3704       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3705       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3706       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3707       orntNew[1] = ornt[1] < 0 ? -2 : 0;
3708       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 2);
3709       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3710       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3711       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3712 #if 1
3713       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3714       for (p = 0; p < 3; ++p) {
3715         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);
3716       }
3717 #endif
3718       supportNew[0] = (c - cStart)*8 + 0;
3719       supportNew[1] = (c - cStart)*8 + 0+4;
3720       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3721 #if 1
3722       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3723       for (p = 0; p < 2; ++p) {
3724         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);
3725       }
3726 #endif
3727       ++newp;
3728       /* Face B: {a, b, e} */
3729       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3730       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3731       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 0);
3732       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3733       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3734       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3735       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3736       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3737 #if 1
3738       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);
3739       for (p = 0; p < 3; ++p) {
3740         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);
3741       }
3742 #endif
3743       supportNew[0] = (c - cStart)*8 + 1;
3744       supportNew[1] = (c - cStart)*8 + 1+4;
3745       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3746 #if 1
3747       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3748       for (p = 0; p < 2; ++p) {
3749         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);
3750       }
3751 #endif
3752       ++newp;
3753       /* Face C: {c, f, b} */
3754       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3755       orntNew[0] = ornt[2] < 0 ? -2 : 0;
3756       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3757       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3758       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 1);
3759       orntNew[2] = ornt[0] < 0 ? -2 : 0;
3760       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3761       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3762 #if 1
3763       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3764       for (p = 0; p < 3; ++p) {
3765         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);
3766       }
3767 #endif
3768       supportNew[0] = (c - cStart)*8 + 2;
3769       supportNew[1] = (c - cStart)*8 + 2+4;
3770       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3771 #if 1
3772       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3773       for (p = 0; p < 2; ++p) {
3774         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);
3775       }
3776 #endif
3777       ++newp;
3778       /* Face D: {d, e, f} */
3779       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 0);
3780       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3781       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3782       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3783       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3784       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3785       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3786       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3787 #if 1
3788       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3789       for (p = 0; p < 3; ++p) {
3790         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);
3791       }
3792 #endif
3793       supportNew[0] = (c - cStart)*8 + 3;
3794       supportNew[1] = (c - cStart)*8 + 3+4;
3795       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3796 #if 1
3797       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3798       for (p = 0; p < 2; ++p) {
3799         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);
3800       }
3801 #endif
3802       ++newp;
3803       /* Face E: {d, f, a} */
3804       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3805       orntNew[0] = ornt[2] < 0 ? 0 : -2;
3806       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3807       orntNew[1] = -2;
3808       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3809       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3810       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3811       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3812 #if 1
3813       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3814       for (p = 0; p < 3; ++p) {
3815         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);
3816       }
3817 #endif
3818       supportNew[0] = (c - cStart)*8 + 0+4;
3819       supportNew[1] = (c - cStart)*8 + 3+4;
3820       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3821 #if 1
3822       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3823       for (p = 0; p < 2; ++p) {
3824         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);
3825       }
3826 #endif
3827       ++newp;
3828       /* Face F: {c, a, f} */
3829       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3830       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3831       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3832       orntNew[1] = 0;
3833       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3834       orntNew[2] = ornt[2] < 0 ? 0 : -2;
3835       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3836       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3837 #if 1
3838       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3839       for (p = 0; p < 3; ++p) {
3840         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);
3841       }
3842 #endif
3843       supportNew[0] = (c - cStart)*8 + 0+4;
3844       supportNew[1] = (c - cStart)*8 + 2+4;
3845       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3846 #if 1
3847       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3848       for (p = 0; p < 2; ++p) {
3849         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);
3850       }
3851 #endif
3852       ++newp;
3853       /* Face G: {e, a, f} */
3854       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3855       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3856       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3857       orntNew[1] = 0;
3858       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3859       orntNew[2] = ornt[3] < 0 ? 0 : -2;
3860       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3861       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3862 #if 1
3863       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3864       for (p = 0; p < 3; ++p) {
3865         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);
3866       }
3867 #endif
3868       supportNew[0] = (c - cStart)*8 + 1+4;
3869       supportNew[1] = (c - cStart)*8 + 3+4;
3870       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3871 #if 1
3872       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3873       for (p = 0; p < 2; ++p) {
3874         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);
3875       }
3876 #endif
3877       ++newp;
3878       /* Face H: {a, b, f} */
3879       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3880       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3881       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3882       orntNew[1] = ornt[3] < 0 ? 0 : -2;
3883       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3884       orntNew[2] = -2;
3885       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3886       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3887 #if 1
3888       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3889       for (p = 0; p < 3; ++p) {
3890         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);
3891       }
3892 #endif
3893       supportNew[0] = (c - cStart)*8 + 1+4;
3894       supportNew[1] = (c - cStart)*8 + 2+4;
3895       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3896 #if 1
3897       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3898       for (p = 0; p < 2; ++p) {
3899         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);
3900       }
3901 #endif
3902       ++newp;
3903     }
3904     /* Hybrid split faces have 4 edges and same cells */
3905     for (f = fMax; f < fEnd; ++f) {
3906       const PetscInt *cone, *ornt, *support;
3907       PetscInt        coneNew[4], orntNew[4];
3908       PetscInt        supportNew[2], size, s, c;
3909 
3910       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3911       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3912       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3913       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3914       for (r = 0; r < 2; ++r) {
3915         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
3916 
3917         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
3918         orntNew[0]   = ornt[0];
3919         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
3920         orntNew[1]   = ornt[1];
3921         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (cone[2+r] - eMax);
3922         orntNew[2+r] = 0;
3923         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd      - eMax) + (f - fMax);
3924         orntNew[3-r] = 0;
3925         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3926         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3927 #if 1
3928         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
3929         for (p = 0; p < 2; ++p) {
3930           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);
3931         }
3932         for (p = 2; p < 4; ++p) {
3933           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);
3934         }
3935 #endif
3936         for (s = 0; s < size; ++s) {
3937           const PetscInt *coneCell, *orntCell, *fornt;
3938           PetscInt        o, of;
3939 
3940           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
3941           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
3942           o = orntCell[0] < 0 ? -1 : 1;
3943           for (c = 2; c < 5; ++c) if (coneCell[c] == f) break;
3944           if (c >= 5) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
3945           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
3946           of = fornt[c-2] < 0 ? -1 : 1;
3947           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetTriEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%3;
3948         }
3949         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3950 #if 1
3951         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
3952         for (p = 0; p < size; ++p) {
3953           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);
3954         }
3955 #endif
3956       }
3957     }
3958     /* Hybrid cell faces have 4 edges and 2 cells */
3959     for (c = cMax; c < cEnd; ++c) {
3960       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3;
3961       const PetscInt *cone, *ornt;
3962       PetscInt        coneNew[4], orntNew[4];
3963       PetscInt        supportNew[2];
3964 
3965       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3966       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3967       for (r = 0; r < 3; ++r) {
3968         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + (r+2)%3;
3969         orntNew[0] = 0;
3970         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + (r+2)%3;
3971         orntNew[1] = 0;
3972         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+(r+2)%3] - fMax);
3973         orntNew[2] = 0;
3974         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+r]       - fMax);
3975         orntNew[3] = 0;
3976         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
3977         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
3978 #if 1
3979         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);
3980         for (p = 0; p < 2; ++p) {
3981           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);
3982         }
3983         for (p = 2; p < 4; ++p) {
3984           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);
3985         }
3986 #endif
3987         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetTriSubface_Static(ornt[0], r);
3988         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + 3;
3989         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
3990 #if 1
3991         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);
3992         for (p = 0; p < 2; ++p) {
3993           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);
3994         }
3995 #endif
3996       }
3997     }
3998     /* Interior split edges have 2 vertices and the same faces as the parent */
3999     for (e = eStart; e < eMax; ++e) {
4000       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
4001 
4002       for (r = 0; r < 2; ++r) {
4003         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
4004         const PetscInt *cone, *ornt, *support;
4005         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4006 
4007         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4008         coneNew[0]       = vStartNew + (cone[0] - vStart);
4009         coneNew[1]       = vStartNew + (cone[1] - vStart);
4010         coneNew[(r+1)%2] = newv;
4011         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4012 #if 1
4013         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4014         for (p = 0; p < 2; ++p) {
4015           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);
4016         }
4017 #endif
4018         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
4019         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4020         for (s = 0; s < supportSize; ++s) {
4021           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4022           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4023           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4024           for (c = 0; c < coneSize; ++c) if (cone[c] == e) break;
4025           if (support[s] < fMax) {
4026             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
4027           } else {
4028             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
4029           }
4030         }
4031         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4032 #if 1
4033         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4034         for (p = 0; p < supportSize; ++p) {
4035           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);
4036         }
4037 #endif
4038       }
4039     }
4040     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
4041     for (f = fStart; f < fMax; ++f) {
4042       const PetscInt *cone, *ornt, *support;
4043       PetscInt        coneSize, supportSize, s;
4044 
4045       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4046       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4047       for (r = 0; r < 3; ++r) {
4048         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
4049         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
4050         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
4051                                     -1, -1,  1,  6,  0,  4,
4052                                      2,  5,  3,  4, -1, -1,
4053                                     -1, -1,  3,  6,  2,  7};
4054 
4055         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4056         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
4057         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
4058         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4059 #if 1
4060         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4061         for (p = 0; p < 2; ++p) {
4062           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);
4063         }
4064 #endif
4065         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
4066         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
4067         for (s = 0; s < supportSize; ++s) {
4068           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4069           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4070           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4071           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
4072           if (support[s] < cMax) {
4073             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
4074             er = GetTriMidEdgeInverse_Static(ornt[c], r);
4075             if (er == eint[c]) {
4076               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
4077             } else {
4078               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
4079               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
4080             }
4081           } else {
4082             supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (r + 1)%3;
4083           }
4084         }
4085         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4086 #if 1
4087         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4088         for (p = 0; p < intFaces; ++p) {
4089           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);
4090         }
4091 #endif
4092       }
4093     }
4094     /* Interior cell edges have 2 vertices and 4 faces */
4095     for (c = cStart; c < cMax; ++c) {
4096       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4097       const PetscInt *cone, *ornt, *fcone;
4098       PetscInt        coneNew[2], supportNew[4], find;
4099 
4100       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4101       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4102       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
4103       find = GetTriEdge_Static(ornt[0], 0);
4104       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4105       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
4106       find = GetTriEdge_Static(ornt[2], 1);
4107       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4108       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4109 #if 1
4110       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4111       for (p = 0; p < 2; ++p) {
4112         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);
4113       }
4114 #endif
4115       supportNew[0] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 4;
4116       supportNew[1] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 5;
4117       supportNew[2] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 6;
4118       supportNew[3] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 7;
4119       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4120 #if 1
4121       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4122       for (p = 0; p < 4; ++p) {
4123         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);
4124       }
4125 #endif
4126     }
4127     /* Hybrid edges have two vertices and the same faces */
4128     for (e = eMax; e < eEnd; ++e) {
4129       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
4130       const PetscInt *cone, *support, *fcone;
4131       PetscInt        coneNew[2], size, fsize, s;
4132 
4133       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4134       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4135       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4136       coneNew[0] = vStartNew + (cone[0] - vStart);
4137       coneNew[1] = vStartNew + (cone[1] - vStart);
4138       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4139 #if 1
4140       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4141       for (p = 0; p < 2; ++p) {
4142         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);
4143       }
4144 #endif
4145       for (s = 0; s < size; ++s) {
4146         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
4147         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
4148         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
4149         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
4150         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + c-2;
4151       }
4152       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4153 #if 1
4154       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4155       for (p = 0; p < size; ++p) {
4156         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);
4157       }
4158 #endif
4159     }
4160     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
4161     for (f = fMax; f < fEnd; ++f) {
4162       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
4163       const PetscInt *cone, *support, *ccone, *cornt;
4164       PetscInt        coneNew[2], size, csize, s;
4165 
4166       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4167       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4168       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4169       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
4170       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
4171       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4172 #if 1
4173       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4174       for (p = 0; p < 2; ++p) {
4175         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);
4176       }
4177 #endif
4178       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 0;
4179       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 1;
4180       for (s = 0; s < size; ++s) {
4181         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
4182         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
4183         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
4184         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
4185         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]);
4186         supportRef[2+s*2+0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + c-2;
4187         supportRef[2+s*2+1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (c-1)%3;
4188       }
4189       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4190 #if 1
4191       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4192       for (p = 0; p < 2+size*2; ++p) {
4193         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);
4194       }
4195 #endif
4196     }
4197     /* Interior vertices have identical supports */
4198     for (v = vStart; v < vEnd; ++v) {
4199       const PetscInt  newp = vStartNew + (v - vStart);
4200       const PetscInt *support, *cone;
4201       PetscInt        size, s;
4202 
4203       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4204       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4205       for (s = 0; s < size; ++s) {
4206         PetscInt r = 0;
4207 
4208         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4209         if (cone[1] == v) r = 1;
4210         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4211         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (support[s] - eMax);
4212       }
4213       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4214 #if 1
4215       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4216       for (p = 0; p < size; ++p) {
4217         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);
4218       }
4219 #endif
4220     }
4221     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
4222     for (e = eStart; e < eMax; ++e) {
4223       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4224       const PetscInt *cone, *support;
4225       PetscInt       *star = NULL, starSize, faceSize = 0, cellSize = 0, coneSize, size, s;
4226 
4227       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4228       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4229       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4230       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4231       for (s = 0; s < size; ++s) {
4232         PetscInt r = 0;
4233 
4234         if (support[s] < fMax) {
4235           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4236           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4237           for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
4238           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
4239           supportRef[2+faceSize+1] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
4240           faceSize += 2;
4241         } else {
4242           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (support[s] - fMax);
4243           ++faceSize;
4244         }
4245       }
4246       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4247       for (s = 0; s < starSize*2; s += 2) {
4248         const PetscInt *cone, *ornt;
4249         PetscInt        e01, e23;
4250 
4251         if ((star[s] >= cStart) && (star[s] < cMax)) {
4252           /* Check edge 0-1 */
4253           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
4254           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
4255           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
4256           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
4257           /* Check edge 2-3 */
4258           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
4259           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
4260           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
4261           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
4262           if ((e01 == e) || (e23 == e)) {supportRef[2+faceSize+cellSize++] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (star[s] - cStart);}
4263         }
4264       }
4265       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4266       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4267 #if 1
4268       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4269       for (p = 0; p < 2+faceSize+cellSize; ++p) {
4270         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);
4271       }
4272 #endif
4273     }
4274     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4275     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
4276     break;
4277   case REFINER_SIMPLEX_TO_HEX_3D:
4278     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
4279     /* All cells have 6 faces */
4280     for (c = cStart; c < cEnd; ++c) {
4281       const PetscInt  newp = cStartNew + (c - cStart)*4;
4282       const PetscInt *cone, *ornt;
4283       PetscInt        coneNew[6];
4284       PetscInt        orntNew[6];
4285 
4286       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4287       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4288       /* A hex */
4289       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 0); /* B */
4290       orntNew[0] = ornt[0] < 0 ? -1 : 1;
4291       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 3;               /* T */
4292       orntNew[1] = -4;
4293       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 0); /* F */
4294       orntNew[2] = ornt[2] < 0 ? -1 : 1;
4295       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 0;               /* K */
4296       orntNew[3] = -1;
4297       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 2;               /* R */
4298       orntNew[4] = 0;
4299       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 0); /* L */
4300       orntNew[5] = ornt[1] < 0 ? -1 : 1;
4301       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4302       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4303 #if 1
4304       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);
4305       for (p = 0; p < 6; ++p) {
4306         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);
4307       }
4308 #endif
4309       /* B hex */
4310       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 1); /* B */
4311       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4312       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 4;               /* T */
4313       orntNew[1] = 0;
4314       coneNew[2] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 0;               /* F */
4315       orntNew[2] = 0;
4316       coneNew[3] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 1); /* K */
4317       orntNew[3] = ornt[3] < 0 ? -2 : 0;
4318       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 1;               /* R */
4319       orntNew[4] = 0;
4320       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 2); /* L */
4321       orntNew[5] = ornt[1] < 0 ? -4 : 2;
4322       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4323       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4324 #if 1
4325       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);
4326       for (p = 0; p < 6; ++p) {
4327         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);
4328       }
4329 #endif
4330       /* C hex */
4331       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 2); /* B */
4332       orntNew[0] = ornt[0] < 0 ? -4 : 2;
4333       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 5;               /* T */
4334       orntNew[1] = -4;
4335       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 1); /* F */
4336       orntNew[2] = ornt[2] < 0 ? -2 : 0;
4337       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 1;               /* K */
4338       orntNew[3] = -1;
4339       coneNew[4] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 0); /* R */
4340       orntNew[4] = ornt[3] < 0 ? -1 : 1;
4341       coneNew[5] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 2;               /* L */
4342       orntNew[5] = -4;
4343       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4344       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4345 #if 1
4346       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);
4347       for (p = 0; p < 6; ++p) {
4348         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);
4349       }
4350 #endif
4351       /* D hex */
4352       coneNew[0] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 3;               /* B */
4353       orntNew[0] = 0;
4354       coneNew[1] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 2); /* T */
4355       orntNew[1] = ornt[3] < 0 ? -1 : 1;
4356       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 2); /* F */
4357       orntNew[2] = ornt[2] < 0 ? -4 : 2;
4358       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 4;               /* K */
4359       orntNew[3] = -1;
4360       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 5;               /* R */
4361       orntNew[4] = 0;
4362       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 1); /* L */
4363       orntNew[5] = ornt[1] < 0 ? -2 : 0;
4364       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4365       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4366 #if 1
4367       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);
4368       for (p = 0; p < 6; ++p) {
4369         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);
4370       }
4371 #endif
4372     }
4373     /* Split faces have 4 edges and the same cells as the parent */
4374     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4375     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
4376     for (f = fStart; f < fEnd; ++f) {
4377       const PetscInt  newp = fStartNew + (f - fStart)*3;
4378       const PetscInt *cone, *ornt, *support;
4379       PetscInt        coneNew[4], orntNew[4], coneSize, supportSize, s;
4380 
4381       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4382       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4383       /* A quad */
4384       coneNew[0] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
4385       orntNew[0] = ornt[2];
4386       coneNew[1] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
4387       orntNew[1] = ornt[0];
4388       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
4389       orntNew[2] = 0;
4390       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
4391       orntNew[3] = -2;
4392       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4393       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4394 #if 1
4395       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);
4396       for (p = 0; p < 4; ++p) {
4397         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);
4398       }
4399 #endif
4400       /* B quad */
4401       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
4402       orntNew[0] = ornt[0];
4403       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
4404       orntNew[1] = ornt[1];
4405       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
4406       orntNew[2] = 0;
4407       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
4408       orntNew[3] = -2;
4409       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4410       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4411 #if 1
4412       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);
4413       for (p = 0; p < 4; ++p) {
4414         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);
4415       }
4416 #endif
4417       /* C quad */
4418       coneNew[0] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
4419       orntNew[0] = ornt[1];
4420       coneNew[1] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
4421       orntNew[1] = ornt[2];
4422       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
4423       orntNew[2] = 0;
4424       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
4425       orntNew[3] = -2;
4426       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4427       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4428 #if 1
4429       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);
4430       for (p = 0; p < 4; ++p) {
4431         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);
4432       }
4433 #endif
4434       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4435       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4436       for (r = 0; r < 3; ++r) {
4437         for (s = 0; s < supportSize; ++s) {
4438           PetscInt subf;
4439           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4440           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4441           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4442           for (c = 0; c < coneSize; ++c) {
4443             if (cone[c] == f) break;
4444           }
4445           subf = GetTriSubfaceInverse_Static(ornt[c], r);
4446           supportRef[s] = cStartNew + (support[s] - cStart)*4 + faces[c*3+subf];
4447         }
4448         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
4449 #if 1
4450         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);
4451         for (p = 0; p < supportSize; ++p) {
4452           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);
4453         }
4454 #endif
4455       }
4456     }
4457     /* Interior faces have 4 edges and 2 cells */
4458     for (c = cStart; c < cEnd; ++c) {
4459       PetscInt        newp = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6;
4460       const PetscInt *cone, *ornt;
4461       PetscInt        coneNew[4], orntNew[4];
4462       PetscInt        supportNew[2];
4463 
4464       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4465       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4466       /* Face {a, g, m, h} */
4467       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],0);
4468       orntNew[0] = 0;
4469       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
4470       orntNew[1] = 0;
4471       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
4472       orntNew[2] = -2;
4473       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],2);
4474       orntNew[3] = -2;
4475       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4476       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4477 #if 1
4478       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4479       for (p = 0; p < 4; ++p) {
4480         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);
4481       }
4482 #endif
4483       supportNew[0] = (c - cStart)*4 + 0;
4484       supportNew[1] = (c - cStart)*4 + 1;
4485       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4486 #if 1
4487       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4488       for (p = 0; p < 2; ++p) {
4489         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);
4490       }
4491 #endif
4492       ++newp;
4493       /* Face {g, b, l , m} */
4494       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],1);
4495       orntNew[0] = -2;
4496       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],0);
4497       orntNew[1] = 0;
4498       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
4499       orntNew[2] = 0;
4500       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
4501       orntNew[3] = -2;
4502       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4503       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4504 #if 1
4505       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4506       for (p = 0; p < 4; ++p) {
4507         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);
4508       }
4509 #endif
4510       supportNew[0] = (c - cStart)*4 + 1;
4511       supportNew[1] = (c - cStart)*4 + 2;
4512       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4513 #if 1
4514       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4515       for (p = 0; p < 2; ++p) {
4516         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);
4517       }
4518 #endif
4519       ++newp;
4520       /* Face {c, g, m, i} */
4521       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],2);
4522       orntNew[0] = 0;
4523       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
4524       orntNew[1] = 0;
4525       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
4526       orntNew[2] = -2;
4527       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],0);
4528       orntNew[3] = -2;
4529       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4530       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4531 #if 1
4532       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4533       for (p = 0; p < 4; ++p) {
4534         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);
4535       }
4536 #endif
4537       supportNew[0] = (c - cStart)*4 + 0;
4538       supportNew[1] = (c - cStart)*4 + 2;
4539       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4540 #if 1
4541       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4542       for (p = 0; p < 2; ++p) {
4543         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);
4544       }
4545 #endif
4546       ++newp;
4547       /* Face {d, h, m, i} */
4548       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],0);
4549       orntNew[0] = 0;
4550       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
4551       orntNew[1] = 0;
4552       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
4553       orntNew[2] = -2;
4554       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],2);
4555       orntNew[3] = -2;
4556       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4557       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4558 #if 1
4559       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4560       for (p = 0; p < 4; ++p) {
4561         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);
4562       }
4563 #endif
4564       supportNew[0] = (c - cStart)*4 + 0;
4565       supportNew[1] = (c - cStart)*4 + 3;
4566       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4567 #if 1
4568       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4569       for (p = 0; p < 2; ++p) {
4570         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);
4571       }
4572 #endif
4573       ++newp;
4574       /* Face {h, m, l, e} */
4575       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
4576       orntNew[0] = 0;
4577       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
4578       orntNew[1] = -2;
4579       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],1);
4580       orntNew[2] = -2;
4581       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],1);
4582       orntNew[3] = 0;
4583       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4584       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4585 #if 1
4586       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4587       for (p = 0; p < 4; ++p) {
4588         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);
4589       }
4590 #endif
4591       supportNew[0] = (c - cStart)*4 + 1;
4592       supportNew[1] = (c - cStart)*4 + 3;
4593       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4594 #if 1
4595       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4596       for (p = 0; p < 2; ++p) {
4597         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);
4598       }
4599 #endif
4600       ++newp;
4601       /* Face {i, m, l, f} */
4602       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
4603       orntNew[0] = 0;
4604       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
4605       orntNew[1] = -2;
4606       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],2);
4607       orntNew[2] = -2;
4608       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],1);
4609       orntNew[3] = 0;
4610       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4611       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4612 #if 1
4613       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4614       for (p = 0; p < 4; ++p) {
4615         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);
4616       }
4617 #endif
4618       supportNew[0] = (c - cStart)*4 + 2;
4619       supportNew[1] = (c - cStart)*4 + 3;
4620       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4621 #if 1
4622       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4623       for (p = 0; p < 2; ++p) {
4624         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);
4625       }
4626 #endif
4627       ++newp;
4628     }
4629     /* Split Edges have 2 vertices and the same faces as the parent */
4630     for (e = eStart; e < eEnd; ++e) {
4631       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
4632 
4633       for (r = 0; r < 2; ++r) {
4634         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
4635         const PetscInt *cone, *ornt, *support;
4636         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4637 
4638         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4639         coneNew[0]       = vStartNew + (cone[0] - vStart);
4640         coneNew[1]       = vStartNew + (cone[1] - vStart);
4641         coneNew[(r+1)%2] = newv;
4642         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4643 #if 1
4644         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4645         for (p = 0; p < 2; ++p) {
4646           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);
4647         }
4648 #endif
4649         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
4650         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4651         for (s = 0; s < supportSize; ++s) {
4652           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4653           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4654           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4655           for (c = 0; c < coneSize; ++c) {
4656             if (cone[c] == e) break;
4657           }
4658           supportRef[s] = fStartNew + (support[s] - fStart)*3 + (c + (ornt[c] < 0 ? 1-r : r))%3;
4659         }
4660         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4661 #if 1
4662         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4663         for (p = 0; p < supportSize; ++p) {
4664           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);
4665         }
4666 #endif
4667       }
4668     }
4669     /* Face edges have 2 vertices and 2 + cell faces supports */
4670     for (f = fStart; f < fEnd; ++f) {
4671       const PetscInt *cone, *ornt, *support;
4672       PetscInt        coneSize, supportSize, s;
4673 
4674       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4675       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4676       for (r = 0; r < 3; ++r) {
4677         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
4678         PetscInt        coneNew[2];
4679         PetscInt        fint[4][3] = { {0, 1, 2},
4680                                        {3, 4, 0},
4681                                        {2, 5, 3},
4682                                        {1, 4, 5} };
4683 
4684         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4685         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
4686         coneNew[1] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + f - fStart;
4687         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4688 #if 1
4689         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4690         for (p = 0; p < 2; ++p) {
4691           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);
4692         }
4693 #endif
4694         supportRef[0] = fStartNew + (f - fStart)*3 + (r+0)%3;
4695         supportRef[1] = fStartNew + (f - fStart)*3 + (r+1)%3;
4696         for (s = 0; s < supportSize; ++s) {
4697           PetscInt er;
4698           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4699           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4700           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4701           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
4702           er = GetTriInteriorEdgeInverse_Static(ornt[c], r);
4703           supportRef[2+s] = fStartNew + (fEnd - fStart)*3 + (support[s] - cStart)*6 + fint[c][er];
4704         }
4705         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4706 #if 1
4707         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4708         for (p = 0; p < supportSize + 2; ++p) {
4709           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);
4710         }
4711 #endif
4712       }
4713     }
4714     /* Interior cell edges have 2 vertices and 3 faces */
4715     for (c = cStart; c < cEnd; ++c) {
4716       const PetscInt *cone;
4717       PetscInt       fint[4][3] = { {0,1,2},
4718                                     {0,3,4},
4719                                     {2,3,5},
4720                                     {1,4,5} } ;
4721 
4722       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4723       for (r = 0; r < 4; r++) {
4724         PetscInt       coneNew[2], supportNew[3];
4725         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + r;
4726 
4727         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
4728         coneNew[1] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd -fStart) + c - cStart;
4729         ierr = DMPlexSetCone(rdm, newp, coneNew);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 < 2; ++p) {
4733           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);
4734         }
4735 #endif
4736         supportNew[0] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][0];
4737         supportNew[1] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][1];
4738         supportNew[2] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][2];
4739         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4740 #if 1
4741         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4742         for (p = 0; p < 3; ++p) {
4743           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);
4744         }
4745 #endif
4746       }
4747     }
4748     /* Old vertices have identical supports */
4749     for (v = vStart; v < vEnd; ++v) {
4750       const PetscInt  newp = vStartNew + (v - vStart);
4751       const PetscInt *support, *cone;
4752       PetscInt        size, s;
4753 
4754       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4755       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4756       for (s = 0; s < size; ++s) {
4757         PetscInt r = 0;
4758 
4759         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4760         if (cone[1] == v) r = 1;
4761         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4762       }
4763       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4764 #if 1
4765       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4766       for (p = 0; p < size; ++p) {
4767         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);
4768       }
4769 #endif
4770     }
4771     /* Edge vertices have 2 + faces supports */
4772     for (e = eStart; e < eEnd; ++e) {
4773       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4774       const PetscInt *cone, *support;
4775       PetscInt        size, s;
4776 
4777       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4778       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4779       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4780       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4781       for (s = 0; s < size; ++s) {
4782         PetscInt r = 0, coneSize;
4783 
4784         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4785         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4786         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
4787         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + r;
4788       }
4789       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4790 #if 1
4791       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4792       for (p = 0; p < 2+size; ++p) {
4793         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);
4794       }
4795 #endif
4796     }
4797     /* Face vertices have 3 + cells supports */
4798     for (f = fStart; f < fEnd; ++f) {
4799       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
4800       const PetscInt *cone, *support;
4801       PetscInt        size, s;
4802 
4803       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4804       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4805       supportRef[0] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 0;
4806       supportRef[1] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 1;
4807       supportRef[2] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 2;
4808       for (s = 0; s < size; ++s) {
4809         PetscInt r = 0, coneSize;
4810 
4811         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4812         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4813         for (r = 0; r < coneSize; ++r) {if (cone[r] == f) break;}
4814         supportRef[3+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (support[s] - cStart)*4 + r;
4815       }
4816       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4817 #if 1
4818       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4819       for (p = 0; p < 3+size; ++p) {
4820         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);
4821       }
4822 #endif
4823     }
4824     /* Interior cell vertices have 4 supports */
4825     for (c = cStart; c < cEnd; ++c) {
4826       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + c - cStart;
4827       supportRef[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
4828       supportRef[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
4829       supportRef[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
4830       supportRef[3] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
4831       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4832 #if 1
4833       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4834       for (p = 0; p < 4; ++p) {
4835         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);
4836       }
4837 #endif
4838     }
4839     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4840     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
4841     break;
4842   case REFINER_HEX_3D:
4843     /*
4844      Bottom (viewed from top)    Top
4845      1---------2---------2       7---------2---------6
4846      |         |         |       |         |         |
4847      |    B    2    C    |       |    H    2    G    |
4848      |         |         |       |         |         |
4849      3----3----0----1----1       3----3----0----1----1
4850      |         |         |       |         |         |
4851      |    A    0    D    |       |    E    0    F    |
4852      |         |         |       |         |         |
4853      0---------0---------3       4---------0---------5
4854      */
4855     /* All cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
4856     for (c = cStart; c < cEnd; ++c) {
4857       const PetscInt  newp = (c - cStart)*8;
4858       const PetscInt *cone, *ornt;
4859       PetscInt        coneNew[6], orntNew[6];
4860 
4861       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4862       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4863       /* A hex */
4864       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
4865       orntNew[0] = ornt[0];
4866       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
4867       orntNew[1] = 0;
4868       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
4869       orntNew[2] = ornt[2];
4870       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
4871       orntNew[3] = 0;
4872       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
4873       orntNew[4] = 0;
4874       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
4875       orntNew[5] = ornt[5];
4876       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4877       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4878 #if 1
4879       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);
4880       for (p = 0; p < 6; ++p) {
4881         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);
4882       }
4883 #endif
4884       /* B hex */
4885       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
4886       orntNew[0] = ornt[0];
4887       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
4888       orntNew[1] = 0;
4889       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
4890       orntNew[2] = -1;
4891       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
4892       orntNew[3] = ornt[3];
4893       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
4894       orntNew[4] = 0;
4895       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
4896       orntNew[5] = ornt[5];
4897       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4898       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4899 #if 1
4900       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);
4901       for (p = 0; p < 6; ++p) {
4902         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);
4903       }
4904 #endif
4905       /* C hex */
4906       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
4907       orntNew[0] = ornt[0];
4908       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
4909       orntNew[1] = 0;
4910       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
4911       orntNew[2] = -1;
4912       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
4913       orntNew[3] = ornt[3];
4914       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
4915       orntNew[4] = ornt[4];
4916       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
4917       orntNew[5] = -4;
4918       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4919       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4920 #if 1
4921       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);
4922       for (p = 0; p < 6; ++p) {
4923         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);
4924       }
4925 #endif
4926       /* D hex */
4927       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
4928       orntNew[0] = ornt[0];
4929       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
4930       orntNew[1] = 0;
4931       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
4932       orntNew[2] = ornt[2];
4933       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
4934       orntNew[3] = 0;
4935       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
4936       orntNew[4] = ornt[4];
4937       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
4938       orntNew[5] = -4;
4939       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4940       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4941 #if 1
4942       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);
4943       for (p = 0; p < 6; ++p) {
4944         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);
4945       }
4946 #endif
4947       /* E hex */
4948       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
4949       orntNew[0] = -4;
4950       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
4951       orntNew[1] = ornt[1];
4952       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
4953       orntNew[2] = ornt[2];
4954       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
4955       orntNew[3] = 0;
4956       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
4957       orntNew[4] = -1;
4958       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
4959       orntNew[5] = ornt[5];
4960       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
4961       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
4962 #if 1
4963       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);
4964       for (p = 0; p < 6; ++p) {
4965         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);
4966       }
4967 #endif
4968       /* F hex */
4969       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
4970       orntNew[0] = -4;
4971       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
4972       orntNew[1] = ornt[1];
4973       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
4974       orntNew[2] = ornt[2];
4975       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4976       orntNew[3] = -1;
4977       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
4978       orntNew[4] = ornt[4];
4979       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
4980       orntNew[5] = 1;
4981       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
4982       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
4983 #if 1
4984       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);
4985       for (p = 0; p < 6; ++p) {
4986         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);
4987       }
4988 #endif
4989       /* G hex */
4990       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
4991       orntNew[0] = -4;
4992       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
4993       orntNew[1] = ornt[1];
4994       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4995       orntNew[2] = 0;
4996       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
4997       orntNew[3] = ornt[3];
4998       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
4999       orntNew[4] = ornt[4];
5000       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
5001       orntNew[5] = -3;
5002       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
5003       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
5004 #if 1
5005       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);
5006       for (p = 0; p < 6; ++p) {
5007         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);
5008       }
5009 #endif
5010       /* H hex */
5011       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
5012       orntNew[0] = -4;
5013       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
5014       orntNew[1] = ornt[1];
5015       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
5016       orntNew[2] = -1;
5017       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
5018       orntNew[3] = ornt[3];
5019       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
5020       orntNew[4] = 3;
5021       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
5022       orntNew[5] = ornt[5];
5023       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
5024       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
5025 #if 1
5026       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);
5027       for (p = 0; p < 6; ++p) {
5028         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);
5029       }
5030 #endif
5031     }
5032     /* Split faces have 4 edges and the same cells as the parent */
5033     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5034     ierr = PetscMalloc1(4 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
5035     for (f = fStart; f < fEnd; ++f) {
5036       for (r = 0; r < 4; ++r) {
5037         /* TODO: This can come from GetFaces_Internal() */
5038         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};
5039         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
5040         const PetscInt *cone, *ornt, *support;
5041         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
5042 
5043         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5044         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
5045         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
5046         orntNew[(r+3)%4] = ornt[(r+3)%4];
5047         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
5048         orntNew[(r+0)%4] = ornt[r];
5049         coneNew[(r+1)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
5050         orntNew[(r+1)%4] = 0;
5051         coneNew[(r+2)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + (r+3)%4;
5052         orntNew[(r+2)%4] = -2;
5053         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5054         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5055 #if 1
5056         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5057         for (p = 0; p < 4; ++p) {
5058           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);
5059         }
5060 #endif
5061         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5062         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5063         for (s = 0; s < supportSize; ++s) {
5064           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5065           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5066           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5067           for (c = 0; c < coneSize; ++c) {
5068             if (cone[c] == f) break;
5069           }
5070           supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+GetQuadSubfaceInverse_Static(ornt[c], r)];
5071         }
5072         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5073 #if 1
5074         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5075         for (p = 0; p < supportSize; ++p) {
5076           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);
5077         }
5078 #endif
5079       }
5080     }
5081     /* Interior faces have 4 edges and 2 cells */
5082     for (c = cStart; c < cEnd; ++c) {
5083       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};
5084       const PetscInt *cone, *ornt;
5085       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
5086 
5087       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5088       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5089       /* A-D face */
5090       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 0;
5091       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
5092       orntNew[0] = 0;
5093       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
5094       orntNew[1] = 0;
5095       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
5096       orntNew[2] = -2;
5097       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
5098       orntNew[3] = -2;
5099       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5100       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5101 #if 1
5102       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5103       for (p = 0; p < 4; ++p) {
5104         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);
5105       }
5106 #endif
5107       /* C-D face */
5108       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 1;
5109       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
5110       orntNew[0] = 0;
5111       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
5112       orntNew[1] = 0;
5113       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
5114       orntNew[2] = -2;
5115       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
5116       orntNew[3] = -2;
5117       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5118       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5119 #if 1
5120       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5121       for (p = 0; p < 4; ++p) {
5122         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);
5123       }
5124 #endif
5125       /* B-C face */
5126       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 2;
5127       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
5128       orntNew[0] = -2;
5129       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
5130       orntNew[1] = 0;
5131       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
5132       orntNew[2] = 0;
5133       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
5134       orntNew[3] = -2;
5135       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5136       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5137 #if 1
5138       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5139       for (p = 0; p < 4; ++p) {
5140         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);
5141       }
5142 #endif
5143       /* A-B face */
5144       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 3;
5145       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
5146       orntNew[0] = -2;
5147       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
5148       orntNew[1] = 0;
5149       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
5150       orntNew[2] = 0;
5151       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
5152       orntNew[3] = -2;
5153       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5154       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5155 #if 1
5156       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5157       for (p = 0; p < 4; ++p) {
5158         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);
5159       }
5160 #endif
5161       /* E-F face */
5162       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 4;
5163       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
5164       orntNew[0] = -2;
5165       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
5166       orntNew[1] = -2;
5167       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
5168       orntNew[2] = 0;
5169       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
5170       orntNew[3] = 0;
5171       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5172       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5173 #if 1
5174       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5175       for (p = 0; p < 4; ++p) {
5176         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);
5177       }
5178 #endif
5179       /* F-G face */
5180       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 5;
5181       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
5182       orntNew[0] = -2;
5183       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
5184       orntNew[1] = -2;
5185       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
5186       orntNew[2] = 0;
5187       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
5188       orntNew[3] = 0;
5189       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5190       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5191 #if 1
5192       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5193       for (p = 0; p < 4; ++p) {
5194         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);
5195       }
5196 #endif
5197       /* G-H face */
5198       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 6;
5199       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
5200       orntNew[0] = -2;
5201       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
5202       orntNew[1] = 0;
5203       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
5204       orntNew[2] = 0;
5205       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
5206       orntNew[3] = -2;
5207       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5208       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5209 #if 1
5210       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5211       for (p = 0; p < 4; ++p) {
5212         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);
5213       }
5214 #endif
5215       /* E-H face */
5216       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 7;
5217       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
5218       orntNew[0] = -2;
5219       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
5220       orntNew[1] = -2;
5221       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
5222       orntNew[2] = 0;
5223       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
5224       orntNew[3] = 0;
5225       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5226       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5227 #if 1
5228       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5229       for (p = 0; p < 4; ++p) {
5230         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);
5231       }
5232 #endif
5233       /* A-E face */
5234       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 8;
5235       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
5236       orntNew[0] = 0;
5237       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
5238       orntNew[1] = 0;
5239       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
5240       orntNew[2] = -2;
5241       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
5242       orntNew[3] = -2;
5243       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5244       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5245 #if 1
5246       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5247       for (p = 0; p < 4; ++p) {
5248         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);
5249       }
5250 #endif
5251       /* D-F face */
5252       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 9;
5253       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
5254       orntNew[0] = -2;
5255       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
5256       orntNew[1] = 0;
5257       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
5258       orntNew[2] = 0;
5259       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
5260       orntNew[3] = -2;
5261       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5262       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5263 #if 1
5264       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5265       for (p = 0; p < 4; ++p) {
5266         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);
5267       }
5268 #endif
5269       /* C-G face */
5270       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 10;
5271       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
5272       orntNew[0] = -2;
5273       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
5274       orntNew[1] = -2;
5275       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
5276       orntNew[2] = 0;
5277       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
5278       orntNew[3] = 0;
5279       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5280       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5281 #if 1
5282       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5283       for (p = 0; p < 4; ++p) {
5284         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);
5285       }
5286 #endif
5287       /* B-H face */
5288       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 11;
5289       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
5290       orntNew[0] = 0;
5291       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
5292       orntNew[1] = -2;
5293       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
5294       orntNew[2] = -2;
5295       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
5296       orntNew[3] = 0;
5297       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5298       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5299 #if 1
5300       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5301       for (p = 0; p < 4; ++p) {
5302         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);
5303       }
5304 #endif
5305       for (r = 0; r < 12; ++r) {
5306         newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
5307         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
5308         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
5309         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5310 #if 1
5311         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5312         for (p = 0; p < 2; ++p) {
5313           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);
5314         }
5315 #endif
5316       }
5317     }
5318     /* Split edges have 2 vertices and the same faces as the parent */
5319     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5320     for (e = eStart; e < eEnd; ++e) {
5321       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
5322 
5323       for (r = 0; r < 2; ++r) {
5324         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
5325         const PetscInt *cone, *ornt, *support;
5326         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5327 
5328         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
5329         coneNew[0]       = vStartNew + (cone[0] - vStart);
5330         coneNew[1]       = vStartNew + (cone[1] - vStart);
5331         coneNew[(r+1)%2] = newv;
5332         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5333 #if 1
5334         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5335         for (p = 0; p < 2; ++p) {
5336           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);
5337         }
5338 #endif
5339         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
5340         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5341         for (s = 0; s < supportSize; ++s) {
5342           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5343           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5344           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5345           for (c = 0; c < coneSize; ++c) {
5346             if (cone[c] == e) break;
5347           }
5348           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
5349         }
5350         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5351 #if 1
5352         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5353         for (p = 0; p < supportSize; ++p) {
5354           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);
5355         }
5356 #endif
5357       }
5358     }
5359     /* Face edges have 2 vertices and 2+cells faces */
5360     for (f = fStart; f < fEnd; ++f) {
5361       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};
5362       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
5363       const PetscInt *cone, *coneCell, *orntCell, *support;
5364       PetscInt        coneNew[2], coneSize, c, supportSize, s;
5365 
5366       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5367       for (r = 0; r < 4; ++r) {
5368         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
5369 
5370         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
5371         coneNew[1] = newv;
5372         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5373 #if 1
5374         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5375         for (p = 0; p < 2; ++p) {
5376           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);
5377         }
5378 #endif
5379         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5380         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5381         supportRef[0] = fStartNew + (f - fStart)*4 + r;
5382         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
5383         for (s = 0; s < supportSize; ++s) {
5384           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5385           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
5386           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
5387           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
5388           supportRef[2+s] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
5389         }
5390         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5391 #if 1
5392         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5393         for (p = 0; p < 2+supportSize; ++p) {
5394           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);
5395         }
5396 #endif
5397       }
5398     }
5399     /* Cell edges have 2 vertices and 4 faces */
5400     for (c = cStart; c < cEnd; ++c) {
5401       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};
5402       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
5403       const PetscInt *cone;
5404       PetscInt        coneNew[2], supportNew[4];
5405 
5406       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5407       for (r = 0; r < 6; ++r) {
5408         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
5409 
5410         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
5411         coneNew[1] = newv;
5412         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5413 #if 1
5414         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5415         for (p = 0; p < 2; ++p) {
5416           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);
5417         }
5418 #endif
5419         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
5420         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5421 #if 1
5422         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5423         for (p = 0; p < 4; ++p) {
5424           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);
5425         }
5426 #endif
5427       }
5428     }
5429     /* Old vertices have identical supports */
5430     for (v = vStart; v < vEnd; ++v) {
5431       const PetscInt  newp = vStartNew + (v - vStart);
5432       const PetscInt *support, *cone;
5433       PetscInt        size, s;
5434 
5435       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5436       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5437       for (s = 0; s < size; ++s) {
5438         PetscInt r = 0;
5439 
5440         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5441         if (cone[1] == v) r = 1;
5442         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
5443       }
5444       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5445 #if 1
5446       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5447       for (p = 0; p < size; ++p) {
5448         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);
5449       }
5450 #endif
5451     }
5452     /* Edge vertices have 2 + faces supports */
5453     for (e = eStart; e < eEnd; ++e) {
5454       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
5455       const PetscInt *cone, *support;
5456       PetscInt        size, s;
5457 
5458       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
5459       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5460       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
5461       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
5462       for (s = 0; s < size; ++s) {
5463         PetscInt r;
5464 
5465         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5466         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
5467         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*4 + r;
5468       }
5469       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5470 #if 1
5471       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5472       for (p = 0; p < 2+size; ++p) {
5473         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);
5474       }
5475 #endif
5476     }
5477     /* Face vertices have 4 + cells supports */
5478     for (f = fStart; f < fEnd; ++f) {
5479       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
5480       const PetscInt *cone, *support;
5481       PetscInt        size, s;
5482 
5483       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5484       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5485       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eEnd - eStart)*2 +  (f - fStart)*4 + r;
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 < 6; ++r) if (cone[r] == f) break;
5491         supportRef[4+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (support[s] - cStart)*6 + 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 < 4+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     /* Cell vertices have 6 supports */
5502     for (c = cStart; c < cEnd; ++c) {
5503       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
5504       PetscInt       supportNew[6];
5505 
5506       for (r = 0; r < 6; ++r) {
5507         supportNew[r] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
5508       }
5509       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5510     }
5511     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5512     break;
5513   case REFINER_HYBRID_HEX_3D:
5514     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
5515     /*
5516      Bottom (viewed from top)    Top
5517      1---------2---------2       7---------2---------6
5518      |         |         |       |         |         |
5519      |    B    2    C    |       |    H    2    G    |
5520      |         |         |       |         |         |
5521      3----3----0----1----1       3----3----0----1----1
5522      |         |         |       |         |         |
5523      |    A    0    D    |       |    E    0    F    |
5524      |         |         |       |         |         |
5525      0---------0---------3       4---------0---------5
5526      */
5527     /* Interior cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
5528     for (c = cStart; c < cMax; ++c) {
5529       const PetscInt  newp = (c - cStart)*8;
5530       const PetscInt *cone, *ornt;
5531       PetscInt        coneNew[6], orntNew[6];
5532 
5533       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5534       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5535       /* A hex */
5536       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
5537       orntNew[0] = ornt[0];
5538       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
5539       orntNew[1] = 0;
5540       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
5541       orntNew[2] = ornt[2];
5542       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
5543       orntNew[3] = 0;
5544       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
5545       orntNew[4] = 0;
5546       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
5547       orntNew[5] = ornt[5];
5548       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5549       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5550 #if 1
5551       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);
5552       for (p = 0; p < 6; ++p) {
5553         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);
5554       }
5555 #endif
5556       /* B hex */
5557       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
5558       orntNew[0] = ornt[0];
5559       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
5560       orntNew[1] = 0;
5561       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
5562       orntNew[2] = -1;
5563       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
5564       orntNew[3] = ornt[3];
5565       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
5566       orntNew[4] = 0;
5567       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
5568       orntNew[5] = ornt[5];
5569       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5570       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5571 #if 1
5572       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);
5573       for (p = 0; p < 6; ++p) {
5574         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);
5575       }
5576 #endif
5577       /* C hex */
5578       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
5579       orntNew[0] = ornt[0];
5580       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
5581       orntNew[1] = 0;
5582       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
5583       orntNew[2] = -1;
5584       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
5585       orntNew[3] = ornt[3];
5586       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
5587       orntNew[4] = ornt[4];
5588       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
5589       orntNew[5] = -4;
5590       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5591       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5592 #if 1
5593       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);
5594       for (p = 0; p < 6; ++p) {
5595         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);
5596       }
5597 #endif
5598       /* D hex */
5599       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
5600       orntNew[0] = ornt[0];
5601       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
5602       orntNew[1] = 0;
5603       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
5604       orntNew[2] = ornt[2];
5605       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
5606       orntNew[3] = 0;
5607       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
5608       orntNew[4] = ornt[4];
5609       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
5610       orntNew[5] = -4;
5611       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5612       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5613 #if 1
5614       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);
5615       for (p = 0; p < 6; ++p) {
5616         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);
5617       }
5618 #endif
5619       /* E hex */
5620       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
5621       orntNew[0] = -4;
5622       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
5623       orntNew[1] = ornt[1];
5624       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
5625       orntNew[2] = ornt[2];
5626       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
5627       orntNew[3] = 0;
5628       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
5629       orntNew[4] = -1;
5630       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
5631       orntNew[5] = ornt[5];
5632       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
5633       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
5634 #if 1
5635       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);
5636       for (p = 0; p < 6; ++p) {
5637         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);
5638       }
5639 #endif
5640       /* F hex */
5641       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
5642       orntNew[0] = -4;
5643       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
5644       orntNew[1] = ornt[1];
5645       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
5646       orntNew[2] = ornt[2];
5647       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
5648       orntNew[3] = -1;
5649       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
5650       orntNew[4] = ornt[4];
5651       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
5652       orntNew[5] = 1;
5653       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
5654       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
5655 #if 1
5656       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);
5657       for (p = 0; p < 6; ++p) {
5658         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);
5659       }
5660 #endif
5661       /* G hex */
5662       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
5663       orntNew[0] = -4;
5664       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
5665       orntNew[1] = ornt[1];
5666       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
5667       orntNew[2] = 0;
5668       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
5669       orntNew[3] = ornt[3];
5670       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
5671       orntNew[4] = ornt[4];
5672       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
5673       orntNew[5] = -3;
5674       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
5675       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
5676 #if 1
5677       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);
5678       for (p = 0; p < 6; ++p) {
5679         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);
5680       }
5681 #endif
5682       /* H hex */
5683       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
5684       orntNew[0] = -4;
5685       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
5686       orntNew[1] = ornt[1];
5687       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
5688       orntNew[2] = -1;
5689       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
5690       orntNew[3] = ornt[3];
5691       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
5692       orntNew[4] = 3;
5693       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
5694       orntNew[5] = ornt[5];
5695       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
5696       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
5697 #if 1
5698       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);
5699       for (p = 0; p < 6; ++p) {
5700         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);
5701       }
5702 #endif
5703     }
5704     /* Hybrid cells have 6 faces: Front, Back, Sides */
5705     /*
5706      3---------2---------2
5707      |         |         |
5708      |    D    2    C    |
5709      |         |         |
5710      3----3----0----1----1
5711      |         |         |
5712      |    A    0    B    |
5713      |         |         |
5714      0---------0---------1
5715      */
5716     for (c = cMax; c < cEnd; ++c) {
5717       const PetscInt  newp = (cMax - cStart)*8 + (c - cMax)*4;
5718       const PetscInt *cone, *ornt, *fornt;
5719       PetscInt        coneNew[6], orntNew[6], o, of, i;
5720 
5721       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5722       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5723       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
5724       o = ornt[0] < 0 ? -1 : 1;
5725       for (r = 0; r < 4; ++r) {
5726         PetscInt subfA = GetQuadSubface_Static(ornt[0], r);
5727         PetscInt edgeA = GetQuadEdge_Static(ornt[0], r);
5728         PetscInt edgeB = GetQuadEdge_Static(ornt[0], (r+3)%4);
5729         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]);
5730         coneNew[0]         = fStartNew + (cone[0] - fStart)*4 + subfA;
5731         orntNew[0]         = ornt[0];
5732         coneNew[1]         = fStartNew + (cone[1] - fStart)*4 + subfA;
5733         orntNew[1]         = ornt[0];
5734         of = fornt[edgeA] < 0 ? -1 : 1;
5735         i  = GetQuadEdgeInverse_Static(ornt[0], r) + 2;
5736         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeA] - fMax)*2 + (o*of < 0 ? 1 : 0);
5737         orntNew[i] = ornt[edgeA];
5738         i  = GetQuadEdgeInverse_Static(ornt[0], (r+1)%4) + 2;
5739         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeA;
5740         orntNew[i] = 0;
5741         i  = GetQuadEdgeInverse_Static(ornt[0], (r+2)%4) + 2;
5742         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeB;
5743         orntNew[i] = -2;
5744         of = fornt[edgeB] < 0 ? -1 : 1;
5745         i  = GetQuadEdgeInverse_Static(ornt[0], (r+3)%4) + 2;
5746         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeB] - fMax)*2 + (o*of < 0 ? 0 : 1);
5747         orntNew[i] = ornt[edgeB];
5748         ierr       = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
5749         ierr       = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
5750 #if 1
5751         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);
5752         for (p = 0; p < 2; ++p) {
5753           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);
5754         }
5755         for (p = 2; p < 6; ++p) {
5756           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);
5757         }
5758 #endif
5759       }
5760     }
5761     /* Interior split faces have 4 edges and the same cells as the parent */
5762     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5763     ierr = PetscMalloc1(4 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
5764     for (f = fStart; f < fMax; ++f) {
5765       for (r = 0; r < 4; ++r) {
5766         /* TODO: This can come from GetFaces_Internal() */
5767         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};
5768         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
5769         const PetscInt *cone, *ornt, *support;
5770         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
5771 
5772         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5773         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
5774         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
5775         orntNew[(r+3)%4] = ornt[(r+3)%4];
5776         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
5777         orntNew[(r+0)%4] = ornt[r];
5778         coneNew[(r+1)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
5779         orntNew[(r+1)%4] = 0;
5780         coneNew[(r+2)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + (r+3)%4;
5781         orntNew[(r+2)%4] = -2;
5782         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5783         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5784 #if 1
5785         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5786         for (p = 0; p < 4; ++p) {
5787           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);
5788         }
5789 #endif
5790         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5791         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5792         for (s = 0; s < supportSize; ++s) {
5793           PetscInt subf;
5794           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5795           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5796           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5797           for (c = 0; c < coneSize; ++c) {
5798             if (cone[c] == f) break;
5799           }
5800           subf = GetQuadSubfaceInverse_Static(ornt[c], r);
5801           if (support[s] < cMax) {
5802             supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+subf];
5803           } else {
5804             supportRef[s] = cStartNew + (cMax       - cStart)*8 + (support[s] - cMax)*4 + subf;
5805           }
5806         }
5807         ierr = DMPlexSetSupport(rdm, newp, supportRef);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 < supportSize; ++p) {
5811           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);
5812         }
5813 #endif
5814       }
5815     }
5816     /* Interior cell faces have 4 edges and 2 cells */
5817     for (c = cStart; c < cMax; ++c) {
5818       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};
5819       const PetscInt *cone, *ornt;
5820       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
5821 
5822       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5823       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5824       /* A-D face */
5825       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 0;
5826       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
5827       orntNew[0] = 0;
5828       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
5829       orntNew[1] = 0;
5830       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
5831       orntNew[2] = -2;
5832       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
5833       orntNew[3] = -2;
5834       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5835       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5836 #if 1
5837       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5838       for (p = 0; p < 4; ++p) {
5839         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);
5840       }
5841 #endif
5842       /* C-D face */
5843       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 1;
5844       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
5845       orntNew[0] = 0;
5846       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
5847       orntNew[1] = 0;
5848       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
5849       orntNew[2] = -2;
5850       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
5851       orntNew[3] = -2;
5852       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5853       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5854 #if 1
5855       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5856       for (p = 0; p < 4; ++p) {
5857         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);
5858       }
5859 #endif
5860       /* B-C face */
5861       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 2;
5862       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
5863       orntNew[0] = -2;
5864       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
5865       orntNew[1] = 0;
5866       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
5867       orntNew[2] = 0;
5868       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
5869       orntNew[3] = -2;
5870       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5871       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5872 #if 1
5873       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5874       for (p = 0; p < 4; ++p) {
5875         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);
5876       }
5877 #endif
5878       /* A-B face */
5879       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 3;
5880       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
5881       orntNew[0] = -2;
5882       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
5883       orntNew[1] = 0;
5884       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
5885       orntNew[2] = 0;
5886       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
5887       orntNew[3] = -2;
5888       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5889       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5890 #if 1
5891       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5892       for (p = 0; p < 4; ++p) {
5893         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);
5894       }
5895 #endif
5896       /* E-F face */
5897       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 4;
5898       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
5899       orntNew[0] = -2;
5900       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
5901       orntNew[1] = -2;
5902       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
5903       orntNew[2] = 0;
5904       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
5905       orntNew[3] = 0;
5906       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5907       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5908 #if 1
5909       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5910       for (p = 0; p < 4; ++p) {
5911         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);
5912       }
5913 #endif
5914       /* F-G face */
5915       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 5;
5916       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
5917       orntNew[0] = -2;
5918       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
5919       orntNew[1] = -2;
5920       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
5921       orntNew[2] = 0;
5922       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
5923       orntNew[3] = 0;
5924       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5925       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5926 #if 1
5927       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5928       for (p = 0; p < 4; ++p) {
5929         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);
5930       }
5931 #endif
5932       /* G-H face */
5933       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 6;
5934       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
5935       orntNew[0] = -2;
5936       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
5937       orntNew[1] = 0;
5938       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
5939       orntNew[2] = 0;
5940       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
5941       orntNew[3] = -2;
5942       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5943       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5944 #if 1
5945       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5946       for (p = 0; p < 4; ++p) {
5947         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);
5948       }
5949 #endif
5950       /* E-H face */
5951       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 7;
5952       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
5953       orntNew[0] = -2;
5954       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
5955       orntNew[1] = -2;
5956       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
5957       orntNew[2] = 0;
5958       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
5959       orntNew[3] = 0;
5960       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5961       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5962 #if 1
5963       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5964       for (p = 0; p < 4; ++p) {
5965         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);
5966       }
5967 #endif
5968       /* A-E face */
5969       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 8;
5970       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
5971       orntNew[0] = 0;
5972       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
5973       orntNew[1] = 0;
5974       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
5975       orntNew[2] = -2;
5976       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
5977       orntNew[3] = -2;
5978       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5979       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5980 #if 1
5981       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5982       for (p = 0; p < 4; ++p) {
5983         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);
5984       }
5985 #endif
5986       /* D-F face */
5987       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 9;
5988       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
5989       orntNew[0] = -2;
5990       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
5991       orntNew[1] = 0;
5992       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
5993       orntNew[2] = 0;
5994       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
5995       orntNew[3] = -2;
5996       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5997       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5998 #if 1
5999       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
6000       for (p = 0; p < 4; ++p) {
6001         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);
6002       }
6003 #endif
6004       /* C-G face */
6005       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 10;
6006       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
6007       orntNew[0] = -2;
6008       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
6009       orntNew[1] = -2;
6010       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
6011       orntNew[2] = 0;
6012       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
6013       orntNew[3] = 0;
6014       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6015       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6016 #if 1
6017       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
6018       for (p = 0; p < 4; ++p) {
6019         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);
6020       }
6021 #endif
6022       /* B-H face */
6023       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 11;
6024       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
6025       orntNew[0] = 0;
6026       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
6027       orntNew[1] = -2;
6028       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
6029       orntNew[2] = -2;
6030       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
6031       orntNew[3] = 0;
6032       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6033       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6034 #if 1
6035       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
6036       for (p = 0; p < 4; ++p) {
6037         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);
6038       }
6039 #endif
6040       for (r = 0; r < 12; ++r) {
6041         newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
6042         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
6043         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
6044         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6045 #if 1
6046         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
6047         for (p = 0; p < 2; ++p) {
6048           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);
6049         }
6050 #endif
6051       }
6052     }
6053     /* Hybrid split faces have 4 edges and same cells */
6054     for (f = fMax; f < fEnd; ++f) {
6055       const PetscInt *cone, *ornt, *support;
6056       PetscInt        coneNew[4], orntNew[4];
6057       PetscInt        supportNew[2], size, s, c;
6058 
6059       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6060       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
6061       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6062       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6063       for (r = 0; r < 2; ++r) {
6064         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
6065 
6066         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
6067         orntNew[0]   = ornt[0];
6068         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
6069         orntNew[1]   = ornt[1];
6070         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (cone[2+r] - eMax);
6071         orntNew[2+r] = 0;
6072         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd      - eMax) + (f - fMax);
6073         orntNew[3-r] = 0;
6074         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6075         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6076 #if 1
6077         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
6078         for (p = 0; p < 2; ++p) {
6079           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);
6080         }
6081         for (p = 2; p < 4; ++p) {
6082           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);
6083         }
6084 #endif
6085         for (s = 0; s < size; ++s) {
6086           const PetscInt *coneCell, *orntCell, *fornt;
6087           PetscInt        o, of;
6088 
6089           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
6090           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
6091           o = orntCell[0] < 0 ? -1 : 1;
6092           for (c = 2; c < 6; ++c) if (coneCell[c] == f) break;
6093           if (c >= 6) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
6094           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
6095           of = fornt[c-2] < 0 ? -1 : 1;
6096           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetQuadEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%4;
6097         }
6098         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6099 #if 1
6100         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
6101         for (p = 0; p < size; ++p) {
6102           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);
6103         }
6104 #endif
6105       }
6106     }
6107     /* Hybrid cell faces have 4 edges and 2 cells */
6108     for (c = cMax; c < cEnd; ++c) {
6109       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4;
6110       const PetscInt *cone, *ornt;
6111       PetscInt        coneNew[4], orntNew[4];
6112       PetscInt        supportNew[2];
6113 
6114       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6115       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6116       for (r = 0; r < 4; ++r) {
6117 #if 0
6118         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], r);
6119         orntNew[0] = 0;
6120         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], r);
6121         orntNew[1] = 0;
6122         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+GetQuadEdge_Static(ornt[0], r)] - fMax);
6123         orntNew[2] = 0;
6124         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd                                   - fMax) + (c - cMax);
6125         orntNew[3] = 0;
6126 #else
6127         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + r;
6128         orntNew[0] = 0;
6129         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + r;
6130         orntNew[1] = 0;
6131         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+r] - fMax);
6132         orntNew[2] = 0;
6133         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd      - fMax) + (c - cMax);
6134         orntNew[3] = 0;
6135 #endif
6136         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
6137         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
6138 #if 1
6139         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);
6140         for (p = 0; p < 2; ++p) {
6141           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);
6142         }
6143         for (p = 2; p < 4; ++p) {
6144           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);
6145         }
6146 #endif
6147         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], r);
6148         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], (r+1)%4);
6149         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
6150 #if 1
6151         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);
6152         for (p = 0; p < 2; ++p) {
6153           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);
6154         }
6155 #endif
6156       }
6157     }
6158     /* Interior split edges have 2 vertices and the same faces as the parent */
6159     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6160     for (e = eStart; e < eMax; ++e) {
6161       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
6162 
6163       for (r = 0; r < 2; ++r) {
6164         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
6165         const PetscInt *cone, *ornt, *support;
6166         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6167 
6168         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6169         coneNew[0]       = vStartNew + (cone[0] - vStart);
6170         coneNew[1]       = vStartNew + (cone[1] - vStart);
6171         coneNew[(r+1)%2] = newv;
6172         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6173 #if 1
6174         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6175         for (p = 0; p < 2; ++p) {
6176           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);
6177         }
6178 #endif
6179         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
6180         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
6181         for (s = 0; s < supportSize; ++s) {
6182           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6183           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6184           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
6185           for (c = 0; c < coneSize; ++c) {
6186             if (cone[c] == e) break;
6187           }
6188           if (support[s] < fMax) {
6189             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%4;
6190           } else {
6191             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
6192           }
6193         }
6194         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6195 #if 1
6196         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6197         for (p = 0; p < supportSize; ++p) {
6198           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);
6199         }
6200 #endif
6201       }
6202     }
6203     /* Interior face edges have 2 vertices and 2+cells faces */
6204     for (f = fStart; f < fMax; ++f) {
6205       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};
6206       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
6207       const PetscInt *cone, *coneCell, *orntCell, *support;
6208       PetscInt        coneNew[2], coneSize, c, supportSize, s;
6209 
6210       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6211       for (r = 0; r < 4; ++r) {
6212         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
6213 
6214         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
6215         coneNew[1] = newv;
6216         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6217 #if 1
6218         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6219         for (p = 0; p < 2; ++p) {
6220           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);
6221         }
6222 #endif
6223         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6224         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6225         supportRef[0] = fStartNew + (f - fStart)*4 + r;
6226         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
6227         for (s = 0; s < supportSize; ++s) {
6228           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6229           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
6230           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
6231           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
6232           if (support[s] < cMax) {
6233             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
6234           } else {
6235             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + r;
6236           }
6237         }
6238         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6239 #if 1
6240         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6241         for (p = 0; p < 2+supportSize; ++p) {
6242           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);
6243         }
6244 #endif
6245       }
6246     }
6247     /* Interior cell edges have 2 vertices and 4 faces */
6248     for (c = cStart; c < cMax; ++c) {
6249       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};
6250       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
6251       const PetscInt *cone;
6252       PetscInt        coneNew[2], supportNew[4];
6253 
6254       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6255       for (r = 0; r < 6; ++r) {
6256         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
6257 
6258         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
6259         coneNew[1] = newv;
6260         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6261 #if 1
6262         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6263         for (p = 0; p < 2; ++p) {
6264           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);
6265         }
6266 #endif
6267         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
6268         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6269 #if 1
6270         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6271         for (p = 0; p < 4; ++p) {
6272           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);
6273         }
6274 #endif
6275       }
6276     }
6277     /* Hybrid edges have two vertices and the same faces */
6278     for (e = eMax; e < eEnd; ++e) {
6279       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
6280       const PetscInt *cone, *support, *fcone;
6281       PetscInt        coneNew[2], size, fsize, s;
6282 
6283       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6284       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
6285       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
6286       coneNew[0] = vStartNew + (cone[0] - vStart);
6287       coneNew[1] = vStartNew + (cone[1] - vStart);
6288       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6289 #if 1
6290       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6291       for (p = 0; p < 2; ++p) {
6292         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);
6293       }
6294 #endif
6295       for (s = 0; s < size; ++s) {
6296         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
6297         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
6298         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
6299         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
6300         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + c-2;
6301       }
6302       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6303 #if 1
6304       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6305       for (p = 0; p < size; ++p) {
6306         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);
6307       }
6308 #endif
6309     }
6310     /* Hybrid face edges have 2 vertices and 2+cells faces */
6311     for (f = fMax; f < fEnd; ++f) {
6312       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
6313       const PetscInt *cone, *support, *ccone, *cornt;
6314       PetscInt        coneNew[2], size, csize, s;
6315 
6316       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6317       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6318       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6319       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
6320       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
6321       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6322 #if 1
6323       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6324       for (p = 0; p < 2; ++p) {
6325         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);
6326       }
6327 #endif
6328       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 0;
6329       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 1;
6330       for (s = 0; s < size; ++s) {
6331         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
6332         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
6333         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
6334         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
6335         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]);
6336         supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + c-2;
6337       }
6338       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6339 #if 1
6340       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6341       for (p = 0; p < 2+size; ++p) {
6342         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);
6343       }
6344 #endif
6345     }
6346     /* Hybrid cell edges have 2 vertices and 4 faces */
6347     for (c = cMax; c < cEnd; ++c) {
6348       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
6349       const PetscInt *cone, *support;
6350       PetscInt        coneNew[2], size;
6351 
6352       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6353       ierr = DMPlexGetSupportSize(dm, c, &size);CHKERRQ(ierr);
6354       ierr = DMPlexGetSupport(dm, c, &support);CHKERRQ(ierr);
6355       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
6356       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
6357       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6358 #if 1
6359       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6360       for (p = 0; p < 2; ++p) {
6361         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);
6362       }
6363 #endif
6364       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 0;
6365       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 1;
6366       supportRef[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 2;
6367       supportRef[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 3;
6368       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6369 #if 1
6370       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6371       for (p = 0; p < 4; ++p) {
6372         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);
6373       }
6374 #endif
6375     }
6376     /* Interior vertices have identical supports */
6377     for (v = vStart; v < vEnd; ++v) {
6378       const PetscInt  newp = vStartNew + (v - vStart);
6379       const PetscInt *support, *cone;
6380       PetscInt        size, s;
6381 
6382       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6383       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6384       for (s = 0; s < size; ++s) {
6385         PetscInt r = 0;
6386 
6387         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6388         if (cone[1] == v) r = 1;
6389         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
6390         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (support[s] - eMax);
6391       }
6392       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6393 #if 1
6394       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6395       for (p = 0; p < size; ++p) {
6396         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);
6397       }
6398 #endif
6399     }
6400     /* Interior edge vertices have 2 + faces supports */
6401     for (e = eStart; e < eMax; ++e) {
6402       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
6403       const PetscInt *cone, *support;
6404       PetscInt        size, s;
6405 
6406       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
6407       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
6408       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
6409       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
6410       for (s = 0; s < size; ++s) {
6411         PetscInt r;
6412 
6413         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6414         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
6415         if (support[s] < fMax) {
6416           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*4 + r;
6417         } else {
6418           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (support[s] - fMax);
6419         }
6420       }
6421       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6422 #if 1
6423       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6424       for (p = 0; p < 2+size; ++p) {
6425         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);
6426       }
6427 #endif
6428     }
6429     /* Interior face vertices have 4 + cells supports */
6430     for (f = fStart; f < fMax; ++f) {
6431       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
6432       const PetscInt *cone, *support;
6433       PetscInt        size, s;
6434 
6435       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6436       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6437       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eMax - eStart)*2 +  (f - fStart)*4 + r;
6438       for (s = 0; s < size; ++s) {
6439         PetscInt r;
6440 
6441         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6442         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
6443         if (support[s] < cMax) {
6444           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (support[s] - cStart)*6 + r;
6445         } else {
6446           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax       - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (support[s] - cMax);
6447         }
6448       }
6449       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6450 #if 1
6451       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6452       for (p = 0; p < 4+size; ++p) {
6453         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);
6454       }
6455 #endif
6456     }
6457     /* Cell vertices have 6 supports */
6458     for (c = cStart; c < cMax; ++c) {
6459       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
6460       PetscInt       supportNew[6];
6461 
6462       for (r = 0; r < 6; ++r) {
6463         supportNew[r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
6464       }
6465       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6466     }
6467     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6468     break;
6469   default:
6470     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6471   }
6472   PetscFunctionReturn(0);
6473 }
6474 
6475 static PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6476 {
6477   PetscSection          coordSection, coordSectionNew;
6478   Vec                   coordinates, coordinatesNew;
6479   PetscScalar          *coords, *coordsNew;
6480   const PetscInt        numVertices = depthSize ? depthSize[0] : 0;
6481   PetscInt              dim, spaceDim, depth, bs, coordSizeNew, cStart, cEnd, cMax;
6482   PetscInt              c, vStart, vStartNew, vEnd, v, eStart, eEnd, eMax, e, fStart, fEnd, fMax, f;
6483   PetscInt              cStartNew, cEndNew, vEndNew, *parentId = NULL;
6484   VecType               vtype;
6485   PetscBool             isperiodic, localize = PETSC_FALSE, needcoords = PETSC_FALSE;
6486   const PetscReal      *maxCell, *L;
6487   const DMBoundaryType *bd;
6488   PetscErrorCode        ierr;
6489 
6490   PetscFunctionBegin;
6491   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6492   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6493   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6494   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6495   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6496   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6497   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, NULL);CHKERRQ(ierr);
6498   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, NULL, NULL, &vStartNew);CHKERRQ(ierr);
6499   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, NULL, NULL, &vEndNew);CHKERRQ(ierr);
6500   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6501   ierr = PetscSectionGetFieldComponents(coordSection, 0, &spaceDim);CHKERRQ(ierr);
6502   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
6503   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
6504   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, spaceDim);CHKERRQ(ierr);
6505   ierr = DMGetPeriodicity(dm, &isperiodic, &maxCell, &L, &bd);CHKERRQ(ierr);
6506   ierr = DMSetPeriodicity(rdm, isperiodic,  maxCell,  L,  bd);CHKERRQ(ierr);
6507   /* Determine if we need to localize coordinates when generating them */
6508   if (isperiodic && !maxCell) {
6509     ierr = DMGetCoordinatesLocalized(dm, &localize);CHKERRQ(ierr);
6510     if (!localize) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Cannot refine if coordinates have not been localized");
6511   }
6512   if (localize) {
6513     PetscInt p, r, newp, *pi;
6514 
6515     /* New coordinates will be already localized on the cell */
6516     ierr = PetscSectionSetChart(coordSectionNew, 0, vStartNew+numVertices);CHKERRQ(ierr);
6517 
6518     /* We need the parentId to properly localize coordinates */
6519     ierr = PetscMalloc1(cEndNew-cStartNew,&pi);CHKERRQ(ierr);
6520     switch (refiner) {
6521     case REFINER_NOOP:
6522       break;
6523     case REFINER_SIMPLEX_1D:
6524       for (p = cStart; p < cEnd; ++p) {
6525         for (r = 0; r < 2; ++r) {
6526           newp     = (p - cStart)*2 + r;
6527           pi[newp] = p;
6528         }
6529       }
6530       break;
6531     case REFINER_SIMPLEX_2D:
6532       for (p = cStart; p < cEnd; ++p) {
6533         for (r = 0; r < 4; ++r) {
6534           newp     = (p - cStart)*4 + r;
6535           pi[newp] = p;
6536         }
6537       }
6538       break;
6539     case REFINER_HEX_2D:
6540       for (p = cStart; p < cEnd; ++p) {
6541         for (r = 0; r < 4; ++r) {
6542           newp     = (p - cStart)*4 + r;
6543           pi[newp] = p;
6544         }
6545       }
6546       break;
6547     case REFINER_SIMPLEX_TO_HEX_2D:
6548       for (p = cStart; p < cEnd; ++p) {
6549         for (r = 0; r < 3; ++r) {
6550           newp     = (p - cStart)*3 + r;
6551           pi[newp] = p;
6552         }
6553       }
6554       break;
6555     case REFINER_HYBRID_SIMPLEX_2D:
6556       for (p = cStart; p < cMax; ++p) {
6557         for (r = 0; r < 4; ++r) {
6558           newp     = (p - cStart)*4 + r;
6559           pi[newp] = p;
6560         }
6561       }
6562       for (p = cMax; p < cEnd; ++p) {
6563         for (r = 0; r < 2; ++r) {
6564           newp     = (cMax - cStart)*4 + (p - cMax)*2 + r;
6565           pi[newp] = p;
6566         }
6567       }
6568       break;
6569     case REFINER_HYBRID_HEX_2D:
6570       for (p = cStart; p < cMax; ++p) {
6571         for (r = 0; r < 4; ++r) {
6572           newp     = (p - cStart)*4 + r;
6573           pi[newp] = p;
6574         }
6575       }
6576       for (p = cMax; p < cEnd; ++p) {
6577         for (r = 0; r < 2; ++r) {
6578           newp     = (cMax - cStart)*4 + (p - cMax)*2 + r;
6579           pi[newp] = p;
6580         }
6581       }
6582       break;
6583     case REFINER_SIMPLEX_3D:
6584       for (p = cStart; p < cEnd; ++p) {
6585         for (r = 0; r < 8; ++r) {
6586           newp     = (p - cStart)*8 + r;
6587           pi[newp] = p;
6588         }
6589       }
6590       break;
6591     case REFINER_HYBRID_SIMPLEX_3D:
6592       for (p = cStart; p < cMax; ++p) {
6593         for (r = 0; r < 8; ++r) {
6594           newp     = (p - cStart)*8 + r;
6595           pi[newp] = p;
6596         }
6597       }
6598       for (p = cMax; p < cEnd; ++p) {
6599         for (r = 0; r < 4; ++r) {
6600           newp     = (cMax - cStart)*8 + (p - cMax)*4 + r;
6601           pi[newp] = p;
6602         }
6603       }
6604       break;
6605     case REFINER_SIMPLEX_TO_HEX_3D:
6606       for (p = cStart; p < cEnd; ++p) {
6607         for (r = 0; r < 4; ++r) {
6608           newp     = (p - cStart)*4 + r;
6609           pi[newp] = p;
6610         }
6611       }
6612       break;
6613     case REFINER_HEX_3D:
6614       for (p = cStart; p < cEnd; ++p) {
6615         for (r = 0; r < 8; ++r) {
6616           newp = (p - cStart)*8 + r;
6617           pi[newp] = p;
6618         }
6619       }
6620       break;
6621     case REFINER_HYBRID_HEX_3D:
6622       for (p = cStart; p < cMax; ++p) {
6623         for (r = 0; r < 8; ++r) {
6624           newp = (p - cStart)*8 + r;
6625           pi[newp] = p;
6626         }
6627       }
6628       for (p = cMax; p < cEnd; ++p) {
6629         for (r = 0; r < 4; ++r) {
6630           newp = (cMax - cStart)*8 + (p - cMax)*4 + r;
6631           pi[newp] = p;
6632         }
6633       }
6634       break;
6635     default:
6636       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6637     }
6638     parentId = pi;
6639   } else {
6640     ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+numVertices);CHKERRQ(ierr);
6641   }
6642   if (cMax < 0) cMax = cEnd;
6643   if (fMax < 0) fMax = fEnd;
6644   if (eMax < 0) eMax = eEnd;
6645 
6646   /* All vertices have the spaceDim coordinates */
6647   if (localize) {
6648     PetscInt c;
6649 
6650     for (c = cStartNew; c < cEndNew; ++c) {
6651       PetscInt *cone = NULL;
6652       PetscInt  closureSize, coneSize = 0, p, pdof;
6653 
6654       ierr = PetscSectionGetDof(coordSection, parentId[c], &pdof); CHKERRQ(ierr);
6655       if (pdof) { /* localize on all cells that are refinement of a localized parent cell */
6656         ierr = DMPlexGetTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6657         for (p = 0; p < closureSize*2; p += 2) {
6658           const PetscInt point = cone[p];
6659           if ((point >= vStartNew) && (point < vEndNew)) coneSize++;
6660         }
6661         ierr = DMPlexRestoreTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6662         ierr = PetscSectionSetDof(coordSectionNew, c, coneSize*spaceDim);CHKERRQ(ierr);
6663         ierr = PetscSectionSetFieldDof(coordSectionNew, c, 0, coneSize*spaceDim);CHKERRQ(ierr);
6664       }
6665     }
6666   }
6667   for (v = vStartNew; v < vStartNew+numVertices; ++v) {
6668     ierr = PetscSectionSetDof(coordSectionNew, v, spaceDim);CHKERRQ(ierr);
6669     ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, spaceDim);CHKERRQ(ierr);
6670   }
6671   ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
6672   ierr = DMSetCoordinateSection(rdm, PETSC_DETERMINE, coordSectionNew);CHKERRQ(ierr);
6673   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6674   ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
6675   ierr = VecCreate(PETSC_COMM_SELF, &coordinatesNew);CHKERRQ(ierr);
6676   ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
6677   ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
6678   ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr);
6679   ierr = VecSetBlockSize(coordinatesNew, bs);CHKERRQ(ierr);
6680   ierr = VecGetType(coordinates, &vtype);CHKERRQ(ierr);
6681   ierr = VecSetType(coordinatesNew, vtype);CHKERRQ(ierr);
6682   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
6683   ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6684 
6685   switch (refiner) {
6686   case REFINER_NOOP: break;
6687   case REFINER_SIMPLEX_TO_HEX_3D:
6688   case REFINER_HEX_3D:
6689   case REFINER_HYBRID_HEX_3D:
6690     /* Face vertices have the average of corner coordinates */
6691     for (f = fStart; f < fMax; ++f) {
6692       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
6693       PetscInt      *cone = NULL;
6694       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
6695 
6696       ierr = DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6697       for (p = 0; p < closureSize*2; p += 2) {
6698         const PetscInt point = cone[p];
6699         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
6700       }
6701       if (localize) {
6702         const PetscInt *support = NULL;
6703         PetscInt       *rStar = NULL;
6704         PetscInt        supportSize, rStarSize, coff, s, ccoff[8];
6705         PetscBool       cellfound = PETSC_FALSE;
6706 
6707         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
6708         ierr = DMPlexGetSupportSize(dm,f,&supportSize);CHKERRQ(ierr);
6709         ierr = DMPlexGetSupport(dm,f,&support);CHKERRQ(ierr);
6710         /* Compute average of coordinates for each cell sharing the face */
6711         for (s = 0; s < supportSize; ++s) {
6712           PetscScalar     coordsNewAux[3] = { 0.0, 0.0, 0.0 };
6713           PetscInt       *cellCone = NULL;
6714           PetscInt        cellClosureSize, cellConeSize = 0, cdof;
6715           const PetscInt  cell = support[s];
6716           PetscBool       copyoff = PETSC_FALSE;
6717 
6718           ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
6719           for (p = 0; p < cellClosureSize*2; p += 2) {
6720             const PetscInt point = cellCone[p];
6721             if ((point >= vStart) && (point < vEnd)) cellCone[cellConeSize++] = point;
6722           }
6723           ierr = PetscSectionGetDof(coordSection, cell, &cdof);CHKERRQ(ierr);
6724           if (!cdof) { /* the parent cell does not have localized coordinates */
6725             cellfound = PETSC_TRUE;
6726             for (v = 0; v < coneSize; ++v) {
6727               ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
6728               for (d = 0; d < spaceDim; ++d) coordsNewAux[d] += coords[off[v]+d];
6729             }
6730             for (d = 0; d < spaceDim; ++d) coordsNewAux[d] /= coneSize;
6731           } else {
6732             ierr = PetscSectionGetOffset(coordSection, cell, &coff);CHKERRQ(ierr);
6733             for (p = 0; p < coneSize; ++p) {
6734               const PetscInt tv = cone[p];
6735               PetscInt       cv, voff;
6736               PetscBool      locv = PETSC_TRUE;
6737 
6738               for (cv = 0; cv < cellConeSize; ++cv) {
6739                 if (cellCone[cv] == tv) {
6740                   ccoff[p] = spaceDim*cv + coff;
6741                   break;
6742                 }
6743               }
6744               if (cv == cellConeSize) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map vertex %D\n",tv);
6745 
6746               ierr = PetscSectionGetOffset(coordSection, cone[p], &voff);CHKERRQ(ierr);
6747               for (d = 0; d < spaceDim; ++d) {
6748                 coordsNewAux[d] += coords[ccoff[p]+d];
6749                 if (!cellfound && coords[voff+d] != coords[ccoff[p]+d]) locv = PETSC_FALSE;
6750               }
6751               if (locv && !cellfound) {
6752                 cellfound = PETSC_TRUE;
6753                 copyoff   = PETSC_TRUE;
6754               }
6755             }
6756             for (d = 0; d < spaceDim; ++d) coordsNewAux[d] /= coneSize;
6757 
6758             /* Found a valid face for the "vertex" part of the Section (physical space)
6759                i.e., a face that has at least one corner in the physical space */
6760             if (copyoff) for (p = 0; p < coneSize; ++p) off[p] = ccoff[p];
6761           }
6762 
6763           /* Localize new coordinates on each refined cell */
6764           for (v = 0; v < rStarSize*2; v += 2) {
6765             if ((rStar[v] >= cStartNew) && (rStar[v] < cEndNew) && parentId[rStar[v]-cStartNew] == cell) {
6766               PetscInt       *rcone = NULL, rclosureSize, lid, rcdof, rcoff;
6767               const PetscInt  rcell = rStar[v];
6768 
6769               ierr = PetscSectionGetDof(coordSectionNew, rcell, &rcdof);CHKERRQ(ierr);
6770               if (!rcdof) continue;
6771               ierr = PetscSectionGetOffset(coordSectionNew, rcell, &rcoff);CHKERRQ(ierr);
6772               ierr = DMPlexGetTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
6773               for (p = 0, lid = 0; p < rclosureSize*2; p += 2) {
6774                 if (rcone[p] == newv) {
6775                   for (d = 0; d < spaceDim; d++) coordsNew[rcoff + lid*spaceDim + d] = coordsNewAux[d];
6776                   break;
6777                 }
6778                 if (rcone[p] >= vStartNew && rcone[p] < vEndNew) lid++;
6779               }
6780               ierr = DMPlexRestoreTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
6781               if (p == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
6782             }
6783           }
6784           ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
6785         }
6786         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
6787         if (!cellfound) {
6788           /* Could not find a valid face for the vertex part, we will get this vertex later (final reduction) */
6789           needcoords = PETSC_TRUE;
6790           coneSize   = 0;
6791         }
6792       } else {
6793         for (v = 0; v < coneSize; ++v) {
6794           ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
6795         }
6796       }
6797       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6798       if (coneSize) {
6799         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
6800         for (v = 0; v < coneSize; ++v) {ierr = DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);CHKERRQ(ierr);}
6801         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
6802       } else {
6803         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = PETSC_MIN_REAL;
6804       }
6805       ierr = DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6806     }
6807   case REFINER_SIMPLEX_TO_HEX_2D:
6808   case REFINER_HEX_2D:
6809   case REFINER_HYBRID_HEX_2D:
6810   case REFINER_SIMPLEX_1D:
6811     /* Cell vertices have the average of corner coordinates */
6812     for (c = cStart; c < cMax; ++c) {
6813       const PetscInt newv = vStartNew + (vEnd - vStart) + (dim > 1 ? (eMax - eStart) : 0) + (c - cStart) + (dim > 2 ? (fMax - fStart) : 0);
6814       PetscInt      *cone = NULL;
6815       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d, cdof = 0;
6816 
6817       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6818       for (p = 0; p < closureSize*2; p += 2) {
6819         const PetscInt point = cone[p];
6820         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
6821       }
6822       if (localize) {
6823         ierr = PetscSectionGetDof(coordSection, c, &cdof);CHKERRQ(ierr);
6824       }
6825       if (cdof) {
6826         PetscInt coff;
6827 
6828         ierr = PetscSectionGetOffset(coordSection, c, &coff);CHKERRQ(ierr);
6829         for (v = 0; v < coneSize; ++v) off[v] = spaceDim*v + coff;
6830       } else {
6831         for (v = 0; v < coneSize; ++v) {
6832           ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
6833         }
6834       }
6835       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6836       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
6837       for (v = 0; v < coneSize; ++v) {ierr = DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);CHKERRQ(ierr);}
6838       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
6839       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6840 
6841       /* Localize new coordinates on each refined cell */
6842       if (cdof) {
6843         PetscInt *rStar = NULL, rStarSize;
6844 
6845         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
6846         for (v = 0; v < rStarSize*2; v += 2) {
6847           if ((rStar[v] >= cStartNew) && (rStar[v] < cEndNew)) {
6848             PetscInt *cone = NULL, closureSize, lid, coff, rc, rcdof;
6849 
6850             rc   = rStar[v];
6851             ierr = PetscSectionGetDof(coordSectionNew, rc, &rcdof);CHKERRQ(ierr);
6852             if (!rcdof) continue;
6853             ierr = PetscSectionGetOffset(coordSectionNew, rc, &coff);CHKERRQ(ierr);
6854             ierr = DMPlexGetTransitiveClosure(rdm, rc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6855             for (p = 0, lid = 0; p < closureSize*2; p += 2) {
6856               if (cone[p] == newv) {
6857                 for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = coordsNew[offnew + d];
6858                 break;
6859               }
6860               if (cone[p] >= vStartNew && cone[p] < vEndNew) lid++;
6861             }
6862             if (p == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
6863             ierr = DMPlexRestoreTransitiveClosure(rdm, rc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6864           }
6865         }
6866         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
6867       }
6868     }
6869   case REFINER_SIMPLEX_2D:
6870   case REFINER_HYBRID_SIMPLEX_2D:
6871   case REFINER_SIMPLEX_3D:
6872   case REFINER_HYBRID_SIMPLEX_3D:
6873     /* Edge vertices have the average of endpoint coordinates */
6874     for (e = eStart; e < eMax; ++e) {
6875       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
6876       const PetscInt *cone;
6877       PetscInt        coneSize, offA, offB, offnew, d;
6878 
6879       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
6880       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
6881       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6882       if (localize) {
6883         PetscInt   coff, toffA = -1, toffB = -1, voffA, voffB;
6884         PetscInt  *eStar = NULL, eStarSize;
6885         PetscInt  *rStar = NULL, rStarSize;
6886         PetscBool  cellfound = PETSC_FALSE;
6887 
6888         offA = offB = -1;
6889         ierr = PetscSectionGetOffset(coordSection, cone[0], &voffA);CHKERRQ(ierr);
6890         ierr = PetscSectionGetOffset(coordSection, cone[1], &voffB);CHKERRQ(ierr);
6891         ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &eStarSize, &eStar);CHKERRQ(ierr);
6892         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
6893         for (v = 0; v < eStarSize*2; v += 2) {
6894           if ((eStar[v] >= cStart) && (eStar[v] < cEnd)) {
6895             PetscScalar     coordsNewAux[3];
6896             PetscInt       *cellCone = NULL;
6897             PetscInt        cellClosureSize, s, cv, cdof;
6898             PetscBool       locvA = PETSC_TRUE, locvB = PETSC_TRUE;
6899             const PetscInt  cell = eStar[v];
6900 
6901             ierr = PetscSectionGetDof(coordSection, cell, &cdof);CHKERRQ(ierr);
6902             if (!cdof) {
6903               /* Found a valid edge for the "vertex" part of the Section */
6904               offA = voffA;
6905               offB = voffB;
6906               cellfound = PETSC_TRUE;
6907             } else {
6908               ierr = PetscSectionGetOffset(coordSection, cell, &coff);CHKERRQ(ierr);
6909               ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
6910               for (s = 0, cv = 0; s < cellClosureSize*2; s += 2) {
6911                 const PetscInt point = cellCone[s];
6912                 if ((point >= vStart) && (point < vEnd)) {
6913                   if (point == cone[0]) toffA = spaceDim*cv + coff;
6914                   else if (point == cone[1]) toffB = spaceDim*cv + coff;
6915                   cv++;
6916                 }
6917               }
6918               ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
6919               for (d = 0; d < spaceDim; ++d) {
6920                 coordsNewAux[d] = 0.5*(coords[toffA+d] + coords[toffB+d]);
6921                 if (coords[toffA+d] != coords[voffA+d]) locvA = PETSC_FALSE;
6922                 if (coords[toffB+d] != coords[voffB+d]) locvB = PETSC_FALSE;
6923               }
6924               /* Found a valid edge for the "vertex" part of the Section */
6925               if (!cellfound && (locvA || locvB)) {
6926                 cellfound = PETSC_TRUE;
6927                 offA = toffA;
6928                 offB = toffB;
6929               }
6930             }
6931 
6932             /* Localize new coordinates on each refined cell */
6933             for (s = 0; s < rStarSize*2; s += 2) {
6934               if ((rStar[s] >= cStartNew) && (rStar[s] < cEndNew) && parentId[rStar[s]-cStartNew] == cell) {
6935                 PetscInt       *rcone = NULL, rclosureSize, lid, p, rcdof;
6936                 const PetscInt  rcell = rStar[s];
6937 
6938                 ierr = PetscSectionGetDof(coordSectionNew, rcell, &rcdof);CHKERRQ(ierr);
6939                 if (!rcdof) continue;
6940                 ierr = PetscSectionGetOffset(coordSectionNew, rcell, &coff);CHKERRQ(ierr);
6941                 ierr = DMPlexGetTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
6942                 for (p = 0, lid = 0; p < rclosureSize*2; p += 2) {
6943                   if (rcone[p] == newv) {
6944                     for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = coordsNewAux[d];
6945                     break;
6946                   }
6947                   if (rcone[p] >= vStartNew && rcone[p] < vEndNew) lid++;
6948                 }
6949                 ierr = DMPlexRestoreTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
6950                 if (p == rclosureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
6951               }
6952             }
6953           }
6954         }
6955         ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &eStarSize, &eStar);CHKERRQ(ierr);
6956         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
6957         if (!cellfound) {
6958           /* Could not find a valid edge for the vertex part, we will get this vertex later (final reduction) */
6959           needcoords = PETSC_TRUE;
6960         }
6961       } else {
6962         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6963         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6964       }
6965       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6966       if (offA != -1 && offB != -1) {
6967         ierr = DMLocalizeCoordinate_Internal(dm, spaceDim, &coords[offA], &coords[offB], &coordsNew[offnew]);CHKERRQ(ierr);
6968         for (d = 0; d < spaceDim; ++d) {
6969           coordsNew[offnew+d] = 0.5*(coords[offA+d] + coordsNew[offnew+d]);
6970         }
6971       } else {
6972         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = PETSC_MIN_REAL;
6973       }
6974     }
6975     /* Old vertices have the same coordinates */
6976     for (v = vStart; v < vEnd; ++v) {
6977       const PetscInt newv = vStartNew + (v - vStart);
6978       PetscInt       off, offnew, d;
6979 
6980       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6981       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6982       for (d = 0; d < spaceDim; ++d) {
6983         coordsNew[offnew+d] = coords[off+d];
6984       }
6985 
6986       /* Localize new coordinates on each refined cell */
6987       if (localize) {
6988         PetscInt  p;
6989         PetscInt *rStar = NULL, rStarSize;
6990 
6991         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
6992         for (p = 0; p < rStarSize*2; p += 2) {
6993           if ((rStar[p] >= cStartNew) && (rStar[p] < cEndNew)) {
6994             PetscScalar  ocoords[3];
6995             PetscInt    *cone = NULL, closureSize, lid, coff, s, oc, cdof;
6996 
6997             c    = rStar[p];
6998             oc   = parentId[c-cStartNew];
6999             ierr = PetscSectionGetDof(coordSectionNew, c, &cdof);CHKERRQ(ierr);
7000             if (!cdof) continue;
7001             ierr = PetscSectionGetDof(coordSection, oc, &cdof);CHKERRQ(ierr);
7002             if (!cdof) continue;
7003             ierr = PetscSectionGetOffset(coordSection, oc, &coff);CHKERRQ(ierr);
7004             ierr = DMPlexGetTransitiveClosure(dm, oc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
7005             for (s = 0, lid = 0; s < closureSize*2; s += 2) {
7006               if (cone[s] == v) {
7007                 for (d = 0; d < spaceDim; d++) ocoords[d] = coords[coff + lid*spaceDim + d];
7008                 break;
7009               }
7010               if (cone[s] >= vStart && cone[s] < vEnd) lid++;
7011             }
7012             if (s == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map old vertex %D\n",v);
7013             ierr = DMPlexRestoreTransitiveClosure(dm, oc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
7014 
7015             ierr = PetscSectionGetOffset(coordSectionNew, c, &coff);CHKERRQ(ierr);
7016             ierr = DMPlexGetTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
7017             for (s = 0, lid = 0; s < closureSize*2; s += 2) {
7018               if (cone[s] == newv) {
7019                 for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = ocoords[d];
7020                 break;
7021               }
7022               if (cone[s] >= vStartNew && cone[s] < vEndNew) lid++;
7023             }
7024             if (s == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
7025             ierr = DMPlexRestoreTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
7026           }
7027         }
7028         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
7029       }
7030     }
7031     break;
7032   default:
7033     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7034   }
7035   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
7036   ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
7037   ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
7038 
7039   /* Final reduction (if needed) if we are localizing */
7040   if (localize) {
7041     PetscBool gred;
7042 
7043     ierr = MPIU_Allreduce(&needcoords, &gred, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)rdm));CHKERRQ(ierr);
7044     if (gred) {
7045       DM                 cdm;
7046       Vec                aux;
7047       PetscSF            sf;
7048       const PetscScalar *lArray;
7049       PetscScalar       *gArray;
7050 
7051       ierr = DMGetCoordinateDM(rdm, &cdm);CHKERRQ(ierr);
7052       ierr = DMCreateGlobalVector(cdm, &aux);CHKERRQ(ierr);
7053       ierr = DMGetDefaultSF(cdm, &sf);CHKERRQ(ierr);
7054       ierr = VecGetArrayRead(coordinatesNew, &lArray);CHKERRQ(ierr);
7055       ierr = VecSet(aux, PETSC_MIN_REAL);CHKERRQ(ierr);
7056       ierr = VecGetArray(aux, &gArray);CHKERRQ(ierr);
7057       ierr = PetscSFReduceBegin(sf, MPIU_SCALAR, lArray, gArray, MPIU_MAX);CHKERRQ(ierr);
7058       ierr = PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_MAX);CHKERRQ(ierr);
7059       ierr = VecRestoreArrayRead(coordinatesNew, &lArray);CHKERRQ(ierr);
7060       ierr = VecRestoreArray(aux, &gArray);CHKERRQ(ierr);
7061       ierr = DMGlobalToLocalBegin(cdm, aux, INSERT_VALUES, coordinatesNew);CHKERRQ(ierr);
7062       ierr = DMGlobalToLocalEnd(cdm, aux, INSERT_VALUES, coordinatesNew);CHKERRQ(ierr);
7063       ierr = VecDestroy(&aux);CHKERRQ(ierr);
7064     }
7065   }
7066   ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
7067   ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
7068   ierr = PetscFree(parentId);CHKERRQ(ierr);
7069   PetscFunctionReturn(0);
7070 }
7071 
7072 /*@
7073   DMPlexCreateProcessSF - Create an SF which just has process connectivity
7074 
7075   Collective on DM
7076 
7077   Input Parameters:
7078 + dm      - The DM
7079 - sfPoint - The PetscSF which encodes point connectivity
7080 
7081   Output Parameters:
7082 + processRanks - A list of process neighbors, or NULL
7083 - sfProcess    - An SF encoding the process connectivity, or NULL
7084 
7085   Level: developer
7086 
7087 .seealso: PetscSFCreate(), DMPlexCreateTwoSidedProcessSF()
7088 @*/
7089 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
7090 {
7091   PetscInt           numRoots, numLeaves, l;
7092   const PetscInt    *localPoints;
7093   const PetscSFNode *remotePoints;
7094   PetscInt          *localPointsNew;
7095   PetscSFNode       *remotePointsNew;
7096   PetscInt          *ranks, *ranksNew;
7097   PetscMPIInt        size;
7098   PetscErrorCode     ierr;
7099 
7100   PetscFunctionBegin;
7101   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7102   PetscValidHeaderSpecific(sfPoint, PETSCSF_CLASSID, 2);
7103   if (processRanks) {PetscValidPointer(processRanks, 3);}
7104   if (sfProcess)    {PetscValidPointer(sfProcess, 4);}
7105   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) dm), &size);CHKERRQ(ierr);
7106   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
7107   ierr = PetscMalloc1(numLeaves, &ranks);CHKERRQ(ierr);
7108   for (l = 0; l < numLeaves; ++l) {
7109     ranks[l] = remotePoints[l].rank;
7110   }
7111   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
7112   ierr = PetscMalloc1(numLeaves, &ranksNew);CHKERRQ(ierr);
7113   ierr = PetscMalloc1(numLeaves, &localPointsNew);CHKERRQ(ierr);
7114   ierr = PetscMalloc1(numLeaves, &remotePointsNew);CHKERRQ(ierr);
7115   for (l = 0; l < numLeaves; ++l) {
7116     ranksNew[l]              = ranks[l];
7117     localPointsNew[l]        = l;
7118     remotePointsNew[l].index = 0;
7119     remotePointsNew[l].rank  = ranksNew[l];
7120   }
7121   ierr = PetscFree(ranks);CHKERRQ(ierr);
7122   if (processRanks) {ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);}
7123   else              {ierr = PetscFree(ranksNew);CHKERRQ(ierr);}
7124   if (sfProcess) {
7125     ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
7126     ierr = PetscObjectSetName((PetscObject) *sfProcess, "Process SF");CHKERRQ(ierr);
7127     ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
7128     ierr = PetscSFSetGraph(*sfProcess, size, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7129   }
7130   PetscFunctionReturn(0);
7131 }
7132 
7133 static PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7134 {
7135   PetscSF            sf, sfNew, sfProcess;
7136   IS                 processRanks;
7137   MPI_Datatype       depthType;
7138   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
7139   const PetscInt    *localPoints, *neighbors;
7140   const PetscSFNode *remotePoints;
7141   PetscInt          *localPointsNew;
7142   PetscSFNode       *remotePointsNew;
7143   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
7144   PetscInt           ldepth, depth, numNeighbors, pStartNew, pEndNew, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r, n;
7145   PetscInt           cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
7146   PetscErrorCode     ierr;
7147 
7148   PetscFunctionBegin;
7149   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
7150   ierr = DMPlexGetDepth(dm, &ldepth);CHKERRQ(ierr);
7151   ierr = MPIU_Allreduce(&ldepth, &depth, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
7152   if ((ldepth >= 0) && (depth != ldepth)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent Plex depth %d != %d", ldepth, depth);
7153   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7154   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7155   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7156   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7157   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7158   cMax = cMax < 0 ? cEnd : cMax;
7159   fMax = fMax < 0 ? fEnd : fMax;
7160   eMax = eMax < 0 ? eEnd : eMax;
7161   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
7162   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
7163   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
7164   /* Calculate size of new SF */
7165   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
7166   if (numRoots < 0) PetscFunctionReturn(0);
7167   for (l = 0; l < numLeaves; ++l) {
7168     const PetscInt p = localPoints[l];
7169 
7170     switch (refiner) {
7171     case REFINER_SIMPLEX_1D:
7172       if ((p >= vStart) && (p < vEnd)) {
7173         /* Interior vertices stay the same */
7174         ++numLeavesNew;
7175       } else if ((p >= cStart && p < cMax)) {
7176         /* Interior cells add new cells and interior vertices */
7177         numLeavesNew += 2 + 1;
7178       }
7179       break;
7180     case REFINER_SIMPLEX_2D:
7181     case REFINER_HYBRID_SIMPLEX_2D:
7182       if ((p >= vStart) && (p < vEnd)) {
7183         /* Interior vertices stay the same */
7184         ++numLeavesNew;
7185       } else if ((p >= fStart) && (p < fMax)) {
7186         /* Interior faces add new faces and vertex */
7187         numLeavesNew += 2 + 1;
7188       } else if ((p >= fMax) && (p < fEnd)) {
7189         /* Hybrid faces stay the same */
7190         ++numLeavesNew;
7191       } else if ((p >= cStart) && (p < cMax)) {
7192         /* Interior cells add new cells and interior faces */
7193         numLeavesNew += 4 + 3;
7194       } else if ((p >= cMax) && (p < cEnd)) {
7195         /* Hybrid cells add new cells and hybrid face */
7196         numLeavesNew += 2 + 1;
7197       }
7198       break;
7199     case REFINER_SIMPLEX_TO_HEX_2D:
7200       if ((p >= vStart) && (p < vEnd)) {
7201         /* Interior vertices stay the same */
7202         ++numLeavesNew;
7203       } else if ((p >= fStart) && (p < fEnd)) {
7204         /* Interior faces add new faces and vertex */
7205         numLeavesNew += 2 + 1;
7206       } else if ((p >= cStart) && (p < cEnd)) {
7207         /* Interior cells add new cells, interior faces, and vertex */
7208         numLeavesNew += 3 + 3 + 1;
7209       }
7210       break;
7211     case REFINER_HEX_2D:
7212     case REFINER_HYBRID_HEX_2D:
7213       if ((p >= vStart) && (p < vEnd)) {
7214         /* Interior vertices stay the same */
7215         ++numLeavesNew;
7216       } else if ((p >= fStart) && (p < fMax)) {
7217         /* Interior faces add new faces and vertex */
7218         numLeavesNew += 2 + 1;
7219       } else if ((p >= fMax) && (p < fEnd)) {
7220         /* Hybrid faces stay the same */
7221         ++numLeavesNew;
7222       } else if ((p >= cStart) && (p < cMax)) {
7223         /* Interior cells add new cells, interior faces, and vertex */
7224         numLeavesNew += 4 + 4 + 1;
7225       } else if ((p >= cMax) && (p < cEnd)) {
7226         /* Hybrid cells add new cells and hybrid face */
7227         numLeavesNew += 2 + 1;
7228       }
7229       break;
7230     case REFINER_SIMPLEX_3D:
7231     case REFINER_HYBRID_SIMPLEX_3D:
7232       if ((p >= vStart) && (p < vEnd)) {
7233         /* Interior vertices stay the same */
7234         ++numLeavesNew;
7235       } else if ((p >= eStart) && (p < eMax)) {
7236         /* Interior edges add new edges and vertex */
7237         numLeavesNew += 2 + 1;
7238       } else if ((p >= eMax) && (p < eEnd)) {
7239         /* Hybrid edges stay the same */
7240         ++numLeavesNew;
7241       } else if ((p >= fStart) && (p < fMax)) {
7242         /* Interior faces add new faces and edges */
7243         numLeavesNew += 4 + 3;
7244       } else if ((p >= fMax) && (p < fEnd)) {
7245         /* Hybrid faces add new faces and edges */
7246         numLeavesNew += 2 + 1;
7247       } else if ((p >= cStart) && (p < cMax)) {
7248         /* Interior cells add new cells, faces, and edges */
7249         numLeavesNew += 8 + 8 + 1;
7250       } else if ((p >= cMax) && (p < cEnd)) {
7251         /* Hybrid cells add new cells and faces */
7252         numLeavesNew += 4 + 3;
7253       }
7254       break;
7255     case REFINER_SIMPLEX_TO_HEX_3D:
7256       if ((p >= vStart) && (p < vEnd)) {
7257         /* Interior vertices stay the same */
7258         ++numLeavesNew;
7259       } else if ((p >= eStart) && (p < eEnd)) {
7260         /* Interior edges add new edges and vertex */
7261         numLeavesNew += 2 + 1;
7262       } else if ((p >= fStart) && (p < fEnd)) {
7263         /* Interior faces add new faces, edges and a vertex */
7264         numLeavesNew += 3 + 3 + 1;
7265       } else if ((p >= cStart) && (p < cEnd)) {
7266         /* Interior cells add new cells, faces, edges and a vertex */
7267         numLeavesNew += 4 + 6 + 4 + 1;
7268       }
7269       break;
7270     case REFINER_HEX_3D:
7271     case REFINER_HYBRID_HEX_3D:
7272       if ((p >= vStart) && (p < vEnd)) {
7273         /* Old vertices stay the same */
7274         ++numLeavesNew;
7275       } else if ((p >= eStart) && (p < eMax)) {
7276         /* Interior edges add new edges, and vertex */
7277         numLeavesNew += 2 + 1;
7278       } else if ((p >= eMax) && (p < eEnd)) {
7279         /* Hybrid edges stay the same */
7280         ++numLeavesNew;
7281       } else if ((p >= fStart) && (p < fMax)) {
7282         /* Interior faces add new faces, edges, and vertex */
7283         numLeavesNew += 4 + 4 + 1;
7284       } else if ((p >= fMax) && (p < fEnd)) {
7285         /* Hybrid faces add new faces and edges */
7286         numLeavesNew += 2 + 1;
7287       } else if ((p >= cStart) && (p < cMax)) {
7288         /* Interior cells add new cells, faces, edges, and vertex */
7289         numLeavesNew += 8 + 12 + 6 + 1;
7290       } else if ((p >= cStart) && (p < cEnd)) {
7291         /* Hybrid cells add new cells, faces, and edges */
7292         numLeavesNew += 4 + 4 + 1;
7293       }
7294       break;
7295     default:
7296       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7297     }
7298   }
7299   /* Communicate depthSizes for each remote rank */
7300   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
7301   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
7302   ierr = PetscMalloc5((depth+1)*numNeighbors,&rdepthSize,numNeighbors,&rvStartNew,numNeighbors,&reStartNew,numNeighbors,&rfStartNew,numNeighbors,&rcStartNew);CHKERRQ(ierr);
7303   ierr = PetscMalloc7(depth+1,&depthSizeOld,(depth+1)*numNeighbors,&rdepthSizeOld,(depth+1)*numNeighbors,&rdepthMaxOld,numNeighbors,&rvStart,numNeighbors,&reStart,numNeighbors,&rfStart,numNeighbors,&rcStart);CHKERRQ(ierr);
7304   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
7305   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
7306   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7307   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7308   for (n = 0; n < numNeighbors; ++n) {
7309     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
7310   }
7311   depthSizeOld[depth]   = cMax;
7312   depthSizeOld[0]       = vMax;
7313   depthSizeOld[depth-1] = fMax;
7314   depthSizeOld[1]       = eMax;
7315 
7316   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7317   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7318 
7319   depthSizeOld[depth]   = cEnd - cStart;
7320   depthSizeOld[0]       = vEnd - vStart;
7321   depthSizeOld[depth-1] = fEnd - fStart;
7322   depthSizeOld[1]       = eEnd - eStart;
7323 
7324   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7325   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7326   for (n = 0; n < numNeighbors; ++n) {
7327     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
7328     rdepthMaxOld[n*(depth+1)+depth]   = rdepthMaxOld[n*(depth+1)+depth]   < 0 ? rdepthSizeOld[n*(depth+1)+depth]  +rcStart[n]: rdepthMaxOld[n*(depth+1)+depth];
7329     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];
7330     rdepthMaxOld[n*(depth+1)+1]       = rdepthMaxOld[n*(depth+1)+1]       < 0 ? rdepthSizeOld[n*(depth+1)+1]      +reStart[n]: rdepthMaxOld[n*(depth+1)+1];
7331   }
7332   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
7333   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
7334   /* Calculate new point SF */
7335   ierr = PetscMalloc1(numLeavesNew, &localPointsNew);CHKERRQ(ierr);
7336   ierr = PetscMalloc1(numLeavesNew, &remotePointsNew);CHKERRQ(ierr);
7337   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
7338   for (l = 0, m = 0; l < numLeaves; ++l) {
7339     PetscInt    p     = localPoints[l];
7340     PetscInt    rp    = remotePoints[l].index, n;
7341     PetscMPIInt rrank = remotePoints[l].rank;
7342 
7343     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
7344     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
7345     switch (refiner) {
7346     case REFINER_SIMPLEX_1D:
7347       if ((p >= vStart) && (p < vEnd)) {
7348         /* Old vertices stay the same */
7349         localPointsNew[m]        = vStartNew     + (p  - vStart);
7350         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7351         remotePointsNew[m].rank  = rrank;
7352         ++m;
7353       } else if ((p >= cStart) && (p < cMax)) {
7354         /* Old interior cells add new cells and vertex */
7355         for (r = 0; r < 2; ++r, ++m) {
7356           localPointsNew[m]        = cStartNew     + (p  - cStart)*2     + r;
7357           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*2 + r;
7358           remotePointsNew[m].rank  = rrank;
7359         }
7360         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - cStart);
7361         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rcStart[n]);
7362         remotePointsNew[m].rank  = rrank;
7363         ++m;
7364       }
7365       break;
7366     case REFINER_SIMPLEX_2D:
7367     case REFINER_HYBRID_SIMPLEX_2D:
7368       if ((p >= vStart) && (p < vEnd)) {
7369         /* Old vertices stay the same */
7370         localPointsNew[m]        = vStartNew     + (p  - vStart);
7371         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7372         remotePointsNew[m].rank  = rrank;
7373         ++m;
7374       } else if ((p >= fStart) && (p < fMax)) {
7375         /* Old interior faces add new faces and vertex */
7376         for (r = 0; r < 2; ++r, ++m) {
7377           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7378           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7379           remotePointsNew[m].rank  = rrank;
7380         }
7381         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7382         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7383         remotePointsNew[m].rank  = rrank;
7384         ++m;
7385       } else if ((p >= fMax) && (p < fEnd)) {
7386         /* Old hybrid faces stay the same */
7387         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
7388         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
7389         remotePointsNew[m].rank  = rrank;
7390         ++m;
7391       } else if ((p >= cStart) && (p < cMax)) {
7392         /* Old interior cells add new cells and interior faces */
7393         for (r = 0; r < 4; ++r, ++m) {
7394           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7395           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7396           remotePointsNew[m].rank  = rrank;
7397         }
7398         for (r = 0; r < 3; ++r, ++m) {
7399           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
7400           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
7401           remotePointsNew[m].rank  = rrank;
7402         }
7403       } else if ((p >= cMax) && (p < cEnd)) {
7404         /* Old hybrid cells add new cells and hybrid face */
7405         for (r = 0; r < 2; ++r, ++m) {
7406           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7407           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7408           remotePointsNew[m].rank  = rrank;
7409         }
7410         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
7411         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]);
7412         remotePointsNew[m].rank  = rrank;
7413         ++m;
7414       }
7415       break;
7416     case REFINER_SIMPLEX_TO_HEX_2D:
7417       if ((p >= vStart) && (p < vEnd)) {
7418         /* Old vertices stay the same */
7419         localPointsNew[m]        = vStartNew     + (p  - vStart);
7420         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7421         remotePointsNew[m].rank  = rrank;
7422         ++m;
7423       } else if ((p >= fStart) && (p < fEnd)) {
7424         /* Old interior faces add new faces and vertex */
7425         for (r = 0; r < 2; ++r, ++m) {
7426           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7427           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7428           remotePointsNew[m].rank  = rrank;
7429         }
7430         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7431         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7432         remotePointsNew[m].rank  = rrank;
7433         ++m;
7434       } else if ((p >= cStart) && (p < cEnd)) {
7435         /* Old interior cells add new cells, interior faces, and a vertex */
7436         for (r = 0; r < 3; ++r, ++m) {
7437           localPointsNew[m]        = cStartNew     + (p  - cStart)*3     + r;
7438           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*3 + r;
7439           remotePointsNew[m].rank  = rrank;
7440         }
7441         for (r = 0; r < 3; ++r, ++m) {
7442           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
7443           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
7444           remotePointsNew[m].rank  = rrank;
7445         }
7446         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (fEnd - fStart)                    + (p  - cStart);
7447         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
7448         remotePointsNew[m].rank  = rrank;
7449         ++m;
7450       }
7451       break;
7452     case REFINER_HEX_2D:
7453     case REFINER_HYBRID_HEX_2D:
7454       if ((p >= vStart) && (p < vEnd)) {
7455         /* Old vertices stay the same */
7456         localPointsNew[m]        = vStartNew     + (p  - vStart);
7457         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7458         remotePointsNew[m].rank  = rrank;
7459         ++m;
7460       } else if ((p >= fStart) && (p < fMax)) {
7461         /* Old interior faces add new faces and vertex */
7462         for (r = 0; r < 2; ++r, ++m) {
7463           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7464           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7465           remotePointsNew[m].rank  = rrank;
7466         }
7467         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7468         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7469         remotePointsNew[m].rank  = rrank;
7470         ++m;
7471       } else if ((p >= fMax) && (p < fEnd)) {
7472         /* Old hybrid faces stay the same */
7473         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
7474         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
7475         remotePointsNew[m].rank  = rrank;
7476         ++m;
7477       } else if ((p >= cStart) && (p < cMax)) {
7478         /* Old interior cells add new cells, interior faces, and vertex */
7479         for (r = 0; r < 4; ++r, ++m) {
7480           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7481           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7482           remotePointsNew[m].rank  = rrank;
7483         }
7484         for (r = 0; r < 4; ++r, ++m) {
7485           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*4     + r;
7486           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*4 + r;
7487           remotePointsNew[m].rank  = rrank;
7488         }
7489         localPointsNew[m]        = vStartNew     + (vEnd - vStart)               + (fMax                              - fStart)     + (p  - cStart);
7490         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0]  + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]);
7491         remotePointsNew[m].rank  = rrank;
7492         ++m;
7493       } else if ((p >= cStart) && (p < cMax)) {
7494         /* Old hybrid cells add new cells and hybrid face */
7495         for (r = 0; r < 2; ++r, ++m) {
7496           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7497           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7498           remotePointsNew[m].rank  = rrank;
7499         }
7500         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*4     + (p  - cMax);
7501         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]);
7502         remotePointsNew[m].rank  = rrank;
7503         ++m;
7504       }
7505       break;
7506     case REFINER_SIMPLEX_3D:
7507     case REFINER_HYBRID_SIMPLEX_3D:
7508       if ((p >= vStart) && (p < vEnd)) {
7509         /* Interior vertices stay the same */
7510         localPointsNew[m]        = vStartNew     + (p  - vStart);
7511         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7512         remotePointsNew[m].rank  = rrank;
7513         ++m;
7514       } else if ((p >= eStart) && (p < eMax)) {
7515         /* Interior edges add new edges and vertex */
7516         for (r = 0; r < 2; ++r, ++m) {
7517           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
7518           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
7519           remotePointsNew[m].rank  = rrank;
7520         }
7521         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
7522         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
7523         remotePointsNew[m].rank  = rrank;
7524         ++m;
7525       } else if ((p >= eMax) && (p < eEnd)) {
7526         /* Hybrid edges stay the same */
7527         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - eMax);
7528         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]);
7529         remotePointsNew[m].rank  = rrank;
7530         ++m;
7531       } else if ((p >= fStart) && (p < fMax)) {
7532         /* Interior faces add new faces and edges */
7533         for (r = 0; r < 4; ++r, ++m) {
7534           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
7535           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
7536           remotePointsNew[m].rank  = rrank;
7537         }
7538         for (r = 0; r < 3; ++r, ++m) {
7539           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*3     + r;
7540           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
7541           remotePointsNew[m].rank  = rrank;
7542         }
7543       } else if ((p >= fMax) && (p < fEnd)) {
7544         /* Hybrid faces add new faces and edges */
7545         for (r = 0; r < 2; ++r, ++m) {
7546           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fMax)*2                              + r;
7547           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;
7548           remotePointsNew[m].rank  = rrank;
7549         }
7550         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (eEnd                                    - eMax)                        + (p  - fMax);
7551         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]);
7552         remotePointsNew[m].rank  = rrank;
7553         ++m;
7554       } else if ((p >= cStart) && (p < cMax)) {
7555         /* Interior cells add new cells, faces, and edges */
7556         for (r = 0; r < 8; ++r, ++m) {
7557           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
7558           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
7559           remotePointsNew[m].rank  = rrank;
7560         }
7561         for (r = 0; r < 8; ++r, ++m) {
7562           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*8     + r;
7563           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*8 + r;
7564           remotePointsNew[m].rank  = rrank;
7565         }
7566         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (p  - cStart)*1     + 0;
7567         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;
7568         remotePointsNew[m].rank  = rrank;
7569         ++m;
7570       } else if ((p >= cMax) && (p < cEnd)) {
7571         /* Hybrid cells add new cells and faces */
7572         for (r = 0; r < 4; ++r, ++m) {
7573           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
7574           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
7575           remotePointsNew[m].rank  = rrank;
7576         }
7577         for (r = 0; r < 3; ++r, ++m) {
7578           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*2                              + (p  - cMax)*3                            + r;
7579           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;
7580           remotePointsNew[m].rank  = rrank;
7581         }
7582       }
7583       break;
7584     case REFINER_SIMPLEX_TO_HEX_3D:
7585       if ((p >= vStart) && (p < vEnd)) {
7586         /* Interior vertices stay the same */
7587         localPointsNew[m]        = vStartNew     + (p  - vStart);
7588         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7589         remotePointsNew[m].rank  = rrank;
7590         ++m;
7591       } else if ((p >= eStart) && (p < eEnd)) {
7592         /* Interior edges add new edges and vertex */
7593         for (r = 0; r < 2; ++r, ++m) {
7594           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
7595           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
7596           remotePointsNew[m].rank  = rrank;
7597         }
7598         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
7599         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
7600         remotePointsNew[m].rank  = rrank;
7601         ++m;
7602       } else if ((p >= fStart) && (p < fEnd)) {
7603         /* Interior faces add new faces, edges and a vertex */
7604         for (r = 0; r < 3; ++r, ++m) {
7605           localPointsNew[m]        = fStartNew     + (p  - fStart)*3     + r;
7606           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*3 + r;
7607           remotePointsNew[m].rank  = rrank;
7608         }
7609         for (r = 0; r < 3; ++r, ++m) {
7610           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2                + (p  - fStart)*3     + r;
7611           remotePointsNew[m].index = reStartNew[n] + (rdepthSizeOld[n*(depth+1)+1])*2 + (rp - rfStart[n])*3 + r;
7612           remotePointsNew[m].rank  = rrank;
7613         }
7614         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eEnd - eStart)              + (p - fStart);
7615         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+1] + (rp - rfStart[n]);
7616         remotePointsNew[m].rank  = rrank;
7617         ++m;
7618       } else if ((p >= cStart) && (p < cEnd)) {
7619         /* Interior cells add new cells, faces, edges, and a vertex */
7620         for (r = 0; r < 4; ++r, ++m) {
7621           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7622           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7623           remotePointsNew[m].rank  = rrank;
7624         }
7625         for (r = 0; r < 6; ++r, ++m) {
7626           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*3                    + (p  - cStart)*6     + r;
7627           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*3 + (rp - rcStart[n])*6 + r;
7628           remotePointsNew[m].rank  = rrank;
7629         }
7630         for (r = 0; r < 4; ++r, ++m) {
7631           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (fEnd - fStart)*3                    + (p  - cStart)*4 + r;
7632           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + rdepthSizeOld[n*(depth+1)+depth-1]*3 + (rp - rcStart[n])*4 + r;
7633           remotePointsNew[m].rank  = rrank;
7634         }
7635         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eEnd - eStart)              + (fEnd - fStart)                    + (p - cStart);
7636         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+1] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
7637         remotePointsNew[m].rank  = rrank;
7638         ++m;
7639       }
7640       break;
7641     case REFINER_HEX_3D:
7642     case REFINER_HYBRID_HEX_3D:
7643       if ((p >= vStart) && (p < vEnd)) {
7644         /* Interior vertices stay the same */
7645         localPointsNew[m]        = vStartNew     + (p  - vStart);
7646         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7647         remotePointsNew[m].rank  = rrank;
7648         ++m;
7649       } else if ((p >= eStart) && (p < eMax)) {
7650         /* Interior edges add new edges and vertex */
7651         for (r = 0; r < 2; ++r, ++m) {
7652           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
7653           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
7654           remotePointsNew[m].rank  = rrank;
7655         }
7656         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
7657         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
7658         remotePointsNew[m].rank  = rrank;
7659         ++m;
7660       } else if ((p >= eMax) && (p < eEnd)) {
7661         /* Hybrid edges stay the same */
7662         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (p  - eMax);
7663         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]);
7664         remotePointsNew[m].rank  = rrank;
7665         ++m;
7666       } else if ((p >= fStart) && (p < fMax)) {
7667         /* Interior faces add new faces, edges, and vertex */
7668         for (r = 0; r < 4; ++r, ++m) {
7669           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
7670           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
7671           remotePointsNew[m].rank  = rrank;
7672         }
7673         for (r = 0; r < 4; ++r, ++m) {
7674           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*4     + r;
7675           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*4 + r;
7676           remotePointsNew[m].rank  = rrank;
7677         }
7678         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax                        - eStart)     + (p  - fStart);
7679         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
7680         remotePointsNew[m].rank  = rrank;
7681         ++m;
7682       } else if ((p >= fMax) && (p < fEnd)) {
7683         /* Hybrid faces add new faces and edges */
7684         for (r = 0; r < 2; ++r, ++m) {
7685           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (p  - fMax)*2                              + r;
7686           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;
7687           remotePointsNew[m].rank  = rrank;
7688         }
7689         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (p  - fMax);
7690         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]);
7691         remotePointsNew[m].rank  = rrank;
7692         ++m;
7693       } else if ((p >= cStart) && (p < cMax)) {
7694         /* Interior cells add new cells, faces, edges, and vertex */
7695         for (r = 0; r < 8; ++r, ++m) {
7696           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
7697           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
7698           remotePointsNew[m].rank  = rrank;
7699         }
7700         for (r = 0; r < 12; ++r, ++m) {
7701           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*12     + r;
7702           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*12 + r;
7703           remotePointsNew[m].rank  = rrank;
7704         }
7705         for (r = 0; r < 6; ++r, ++m) {
7706           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (p  - cStart)*6     + r;
7707           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;
7708           remotePointsNew[m].rank  = rrank;
7709         }
7710         for (r = 0; r < 1; ++r, ++m) {
7711           localPointsNew[m]        = vStartNew     + (eMax                        - eStart)     + (fMax                              - fStart)     + (p  - cStart)     + r;
7712           remotePointsNew[m].index = rvStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]) + r;
7713           remotePointsNew[m].rank  = rrank;
7714         }
7715       } else if ((p >= cMax) && (p < cEnd)) {
7716         /* Hybrid cells add new cells, faces, and edges */
7717         for (r = 0; r < 4; ++r, ++m) {
7718           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
7719           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
7720           remotePointsNew[m].rank  = rrank;
7721         }
7722         for (r = 0; r < 4; ++r, ++m) {
7723           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (fEnd                                          - fMax)*2                              + (p  - cMax)*4                            + r;
7724           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;
7725           remotePointsNew[m].rank  = rrank;
7726         }
7727         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (fEnd                                          - fMax)                              + (p  - cMax);
7728         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]);
7729         remotePointsNew[m].rank  = rrank;
7730         ++m;
7731       }
7732       break;
7733     default:
7734       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7735     }
7736   }
7737   if (m != numLeavesNew) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of leaf point %d should be %d", m, numLeavesNew);
7738   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
7739   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
7740   {
7741     PetscSFNode *rp, *rtmp;
7742     PetscInt    *lp, *idx, *ltmp, i;
7743 
7744     /* SF needs sorted leaves to correct calculate Gather */
7745     ierr = PetscMalloc1(numLeavesNew,&idx);CHKERRQ(ierr);
7746     ierr = PetscMalloc1(numLeavesNew, &lp);CHKERRQ(ierr);
7747     ierr = PetscMalloc1(numLeavesNew, &rp);CHKERRQ(ierr);
7748     for (i = 0; i < numLeavesNew; ++i) {
7749       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);
7750       idx[i] = i;
7751     }
7752     ierr = PetscSortIntWithPermutation(numLeavesNew, localPointsNew, idx);CHKERRQ(ierr);
7753     for (i = 0; i < numLeavesNew; ++i) {
7754       lp[i] = localPointsNew[idx[i]];
7755       rp[i] = remotePointsNew[idx[i]];
7756     }
7757     ltmp            = localPointsNew;
7758     localPointsNew  = lp;
7759     rtmp            = remotePointsNew;
7760     remotePointsNew = rp;
7761     ierr = PetscFree(idx);CHKERRQ(ierr);
7762     ierr = PetscFree(ltmp);CHKERRQ(ierr);
7763     ierr = PetscFree(rtmp);CHKERRQ(ierr);
7764   }
7765   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7766   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
7767   ierr = PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
7768   PetscFunctionReturn(0);
7769 }
7770 
7771 static PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7772 {
7773   PetscInt       numLabels, l;
7774   PetscInt       depth, newp, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r;
7775   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
7776   PetscErrorCode ierr;
7777 
7778   PetscFunctionBegin;
7779   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7780   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7781   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7782   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7783   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7784   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
7785   ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
7786   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7787   switch (refiner) {
7788   case REFINER_NOOP:
7789   case REFINER_SIMPLEX_1D:
7790   case REFINER_SIMPLEX_2D:
7791   case REFINER_SIMPLEX_TO_HEX_2D:
7792   case REFINER_HEX_2D:
7793   case REFINER_SIMPLEX_3D:
7794   case REFINER_HEX_3D:
7795   case REFINER_SIMPLEX_TO_HEX_3D:
7796     break;
7797   case REFINER_HYBRID_SIMPLEX_3D:
7798   case REFINER_HYBRID_HEX_3D:
7799     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
7800   case REFINER_HYBRID_SIMPLEX_2D:
7801   case REFINER_HYBRID_HEX_2D:
7802     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7803     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7804     break;
7805   default:
7806     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7807   }
7808   for (l = 0; l < numLabels; ++l) {
7809     DMLabel         label, labelNew;
7810     const char     *lname;
7811     PetscBool       isDepth;
7812     IS              valueIS;
7813     const PetscInt *values;
7814     PetscInt        defVal;
7815     PetscInt        numValues, val;
7816 
7817     ierr = DMGetLabelName(dm, l, &lname);CHKERRQ(ierr);
7818     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
7819     if (isDepth) continue;
7820     ierr = DMCreateLabel(rdm, lname);CHKERRQ(ierr);
7821     ierr = DMGetLabel(dm, lname, &label);CHKERRQ(ierr);
7822     ierr = DMGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
7823     ierr = DMLabelGetDefaultValue(label,&defVal);CHKERRQ(ierr);
7824     ierr = DMLabelSetDefaultValue(labelNew,defVal);CHKERRQ(ierr);
7825     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
7826     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
7827     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
7828     for (val = 0; val < numValues; ++val) {
7829       IS              pointIS;
7830       const PetscInt *points;
7831       PetscInt        numPoints, n;
7832 
7833       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
7834       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
7835       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
7836       /* Ensure refined label is created with same number of strata as
7837        * original (even if no entries here). */
7838       ierr = DMLabelAddStratum(labelNew, values[val]);CHKERRQ(ierr);
7839       for (n = 0; n < numPoints; ++n) {
7840         const PetscInt p = points[n];
7841         switch (refiner) {
7842         case REFINER_SIMPLEX_1D:
7843           if ((p >= vStart) && (p < vEnd)) {
7844             /* Old vertices stay the same */
7845             newp = vStartNew + (p - vStart);
7846             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7847           } else if ((p >= cStart) && (p < cEnd)) {
7848             /* Old cells add new cells and vertex */
7849             newp = vStartNew + (vEnd - vStart) + (p - cStart);
7850             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7851             for (r = 0; r < 2; ++r) {
7852               newp = cStartNew + (p - cStart)*2 + r;
7853               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7854             }
7855           }
7856           break;
7857         case REFINER_SIMPLEX_2D:
7858           if ((p >= vStart) && (p < vEnd)) {
7859             /* Old vertices stay the same */
7860             newp = vStartNew + (p - vStart);
7861             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7862           } else if ((p >= fStart) && (p < fEnd)) {
7863             /* Old faces add new faces and vertex */
7864             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7865             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7866             for (r = 0; r < 2; ++r) {
7867               newp = fStartNew + (p - fStart)*2 + r;
7868               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7869             }
7870           } else if ((p >= cStart) && (p < cEnd)) {
7871             /* Old cells add new cells and interior faces */
7872             for (r = 0; r < 4; ++r) {
7873               newp = cStartNew + (p - cStart)*4 + r;
7874               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7875             }
7876             for (r = 0; r < 3; ++r) {
7877               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7878               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7879             }
7880           }
7881           break;
7882         case REFINER_SIMPLEX_TO_HEX_2D:
7883           if ((p >= vStart) && (p < vEnd)) {
7884             /* Old vertices stay the same */
7885             newp = vStartNew + (p - vStart);
7886             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7887           } else if ((p >= fStart) && (p < fEnd)) {
7888             /* Old faces add new faces and vertex */
7889             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7890             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7891             for (r = 0; r < 2; ++r) {
7892               newp = fStartNew + (p - fStart)*2 + r;
7893               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7894             }
7895           } else if ((p >= cStart) && (p < cEnd)) {
7896             /* Old cells add new cells, interior faces, and a vertex */
7897             for (r = 0; r < 3; ++r) {
7898               newp = cStartNew + (p - cStart)*3 + r;
7899               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7900             }
7901             for (r = 0; r < 3; ++r) {
7902               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7903               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7904             }
7905             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + p;
7906             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7907           }
7908           break;
7909         case REFINER_HEX_2D:
7910           if ((p >= vStart) && (p < vEnd)) {
7911             /* Old vertices stay the same */
7912             newp = vStartNew + (p - vStart);
7913             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7914           } else if ((p >= fStart) && (p < fEnd)) {
7915             /* Old faces add new faces and vertex */
7916             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7917             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7918             for (r = 0; r < 2; ++r) {
7919               newp = fStartNew + (p - fStart)*2 + r;
7920               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7921             }
7922           } else if ((p >= cStart) && (p < cEnd)) {
7923             /* Old cells add new cells and interior faces and vertex */
7924             for (r = 0; r < 4; ++r) {
7925               newp = cStartNew + (p - cStart)*4 + r;
7926               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7927             }
7928             for (r = 0; r < 4; ++r) {
7929               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
7930               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7931             }
7932             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
7933             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7934           }
7935           break;
7936         case REFINER_HYBRID_SIMPLEX_2D:
7937           if ((p >= vStart) && (p < vEnd)) {
7938             /* Old vertices stay the same */
7939             newp = vStartNew + (p - vStart);
7940             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7941           } else if ((p >= fStart) && (p < fMax)) {
7942             /* Old interior faces add new faces and vertex */
7943             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7944             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7945             for (r = 0; r < 2; ++r) {
7946               newp = fStartNew + (p - fStart)*2 + r;
7947               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7948             }
7949           } else if ((p >= fMax) && (p < fEnd)) {
7950             /* Old hybrid faces stay the same */
7951             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7952             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7953           } else if ((p >= cStart) && (p < cMax)) {
7954             /* Old interior cells add new cells and interior faces */
7955             for (r = 0; r < 4; ++r) {
7956               newp = cStartNew + (p - cStart)*4 + r;
7957               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7958             }
7959             for (r = 0; r < 3; ++r) {
7960               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7961               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7962             }
7963           } else if ((p >= cMax) && (p < cEnd)) {
7964             /* Old hybrid cells add new cells and hybrid face */
7965             for (r = 0; r < 2; ++r) {
7966               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
7967               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7968             }
7969             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
7970             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7971           }
7972           break;
7973         case REFINER_HYBRID_HEX_2D:
7974           if ((p >= vStart) && (p < vEnd)) {
7975             /* Old vertices stay the same */
7976             newp = vStartNew + (p - vStart);
7977             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7978           } else if ((p >= fStart) && (p < fMax)) {
7979             /* Old interior faces add new faces and vertex */
7980             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7981             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7982             for (r = 0; r < 2; ++r) {
7983               newp = fStartNew + (p - fStart)*2 + r;
7984               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7985             }
7986           } else if ((p >= fMax) && (p < fEnd)) {
7987             /* Old hybrid faces stay the same */
7988             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7989             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7990           } else if ((p >= cStart) && (p < cMax)) {
7991             /* Old interior cells add new cells, interior faces, and vertex */
7992             for (r = 0; r < 4; ++r) {
7993               newp = cStartNew + (p - cStart)*4 + r;
7994               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7995             }
7996             for (r = 0; r < 4; ++r) {
7997               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
7998               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7999             }
8000             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
8001             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8002           } else if ((p >= cMax) && (p < cEnd)) {
8003             /* Old hybrid cells add new cells and hybrid face */
8004             for (r = 0; r < 2; ++r) {
8005               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
8006               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8007             }
8008             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (p - cMax);
8009             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8010           }
8011           break;
8012         case REFINER_SIMPLEX_3D:
8013           if ((p >= vStart) && (p < vEnd)) {
8014             /* Old vertices stay the same */
8015             newp = vStartNew + (p - vStart);
8016             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8017           } else if ((p >= eStart) && (p < eEnd)) {
8018             /* Old edges add new edges and vertex */
8019             for (r = 0; r < 2; ++r) {
8020               newp = eStartNew + (p - eStart)*2 + r;
8021               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8022             }
8023             newp = vStartNew + (vEnd - vStart) + (p - eStart);
8024             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8025           } else if ((p >= fStart) && (p < fEnd)) {
8026             /* Old faces add new faces and edges */
8027             for (r = 0; r < 4; ++r) {
8028               newp = fStartNew + (p - fStart)*4 + r;
8029               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8030             }
8031             for (r = 0; r < 3; ++r) {
8032               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
8033               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8034             }
8035           } else if ((p >= cStart) && (p < cEnd)) {
8036             /* Old cells add new cells and interior faces and edges */
8037             for (r = 0; r < 8; ++r) {
8038               newp = cStartNew + (p - cStart)*8 + r;
8039               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8040             }
8041             for (r = 0; r < 8; ++r) {
8042               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*8 + r;
8043               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8044             }
8045             for (r = 0; r < 1; ++r) {
8046               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*1 + r;
8047               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8048             }
8049           }
8050           break;
8051         case REFINER_SIMPLEX_TO_HEX_3D:
8052           if ((p >= vStart) && (p < vEnd)) {
8053             /* Old vertices stay the same */
8054             newp = vStartNew + (p - vStart);
8055             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8056           } else if ((p >= eStart) && (p < eEnd)) {
8057             /* Old edges add new edges and vertex */
8058             for (r = 0; r < 2; ++r) {
8059               newp = eStartNew + (p - eStart)*2 + r;
8060               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8061             }
8062             newp = vStartNew + (vEnd - vStart) + (p - eStart);
8063             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8064           } else if ((p >= fStart) && (p < fEnd)) {
8065             /* Old faces add new faces, edges and a vertex */
8066             for (r = 0; r < 3; ++r) {
8067               newp = fStartNew + (p - fStart)*3 + r;
8068               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8069             }
8070             for (r = 0; r < 3; ++r) {
8071               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
8072               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8073             }
8074           } else if ((p >= cStart) && (p < cEnd)) {
8075             /* Old cells add new cells and interior faces and edges and a vertex */
8076             for (r = 0; r < 4; ++r) {
8077               newp = cStartNew + (p - cStart)*4 + r;
8078               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8079             }
8080             for (r = 0; r < 6; ++r) {
8081               newp = fStartNew + (fEnd - fStart)*3 + (p - cStart)*6 + r;
8082               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8083             }
8084             for (r = 0; r < 4; ++r) {
8085               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*4 + r;
8086               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8087             }
8088             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + p - cStart;
8089             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8090           }
8091           break;
8092         case REFINER_HYBRID_SIMPLEX_3D:
8093           if ((p >= vStart) && (p < vEnd)) {
8094             /* Interior vertices stay the same */
8095             newp = vStartNew + (p - vStart);
8096             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8097           } else if ((p >= eStart) && (p < eMax)) {
8098             /* Interior edges add new edges and vertex */
8099             for (r = 0; r < 2; ++r) {
8100               newp = eStartNew + (p - eStart)*2 + r;
8101               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8102             }
8103             newp = vStartNew + (vEnd - vStart) + (p - eStart);
8104             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8105           } else if ((p >= eMax) && (p < eEnd)) {
8106             /* Hybrid edges stay the same */
8107             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - eMax);
8108             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8109           } else if ((p >= fStart) && (p < fMax)) {
8110             /* Interior faces add new faces and edges */
8111             for (r = 0; r < 4; ++r) {
8112               newp = fStartNew + (p - fStart)*4 + r;
8113               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8114             }
8115             for (r = 0; r < 3; ++r) {
8116               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
8117               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8118             }
8119           } else if ((p >= fMax) && (p < fEnd)) {
8120             /* Hybrid faces add new faces and edges */
8121             for (r = 0; r < 2; ++r) {
8122               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (p - fMax)*2 + r;
8123               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8124             }
8125             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - fMax);
8126             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8127           } else if ((p >= cStart) && (p < cMax)) {
8128             /* Interior cells add new cells, faces, and edges */
8129             for (r = 0; r < 8; ++r) {
8130               newp = cStartNew + (p - cStart)*8 + r;
8131               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8132             }
8133             for (r = 0; r < 8; ++r) {
8134               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*8 + r;
8135               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8136             }
8137             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart);
8138             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8139           } else if ((p >= cMax) && (p < cEnd)) {
8140             /* Hybrid cells add new cells and faces */
8141             for (r = 0; r < 4; ++r) {
8142               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
8143               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8144             }
8145             for (r = 0; r < 3; ++r) {
8146               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
8147               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8148             }
8149           }
8150           break;
8151         case REFINER_HEX_3D:
8152           if ((p >= vStart) && (p < vEnd)) {
8153             /* Old vertices stay the same */
8154             newp = vStartNew + (p - vStart);
8155             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8156           } else if ((p >= eStart) && (p < eEnd)) {
8157             /* Old edges add new edges and vertex */
8158             for (r = 0; r < 2; ++r) {
8159               newp = eStartNew + (p - eStart)*2 + r;
8160               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8161             }
8162             newp = vStartNew + (vEnd - vStart) + (p - eStart);
8163             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8164           } else if ((p >= fStart) && (p < fEnd)) {
8165             /* Old faces add new faces, edges, and vertex */
8166             for (r = 0; r < 4; ++r) {
8167               newp = fStartNew + (p - fStart)*4 + r;
8168               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8169             }
8170             for (r = 0; r < 4; ++r) {
8171               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*4 + r;
8172               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8173             }
8174             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (p - fStart);
8175             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8176           } else if ((p >= cStart) && (p < cEnd)) {
8177             /* Old cells add new cells, faces, edges, and vertex */
8178             for (r = 0; r < 8; ++r) {
8179               newp = cStartNew + (p - cStart)*8 + r;
8180               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8181             }
8182             for (r = 0; r < 12; ++r) {
8183               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*12 + r;
8184               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8185             }
8186             for (r = 0; r < 6; ++r) {
8187               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (p - cStart)*6 + r;
8188               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8189             }
8190             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (p - cStart);
8191             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8192           }
8193           break;
8194         case REFINER_HYBRID_HEX_3D:
8195           if ((p >= vStart) && (p < vEnd)) {
8196             /* Interior vertices stay the same */
8197             newp = vStartNew + (p - vStart);
8198             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8199           } else if ((p >= eStart) && (p < eMax)) {
8200             /* Interior edges add new edges and vertex */
8201             for (r = 0; r < 2; ++r) {
8202               newp = eStartNew + (p - eStart)*2 + r;
8203               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8204             }
8205             newp = vStartNew + (vEnd - vStart) + (p - eStart);
8206             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8207           } else if ((p >= eMax) && (p < eEnd)) {
8208             /* Hybrid edges stay the same */
8209             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - eMax);
8210             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8211           } else if ((p >= fStart) && (p < fMax)) {
8212             /* Interior faces add new faces, edges, and vertex */
8213             for (r = 0; r < 4; ++r) {
8214               newp = fStartNew + (p - fStart)*4 + r;
8215               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8216             }
8217             for (r = 0; r < 4; ++r) {
8218               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*4 + r;
8219               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8220             }
8221             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (p - fStart);
8222             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8223           } else if ((p >= fMax) && (p < fEnd)) {
8224             /* Hybrid faces add new faces and edges */
8225             for (r = 0; r < 2; ++r) {
8226               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (p - fMax)*2 + r;
8227               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8228             }
8229             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - fMax);
8230             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8231           } else if ((p >= cStart) && (p < cMax)) {
8232             /* Interior cells add new cells, faces, edges, and vertex */
8233             for (r = 0; r < 8; ++r) {
8234               newp = cStartNew + (p - cStart)*8 + r;
8235               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8236             }
8237             for (r = 0; r < 12; ++r) {
8238               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*12 + r;
8239               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8240             }
8241             for (r = 0; r < 6; ++r) {
8242               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (p - cStart)*6 + r;
8243               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8244             }
8245             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (p - cStart);
8246             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8247           } else if ((p >= cMax) && (p < cEnd)) {
8248             /* Hybrid cells add new cells, faces, and edges */
8249             for (r = 0; r < 4; ++r) {
8250               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
8251               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8252             }
8253             for (r = 0; r < 4; ++r) {
8254               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (p - cMax)*4 + r;
8255               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8256             }
8257             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (fEnd - fMax) + (p - cMax);
8258             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8259           }
8260           break;
8261         default:
8262           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
8263         }
8264       }
8265       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
8266       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
8267     }
8268     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
8269     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
8270     if (0) {
8271       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
8272     }
8273   }
8274   PetscFunctionReturn(0);
8275 }
8276 
8277 /* This will only work for interpolated meshes */
8278 PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
8279 {
8280   DM             rdm;
8281   PetscInt      *depthSize;
8282   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
8283   PetscErrorCode ierr;
8284 
8285   PetscFunctionBegin;
8286   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
8287   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
8288   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
8289   ierr = DMSetDimension(rdm, dim);CHKERRQ(ierr);
8290   /* Calculate number of new points of each depth */
8291   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
8292   if (depth >= 0 && dim != depth) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Mesh must be interpolated for regular refinement");
8293   ierr = PetscMalloc1(depth+1, &depthSize);CHKERRQ(ierr);
8294   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
8295   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
8296   /* Step 1: Set chart */
8297   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
8298   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
8299   /* Step 2: Set cone/support sizes */
8300   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
8301   /* Step 3: Setup refined DM */
8302   ierr = DMSetUp(rdm);CHKERRQ(ierr);
8303   /* Step 4: Set cones and supports */
8304   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
8305   /* Step 5: Stratify */
8306   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
8307   /* Step 6: Create pointSF */
8308   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
8309   /* Step 7: Create labels */
8310   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
8311   /* Step 8: Set coordinates */
8312   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
8313   ierr = PetscFree(depthSize);CHKERRQ(ierr);
8314 
8315   *dmRefined = rdm;
8316   PetscFunctionReturn(0);
8317 }
8318 
8319 /*@
8320   DMPlexCreateCoarsePointIS - Creates an IS covering the coarse DM chart with the fine points as data
8321 
8322   Input Parameter:
8323 . dm - The coarse DM
8324 
8325   Output Parameter:
8326 . fpointIS - The IS of all the fine points which exist in the original coarse mesh
8327 
8328   Level: developer
8329 
8330 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexCreateSubpointIS()
8331 @*/
8332 PetscErrorCode DMPlexCreateCoarsePointIS(DM dm, IS *fpointIS)
8333 {
8334   CellRefiner    cellRefiner;
8335   PetscInt      *depthSize, *fpoints;
8336   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
8337   PetscInt       depth, pStart, pEnd, p, vStart, vEnd, v;
8338   PetscErrorCode ierr;
8339 
8340   PetscFunctionBegin;
8341   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
8342   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
8343   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8344   ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr);
8345   ierr = PetscMalloc1(depth+1, &depthSize);CHKERRQ(ierr);
8346   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
8347   if (cellRefiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
8348   ierr = PetscMalloc1(pEnd-pStart,&fpoints);CHKERRQ(ierr);
8349   for (p = 0; p < pEnd-pStart; ++p) fpoints[p] = -1;
8350   switch (cellRefiner) {
8351   case REFINER_SIMPLEX_1D:
8352   case REFINER_SIMPLEX_2D:
8353   case REFINER_HYBRID_SIMPLEX_2D:
8354   case REFINER_HEX_2D:
8355   case REFINER_HYBRID_HEX_2D:
8356   case REFINER_SIMPLEX_3D:
8357   case REFINER_HYBRID_SIMPLEX_3D:
8358   case REFINER_HEX_3D:
8359   case REFINER_HYBRID_HEX_3D:
8360     for (v = vStart; v < vEnd; ++v) fpoints[v-pStart] = vStartNew + (v - vStart);
8361     break;
8362   default:
8363     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", cellRefiner);
8364   }
8365   ierr = ISCreateGeneral(PETSC_COMM_SELF, pEnd-pStart, fpoints, PETSC_OWN_POINTER, fpointIS);CHKERRQ(ierr);
8366   ierr = PetscFree(depthSize);CHKERRQ(ierr);
8367   PetscFunctionReturn(0);
8368 }
8369 
8370 /*@
8371   DMPlexSetRefinementUniform - Set the flag for uniform refinement
8372 
8373   Input Parameters:
8374 + dm - The DM
8375 - refinementUniform - The flag for uniform refinement
8376 
8377   Level: developer
8378 
8379 .seealso: DMRefine(), DMPlexGetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
8380 @*/
8381 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
8382 {
8383   DM_Plex *mesh = (DM_Plex*) dm->data;
8384 
8385   PetscFunctionBegin;
8386   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8387   mesh->refinementUniform = refinementUniform;
8388   PetscFunctionReturn(0);
8389 }
8390 
8391 /*@
8392   DMPlexGetRefinementUniform - Retrieve the flag for uniform refinement
8393 
8394   Input Parameter:
8395 . dm - The DM
8396 
8397   Output Parameter:
8398 . refinementUniform - The flag for uniform refinement
8399 
8400   Level: developer
8401 
8402 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
8403 @*/
8404 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
8405 {
8406   DM_Plex *mesh = (DM_Plex*) dm->data;
8407 
8408   PetscFunctionBegin;
8409   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8410   PetscValidPointer(refinementUniform,  2);
8411   *refinementUniform = mesh->refinementUniform;
8412   PetscFunctionReturn(0);
8413 }
8414 
8415 /*@
8416   DMPlexSetRefinementLimit - Set the maximum cell volume for refinement
8417 
8418   Input Parameters:
8419 + dm - The DM
8420 - refinementLimit - The maximum cell volume in the refined mesh
8421 
8422   Level: developer
8423 
8424 .seealso: DMRefine(), DMPlexGetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
8425 @*/
8426 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
8427 {
8428   DM_Plex *mesh = (DM_Plex*) dm->data;
8429 
8430   PetscFunctionBegin;
8431   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8432   mesh->refinementLimit = refinementLimit;
8433   PetscFunctionReturn(0);
8434 }
8435 
8436 /*@
8437   DMPlexGetRefinementLimit - Retrieve the maximum cell volume for refinement
8438 
8439   Input Parameter:
8440 . dm - The DM
8441 
8442   Output Parameter:
8443 . refinementLimit - The maximum cell volume in the refined mesh
8444 
8445   Level: developer
8446 
8447 .seealso: DMRefine(), DMPlexSetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
8448 @*/
8449 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
8450 {
8451   DM_Plex *mesh = (DM_Plex*) dm->data;
8452 
8453   PetscFunctionBegin;
8454   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8455   PetscValidPointer(refinementLimit,  2);
8456   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
8457   *refinementLimit = mesh->refinementLimit;
8458   PetscFunctionReturn(0);
8459 }
8460 
8461 /*@
8462   DMPlexSetRefinementFunction - Set the function giving the maximum cell volume for refinement
8463 
8464   Input Parameters:
8465 + dm - The DM
8466 - refinementFunc - Function giving the maximum cell volume in the refined mesh
8467 
8468   Note: The calling sequence is refinementFunc(coords, limit)
8469 $ coords - Coordinates of the current point, usually a cell centroid
8470 $ limit  - The maximum cell volume for a cell containing this point
8471 
8472   Level: developer
8473 
8474 .seealso: DMRefine(), DMPlexGetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
8475 @*/
8476 PetscErrorCode DMPlexSetRefinementFunction(DM dm, PetscErrorCode (*refinementFunc)(const PetscReal [], PetscReal *))
8477 {
8478   DM_Plex *mesh = (DM_Plex*) dm->data;
8479 
8480   PetscFunctionBegin;
8481   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8482   mesh->refinementFunc = refinementFunc;
8483   PetscFunctionReturn(0);
8484 }
8485 
8486 /*@
8487   DMPlexGetRefinementFunction - Get the function giving the maximum cell volume for refinement
8488 
8489   Input Parameter:
8490 . dm - The DM
8491 
8492   Output Parameter:
8493 . refinementFunc - Function giving the maximum cell volume in the refined mesh
8494 
8495   Note: The calling sequence is refinementFunc(coords, limit)
8496 $ coords - Coordinates of the current point, usually a cell centroid
8497 $ limit  - The maximum cell volume for a cell containing this point
8498 
8499   Level: developer
8500 
8501 .seealso: DMRefine(), DMPlexSetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
8502 @*/
8503 PetscErrorCode DMPlexGetRefinementFunction(DM dm, PetscErrorCode (**refinementFunc)(const PetscReal [], PetscReal *))
8504 {
8505   DM_Plex *mesh = (DM_Plex*) dm->data;
8506 
8507   PetscFunctionBegin;
8508   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8509   PetscValidPointer(refinementFunc,  2);
8510   *refinementFunc = mesh->refinementFunc;
8511   PetscFunctionReturn(0);
8512 }
8513 
8514 PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
8515 {
8516   PetscInt       dim, cStart, cEnd, coneSize, cMax, fMax;
8517   PetscErrorCode ierr;
8518 
8519   PetscFunctionBegin;
8520   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
8521   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8522   if (cEnd <= cStart) {*cellRefiner = REFINER_NOOP; PetscFunctionReturn(0);}
8523   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
8524   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, NULL, NULL);CHKERRQ(ierr);
8525   switch (dim) {
8526   case 1:
8527     switch (coneSize) {
8528     case 2:
8529       *cellRefiner = REFINER_SIMPLEX_1D;
8530       break;
8531     default:
8532       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
8533     }
8534     break;
8535   case 2:
8536     switch (coneSize) {
8537     case 3:
8538       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_2D;
8539       else *cellRefiner = REFINER_SIMPLEX_2D;
8540       break;
8541     case 4:
8542       if (cMax >= 0 && fMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_2D;
8543       else *cellRefiner = REFINER_HEX_2D;
8544       break;
8545     default:
8546       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
8547     }
8548     break;
8549   case 3:
8550     switch (coneSize) {
8551     case 4:
8552       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_3D;
8553       else *cellRefiner = REFINER_SIMPLEX_3D;
8554       break;
8555     case 6:
8556       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_3D;
8557       else *cellRefiner = REFINER_HEX_3D;
8558       break;
8559     default:
8560       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
8561     }
8562     break;
8563   default:
8564     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
8565   }
8566   PetscFunctionReturn(0);
8567 }
8568 
8569 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
8570 {
8571   PetscBool      isUniform;
8572   PetscErrorCode ierr;
8573 
8574   PetscFunctionBegin;
8575   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
8576   if (isUniform) {
8577     CellRefiner cellRefiner;
8578     PetscBool   localized;
8579 
8580     ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
8581     ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr);
8582     ierr = DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
8583     ierr = DMCopyBoundary(dm, *dmRefined);CHKERRQ(ierr);
8584     if (localized) {ierr = DMLocalizeCoordinates(*dmRefined);CHKERRQ(ierr);}
8585   } else {
8586     ierr = DMPlexRefine_Internal(dm, NULL, dmRefined);CHKERRQ(ierr);
8587   }
8588   PetscFunctionReturn(0);
8589 }
8590 
8591 PetscErrorCode DMRefineHierarchy_Plex(DM dm, PetscInt nlevels, DM dmRefined[])
8592 {
8593   DM             cdm = dm;
8594   PetscInt       r;
8595   PetscBool      isUniform, localized;
8596   PetscErrorCode ierr;
8597 
8598   PetscFunctionBegin;
8599   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
8600   ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
8601   if (isUniform) {
8602     for (r = 0; r < nlevels; ++r) {
8603       CellRefiner cellRefiner;
8604 
8605       ierr = DMPlexGetCellRefiner_Internal(cdm, &cellRefiner);CHKERRQ(ierr);
8606       ierr = DMPlexRefineUniform_Internal(cdm, cellRefiner, &dmRefined[r]);CHKERRQ(ierr);
8607       ierr = DMCopyBoundary(cdm, dmRefined[r]);CHKERRQ(ierr);
8608       if (localized) {ierr = DMLocalizeCoordinates(dmRefined[r]);CHKERRQ(ierr);}
8609       ierr = DMSetCoarseDM(dmRefined[r], cdm);CHKERRQ(ierr);
8610       ierr = DMPlexSetRegularRefinement(dmRefined[r], PETSC_TRUE);CHKERRQ(ierr);
8611       cdm  = dmRefined[r];
8612     }
8613   } else {
8614     for (r = 0; r < nlevels; ++r) {
8615       ierr = DMRefine(cdm, PetscObjectComm((PetscObject) dm), &dmRefined[r]);CHKERRQ(ierr);
8616       ierr = DMCopyBoundary(cdm, dmRefined[r]);CHKERRQ(ierr);
8617       if (localized) {ierr = DMLocalizeCoordinates(dmRefined[r]);CHKERRQ(ierr);}
8618       ierr = DMSetCoarseDM(dmRefined[r], cdm);CHKERRQ(ierr);
8619       cdm  = dmRefined[r];
8620     }
8621   }
8622   PetscFunctionReturn(0);
8623 }
8624