xref: /petsc/src/dm/impls/plex/plexrefine.c (revision 02f1c2d0737cbecdb61f912a046d7b7d95fc755b)
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 = DMGetPeriodicity(dm, &isperiodic, &maxCell, &L, &bd);CHKERRQ(ierr);
6501   /* Determine if we need to localize coordinates when generating them */
6502   if (isperiodic && !maxCell) {
6503     ierr = DMGetCoordinatesLocalized(dm, &localize);CHKERRQ(ierr);
6504     if (!localize) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Cannot refine if coordinates have not been localized");
6505   }
6506   if (isperiodic) {
6507     ierr = PetscOptionsBegin(PetscObjectComm((PetscObject)dm),((PetscObject)dm)->prefix,"DMPlex coords refinement options","DM");CHKERRQ(ierr);
6508     ierr = PetscOptionsBool("-dm_plex_refine_localize","Automatically localize from parent cells",NULL,localize,&localize,NULL);CHKERRQ(ierr);
6509     ierr = PetscOptionsEnd();CHKERRQ(ierr);
6510     if (localize) {
6511       ierr = DMLocalizeCoordinates(dm);CHKERRQ(ierr);
6512     }
6513   }
6514   ierr = DMSetPeriodicity(rdm, isperiodic,  maxCell,  L,  bd);CHKERRQ(ierr);
6515 
6516   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6517   ierr = PetscSectionGetFieldComponents(coordSection, 0, &spaceDim);CHKERRQ(ierr);
6518   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
6519   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
6520   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, spaceDim);CHKERRQ(ierr);
6521 
6522   if (localize) {
6523     PetscInt p, r, newp, *pi;
6524 
6525     /* New coordinates will be already localized on the cell */
6526     ierr = PetscSectionSetChart(coordSectionNew, 0, vStartNew+numVertices);CHKERRQ(ierr);
6527 
6528     /* We need the parentId to properly localize coordinates */
6529     ierr = PetscMalloc1(cEndNew-cStartNew,&pi);CHKERRQ(ierr);
6530     switch (refiner) {
6531     case REFINER_NOOP:
6532       break;
6533     case REFINER_SIMPLEX_1D:
6534       for (p = cStart; p < cEnd; ++p) {
6535         for (r = 0; r < 2; ++r) {
6536           newp     = (p - cStart)*2 + r;
6537           pi[newp] = p;
6538         }
6539       }
6540       break;
6541     case REFINER_SIMPLEX_2D:
6542       for (p = cStart; p < cEnd; ++p) {
6543         for (r = 0; r < 4; ++r) {
6544           newp     = (p - cStart)*4 + r;
6545           pi[newp] = p;
6546         }
6547       }
6548       break;
6549     case REFINER_HEX_2D:
6550       for (p = cStart; p < cEnd; ++p) {
6551         for (r = 0; r < 4; ++r) {
6552           newp     = (p - cStart)*4 + r;
6553           pi[newp] = p;
6554         }
6555       }
6556       break;
6557     case REFINER_SIMPLEX_TO_HEX_2D:
6558       for (p = cStart; p < cEnd; ++p) {
6559         for (r = 0; r < 3; ++r) {
6560           newp     = (p - cStart)*3 + r;
6561           pi[newp] = p;
6562         }
6563       }
6564       break;
6565     case REFINER_HYBRID_SIMPLEX_2D:
6566       for (p = cStart; p < cMax; ++p) {
6567         for (r = 0; r < 4; ++r) {
6568           newp     = (p - cStart)*4 + r;
6569           pi[newp] = p;
6570         }
6571       }
6572       for (p = cMax; p < cEnd; ++p) {
6573         for (r = 0; r < 2; ++r) {
6574           newp     = (cMax - cStart)*4 + (p - cMax)*2 + r;
6575           pi[newp] = p;
6576         }
6577       }
6578       break;
6579     case REFINER_HYBRID_HEX_2D:
6580       for (p = cStart; p < cMax; ++p) {
6581         for (r = 0; r < 4; ++r) {
6582           newp     = (p - cStart)*4 + r;
6583           pi[newp] = p;
6584         }
6585       }
6586       for (p = cMax; p < cEnd; ++p) {
6587         for (r = 0; r < 2; ++r) {
6588           newp     = (cMax - cStart)*4 + (p - cMax)*2 + r;
6589           pi[newp] = p;
6590         }
6591       }
6592       break;
6593     case REFINER_SIMPLEX_3D:
6594       for (p = cStart; p < cEnd; ++p) {
6595         for (r = 0; r < 8; ++r) {
6596           newp     = (p - cStart)*8 + r;
6597           pi[newp] = p;
6598         }
6599       }
6600       break;
6601     case REFINER_HYBRID_SIMPLEX_3D:
6602       for (p = cStart; p < cMax; ++p) {
6603         for (r = 0; r < 8; ++r) {
6604           newp     = (p - cStart)*8 + r;
6605           pi[newp] = p;
6606         }
6607       }
6608       for (p = cMax; p < cEnd; ++p) {
6609         for (r = 0; r < 4; ++r) {
6610           newp     = (cMax - cStart)*8 + (p - cMax)*4 + r;
6611           pi[newp] = p;
6612         }
6613       }
6614       break;
6615     case REFINER_SIMPLEX_TO_HEX_3D:
6616       for (p = cStart; p < cEnd; ++p) {
6617         for (r = 0; r < 4; ++r) {
6618           newp     = (p - cStart)*4 + r;
6619           pi[newp] = p;
6620         }
6621       }
6622       break;
6623     case REFINER_HEX_3D:
6624       for (p = cStart; p < cEnd; ++p) {
6625         for (r = 0; r < 8; ++r) {
6626           newp = (p - cStart)*8 + r;
6627           pi[newp] = p;
6628         }
6629       }
6630       break;
6631     case REFINER_HYBRID_HEX_3D:
6632       for (p = cStart; p < cMax; ++p) {
6633         for (r = 0; r < 8; ++r) {
6634           newp = (p - cStart)*8 + r;
6635           pi[newp] = p;
6636         }
6637       }
6638       for (p = cMax; p < cEnd; ++p) {
6639         for (r = 0; r < 4; ++r) {
6640           newp = (cMax - cStart)*8 + (p - cMax)*4 + r;
6641           pi[newp] = p;
6642         }
6643       }
6644       break;
6645     default:
6646       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6647     }
6648     parentId = pi;
6649   } else {
6650     ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+numVertices);CHKERRQ(ierr);
6651   }
6652   if (cMax < 0) cMax = cEnd;
6653   if (fMax < 0) fMax = fEnd;
6654   if (eMax < 0) eMax = eEnd;
6655 
6656   /* All vertices have the spaceDim coordinates */
6657   if (localize) {
6658     PetscInt c;
6659 
6660     for (c = cStartNew; c < cEndNew; ++c) {
6661       PetscInt *cone = NULL;
6662       PetscInt  closureSize, coneSize = 0, p, pdof;
6663 
6664       ierr = PetscSectionGetDof(coordSection, parentId[c], &pdof); CHKERRQ(ierr);
6665       if (pdof) { /* localize on all cells that are refinement of a localized parent cell */
6666         ierr = DMPlexGetTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6667         for (p = 0; p < closureSize*2; p += 2) {
6668           const PetscInt point = cone[p];
6669           if ((point >= vStartNew) && (point < vEndNew)) coneSize++;
6670         }
6671         ierr = DMPlexRestoreTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6672         ierr = PetscSectionSetDof(coordSectionNew, c, coneSize*spaceDim);CHKERRQ(ierr);
6673         ierr = PetscSectionSetFieldDof(coordSectionNew, c, 0, coneSize*spaceDim);CHKERRQ(ierr);
6674       }
6675     }
6676   }
6677   for (v = vStartNew; v < vStartNew+numVertices; ++v) {
6678     ierr = PetscSectionSetDof(coordSectionNew, v, spaceDim);CHKERRQ(ierr);
6679     ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, spaceDim);CHKERRQ(ierr);
6680   }
6681   ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
6682   ierr = DMSetCoordinateSection(rdm, PETSC_DETERMINE, coordSectionNew);CHKERRQ(ierr);
6683   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6684   ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
6685   ierr = VecCreate(PETSC_COMM_SELF, &coordinatesNew);CHKERRQ(ierr);
6686   ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
6687   ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
6688   ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr);
6689   ierr = VecSetBlockSize(coordinatesNew, bs);CHKERRQ(ierr);
6690   ierr = VecGetType(coordinates, &vtype);CHKERRQ(ierr);
6691   ierr = VecSetType(coordinatesNew, vtype);CHKERRQ(ierr);
6692   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
6693   ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6694 
6695   switch (refiner) {
6696   case REFINER_NOOP: break;
6697   case REFINER_SIMPLEX_TO_HEX_3D:
6698   case REFINER_HEX_3D:
6699   case REFINER_HYBRID_HEX_3D:
6700     /* Face vertices have the average of corner coordinates */
6701     for (f = fStart; f < fMax; ++f) {
6702       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
6703       PetscInt      *cone = NULL;
6704       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
6705 
6706       ierr = DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6707       for (p = 0; p < closureSize*2; p += 2) {
6708         const PetscInt point = cone[p];
6709         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
6710       }
6711       if (localize) {
6712         const PetscInt *support = NULL;
6713         PetscInt       *rStar = NULL;
6714         PetscInt        supportSize, rStarSize, coff, s, ccoff[8];
6715         PetscBool       cellfound = PETSC_FALSE;
6716 
6717         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
6718         ierr = DMPlexGetSupportSize(dm,f,&supportSize);CHKERRQ(ierr);
6719         ierr = DMPlexGetSupport(dm,f,&support);CHKERRQ(ierr);
6720         /* Compute average of coordinates for each cell sharing the face */
6721         for (s = 0; s < supportSize; ++s) {
6722           PetscScalar     coordsNewAux[3] = { 0.0, 0.0, 0.0 };
6723           PetscInt       *cellCone = NULL;
6724           PetscInt        cellClosureSize, cellConeSize = 0, cdof;
6725           const PetscInt  cell = support[s];
6726           PetscBool       copyoff = PETSC_FALSE;
6727 
6728           ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
6729           for (p = 0; p < cellClosureSize*2; p += 2) {
6730             const PetscInt point = cellCone[p];
6731             if ((point >= vStart) && (point < vEnd)) cellCone[cellConeSize++] = point;
6732           }
6733           ierr = PetscSectionGetDof(coordSection, cell, &cdof);CHKERRQ(ierr);
6734           if (!cdof) { /* the parent cell does not have localized coordinates */
6735             cellfound = PETSC_TRUE;
6736             for (v = 0; v < coneSize; ++v) {
6737               ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
6738               for (d = 0; d < spaceDim; ++d) coordsNewAux[d] += coords[off[v]+d];
6739             }
6740             for (d = 0; d < spaceDim; ++d) coordsNewAux[d] /= coneSize;
6741           } else {
6742             ierr = PetscSectionGetOffset(coordSection, cell, &coff);CHKERRQ(ierr);
6743             for (p = 0; p < coneSize; ++p) {
6744               const PetscInt tv = cone[p];
6745               PetscInt       cv, voff;
6746               PetscBool      locv = PETSC_TRUE;
6747 
6748               for (cv = 0; cv < cellConeSize; ++cv) {
6749                 if (cellCone[cv] == tv) {
6750                   ccoff[p] = spaceDim*cv + coff;
6751                   break;
6752                 }
6753               }
6754               if (cv == cellConeSize) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map vertex %D\n",tv);
6755 
6756               ierr = PetscSectionGetOffset(coordSection, cone[p], &voff);CHKERRQ(ierr);
6757               for (d = 0; d < spaceDim; ++d) {
6758                 coordsNewAux[d] += coords[ccoff[p]+d];
6759                 if (!cellfound && coords[voff+d] != coords[ccoff[p]+d]) locv = PETSC_FALSE;
6760               }
6761               if (locv && !cellfound) {
6762                 cellfound = PETSC_TRUE;
6763                 copyoff   = PETSC_TRUE;
6764               }
6765             }
6766             for (d = 0; d < spaceDim; ++d) coordsNewAux[d] /= coneSize;
6767 
6768             /* Found a valid face for the "vertex" part of the Section (physical space)
6769                i.e., a face that has at least one corner in the physical space */
6770             if (copyoff) for (p = 0; p < coneSize; ++p) off[p] = ccoff[p];
6771           }
6772 
6773           /* Localize new coordinates on each refined cell */
6774           for (v = 0; v < rStarSize*2; v += 2) {
6775             if ((rStar[v] >= cStartNew) && (rStar[v] < cEndNew) && parentId[rStar[v]-cStartNew] == cell) {
6776               PetscInt       *rcone = NULL, rclosureSize, lid, rcdof, rcoff;
6777               const PetscInt  rcell = rStar[v];
6778 
6779               ierr = PetscSectionGetDof(coordSectionNew, rcell, &rcdof);CHKERRQ(ierr);
6780               if (!rcdof) continue;
6781               ierr = PetscSectionGetOffset(coordSectionNew, rcell, &rcoff);CHKERRQ(ierr);
6782               ierr = DMPlexGetTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
6783               for (p = 0, lid = 0; p < rclosureSize*2; p += 2) {
6784                 if (rcone[p] == newv) {
6785                   for (d = 0; d < spaceDim; d++) coordsNew[rcoff + lid*spaceDim + d] = coordsNewAux[d];
6786                   break;
6787                 }
6788                 if (rcone[p] >= vStartNew && rcone[p] < vEndNew) lid++;
6789               }
6790               ierr = DMPlexRestoreTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
6791               if (p == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
6792             }
6793           }
6794           ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
6795         }
6796         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
6797         if (!cellfound) {
6798           /* Could not find a valid face for the vertex part, we will get this vertex later (final reduction) */
6799           needcoords = PETSC_TRUE;
6800           coneSize   = 0;
6801         }
6802       } else {
6803         for (v = 0; v < coneSize; ++v) {
6804           ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
6805         }
6806       }
6807       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6808       if (coneSize) {
6809         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
6810         for (v = 0; v < coneSize; ++v) {ierr = DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);CHKERRQ(ierr);}
6811         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
6812       } else {
6813         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = PETSC_MIN_REAL;
6814       }
6815       ierr = DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6816     }
6817   case REFINER_SIMPLEX_TO_HEX_2D:
6818   case REFINER_HEX_2D:
6819   case REFINER_HYBRID_HEX_2D:
6820   case REFINER_SIMPLEX_1D:
6821     /* Cell vertices have the average of corner coordinates */
6822     for (c = cStart; c < cMax; ++c) {
6823       const PetscInt newv = vStartNew + (vEnd - vStart) + (dim > 1 ? (eMax - eStart) : 0) + (c - cStart) + (dim > 2 ? (fMax - fStart) : 0);
6824       PetscInt      *cone = NULL;
6825       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d, cdof = 0;
6826 
6827       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6828       for (p = 0; p < closureSize*2; p += 2) {
6829         const PetscInt point = cone[p];
6830         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
6831       }
6832       if (localize) {
6833         ierr = PetscSectionGetDof(coordSection, c, &cdof);CHKERRQ(ierr);
6834       }
6835       if (cdof) {
6836         PetscInt coff;
6837 
6838         ierr = PetscSectionGetOffset(coordSection, c, &coff);CHKERRQ(ierr);
6839         for (v = 0; v < coneSize; ++v) off[v] = spaceDim*v + coff;
6840       } else {
6841         for (v = 0; v < coneSize; ++v) {
6842           ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
6843         }
6844       }
6845       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6846       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
6847       for (v = 0; v < coneSize; ++v) {ierr = DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);CHKERRQ(ierr);}
6848       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
6849       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6850 
6851       /* Localize new coordinates on each refined cell */
6852       if (cdof) {
6853         PetscInt *rStar = NULL, rStarSize;
6854 
6855         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
6856         for (v = 0; v < rStarSize*2; v += 2) {
6857           if ((rStar[v] >= cStartNew) && (rStar[v] < cEndNew)) {
6858             PetscInt *cone = NULL, closureSize, lid, coff, rc, rcdof;
6859 
6860             rc   = rStar[v];
6861             ierr = PetscSectionGetDof(coordSectionNew, rc, &rcdof);CHKERRQ(ierr);
6862             if (!rcdof) continue;
6863             ierr = PetscSectionGetOffset(coordSectionNew, rc, &coff);CHKERRQ(ierr);
6864             ierr = DMPlexGetTransitiveClosure(rdm, rc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6865             for (p = 0, lid = 0; p < closureSize*2; p += 2) {
6866               if (cone[p] == newv) {
6867                 for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = coordsNew[offnew + d];
6868                 break;
6869               }
6870               if (cone[p] >= vStartNew && cone[p] < vEndNew) lid++;
6871             }
6872             if (p == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
6873             ierr = DMPlexRestoreTransitiveClosure(rdm, rc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6874           }
6875         }
6876         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
6877       }
6878     }
6879   case REFINER_SIMPLEX_2D:
6880   case REFINER_HYBRID_SIMPLEX_2D:
6881   case REFINER_SIMPLEX_3D:
6882   case REFINER_HYBRID_SIMPLEX_3D:
6883     /* Edge vertices have the average of endpoint coordinates */
6884     for (e = eStart; e < eMax; ++e) {
6885       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
6886       const PetscInt *cone;
6887       PetscInt        coneSize, offA, offB, offnew, d;
6888 
6889       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
6890       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
6891       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6892       if (localize) {
6893         PetscInt   coff, toffA = -1, toffB = -1, voffA, voffB;
6894         PetscInt  *eStar = NULL, eStarSize;
6895         PetscInt  *rStar = NULL, rStarSize;
6896         PetscBool  cellfound = PETSC_FALSE;
6897 
6898         offA = offB = -1;
6899         ierr = PetscSectionGetOffset(coordSection, cone[0], &voffA);CHKERRQ(ierr);
6900         ierr = PetscSectionGetOffset(coordSection, cone[1], &voffB);CHKERRQ(ierr);
6901         ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &eStarSize, &eStar);CHKERRQ(ierr);
6902         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
6903         for (v = 0; v < eStarSize*2; v += 2) {
6904           if ((eStar[v] >= cStart) && (eStar[v] < cEnd)) {
6905             PetscScalar     coordsNewAux[3];
6906             PetscInt       *cellCone = NULL;
6907             PetscInt        cellClosureSize, s, cv, cdof;
6908             PetscBool       locvA = PETSC_TRUE, locvB = PETSC_TRUE;
6909             const PetscInt  cell = eStar[v];
6910 
6911             ierr = PetscSectionGetDof(coordSection, cell, &cdof);CHKERRQ(ierr);
6912             if (!cdof) {
6913               /* Found a valid edge for the "vertex" part of the Section */
6914               offA = voffA;
6915               offB = voffB;
6916               cellfound = PETSC_TRUE;
6917             } else {
6918               ierr = PetscSectionGetOffset(coordSection, cell, &coff);CHKERRQ(ierr);
6919               ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
6920               for (s = 0, cv = 0; s < cellClosureSize*2; s += 2) {
6921                 const PetscInt point = cellCone[s];
6922                 if ((point >= vStart) && (point < vEnd)) {
6923                   if (point == cone[0]) toffA = spaceDim*cv + coff;
6924                   else if (point == cone[1]) toffB = spaceDim*cv + coff;
6925                   cv++;
6926                 }
6927               }
6928               ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
6929               for (d = 0; d < spaceDim; ++d) {
6930                 coordsNewAux[d] = 0.5*(coords[toffA+d] + coords[toffB+d]);
6931                 if (coords[toffA+d] != coords[voffA+d]) locvA = PETSC_FALSE;
6932                 if (coords[toffB+d] != coords[voffB+d]) locvB = PETSC_FALSE;
6933               }
6934               /* Found a valid edge for the "vertex" part of the Section */
6935               if (!cellfound && (locvA || locvB)) {
6936                 cellfound = PETSC_TRUE;
6937                 offA = toffA;
6938                 offB = toffB;
6939               }
6940             }
6941 
6942             /* Localize new coordinates on each refined cell */
6943             for (s = 0; s < rStarSize*2; s += 2) {
6944               if ((rStar[s] >= cStartNew) && (rStar[s] < cEndNew) && parentId[rStar[s]-cStartNew] == cell) {
6945                 PetscInt       *rcone = NULL, rclosureSize, lid, p, rcdof;
6946                 const PetscInt  rcell = rStar[s];
6947 
6948                 ierr = PetscSectionGetDof(coordSectionNew, rcell, &rcdof);CHKERRQ(ierr);
6949                 if (!rcdof) continue;
6950                 ierr = PetscSectionGetOffset(coordSectionNew, rcell, &coff);CHKERRQ(ierr);
6951                 ierr = DMPlexGetTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
6952                 for (p = 0, lid = 0; p < rclosureSize*2; p += 2) {
6953                   if (rcone[p] == newv) {
6954                     for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = coordsNewAux[d];
6955                     break;
6956                   }
6957                   if (rcone[p] >= vStartNew && rcone[p] < vEndNew) lid++;
6958                 }
6959                 ierr = DMPlexRestoreTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
6960                 if (p == rclosureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
6961               }
6962             }
6963           }
6964         }
6965         ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &eStarSize, &eStar);CHKERRQ(ierr);
6966         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
6967         if (!cellfound) {
6968           /* Could not find a valid edge for the vertex part, we will get this vertex later (final reduction) */
6969           needcoords = PETSC_TRUE;
6970         }
6971       } else {
6972         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6973         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6974       }
6975       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6976       if (offA != -1 && offB != -1) {
6977         ierr = DMLocalizeCoordinate_Internal(dm, spaceDim, &coords[offA], &coords[offB], &coordsNew[offnew]);CHKERRQ(ierr);
6978         for (d = 0; d < spaceDim; ++d) {
6979           coordsNew[offnew+d] = 0.5*(coords[offA+d] + coordsNew[offnew+d]);
6980         }
6981       } else {
6982         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = PETSC_MIN_REAL;
6983       }
6984     }
6985     /* Old vertices have the same coordinates */
6986     for (v = vStart; v < vEnd; ++v) {
6987       const PetscInt newv = vStartNew + (v - vStart);
6988       PetscInt       off, offnew, d;
6989 
6990       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6991       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6992       for (d = 0; d < spaceDim; ++d) {
6993         coordsNew[offnew+d] = coords[off+d];
6994       }
6995 
6996       /* Localize new coordinates on each refined cell */
6997       if (localize) {
6998         PetscInt  p;
6999         PetscInt *rStar = NULL, rStarSize;
7000 
7001         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
7002         for (p = 0; p < rStarSize*2; p += 2) {
7003           if ((rStar[p] >= cStartNew) && (rStar[p] < cEndNew)) {
7004             PetscScalar  ocoords[3];
7005             PetscInt    *cone = NULL, closureSize, lid, coff, s, oc, cdof;
7006 
7007             c    = rStar[p];
7008             oc   = parentId[c-cStartNew];
7009             ierr = PetscSectionGetDof(coordSectionNew, c, &cdof);CHKERRQ(ierr);
7010             if (!cdof) continue;
7011             ierr = PetscSectionGetDof(coordSection, oc, &cdof);CHKERRQ(ierr);
7012             if (!cdof) continue;
7013             ierr = PetscSectionGetOffset(coordSection, oc, &coff);CHKERRQ(ierr);
7014             ierr = DMPlexGetTransitiveClosure(dm, oc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
7015             for (s = 0, lid = 0; s < closureSize*2; s += 2) {
7016               if (cone[s] == v) {
7017                 for (d = 0; d < spaceDim; d++) ocoords[d] = coords[coff + lid*spaceDim + d];
7018                 break;
7019               }
7020               if (cone[s] >= vStart && cone[s] < vEnd) lid++;
7021             }
7022             if (s == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map old vertex %D\n",v);
7023             ierr = DMPlexRestoreTransitiveClosure(dm, oc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
7024 
7025             ierr = PetscSectionGetOffset(coordSectionNew, c, &coff);CHKERRQ(ierr);
7026             ierr = DMPlexGetTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
7027             for (s = 0, lid = 0; s < closureSize*2; s += 2) {
7028               if (cone[s] == newv) {
7029                 for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = ocoords[d];
7030                 break;
7031               }
7032               if (cone[s] >= vStartNew && cone[s] < vEndNew) lid++;
7033             }
7034             if (s == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
7035             ierr = DMPlexRestoreTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
7036           }
7037         }
7038         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
7039       }
7040     }
7041     break;
7042   default:
7043     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7044   }
7045   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
7046   ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
7047   ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
7048 
7049   /* Final reduction (if needed) if we are localizing */
7050   if (localize) {
7051     PetscBool gred;
7052 
7053     ierr = MPIU_Allreduce(&needcoords, &gred, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)rdm));CHKERRQ(ierr);
7054     if (gred) {
7055       DM                 cdm;
7056       Vec                aux;
7057       PetscSF            sf;
7058       const PetscScalar *lArray;
7059       PetscScalar       *gArray;
7060 
7061       ierr = DMGetCoordinateDM(rdm, &cdm);CHKERRQ(ierr);
7062       ierr = DMCreateGlobalVector(cdm, &aux);CHKERRQ(ierr);
7063       ierr = DMGetDefaultSF(cdm, &sf);CHKERRQ(ierr);
7064       ierr = VecGetArrayRead(coordinatesNew, &lArray);CHKERRQ(ierr);
7065       ierr = VecSet(aux, PETSC_MIN_REAL);CHKERRQ(ierr);
7066       ierr = VecGetArray(aux, &gArray);CHKERRQ(ierr);
7067       ierr = PetscSFReduceBegin(sf, MPIU_SCALAR, lArray, gArray, MPIU_MAX);CHKERRQ(ierr);
7068       ierr = PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_MAX);CHKERRQ(ierr);
7069       ierr = VecRestoreArrayRead(coordinatesNew, &lArray);CHKERRQ(ierr);
7070       ierr = VecRestoreArray(aux, &gArray);CHKERRQ(ierr);
7071       ierr = DMGlobalToLocalBegin(cdm, aux, INSERT_VALUES, coordinatesNew);CHKERRQ(ierr);
7072       ierr = DMGlobalToLocalEnd(cdm, aux, INSERT_VALUES, coordinatesNew);CHKERRQ(ierr);
7073       ierr = VecDestroy(&aux);CHKERRQ(ierr);
7074     }
7075   }
7076   ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
7077   ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
7078   ierr = PetscFree(parentId);CHKERRQ(ierr);
7079   PetscFunctionReturn(0);
7080 }
7081 
7082 /*@
7083   DMPlexCreateProcessSF - Create an SF which just has process connectivity
7084 
7085   Collective on DM
7086 
7087   Input Parameters:
7088 + dm      - The DM
7089 - sfPoint - The PetscSF which encodes point connectivity
7090 
7091   Output Parameters:
7092 + processRanks - A list of process neighbors, or NULL
7093 - sfProcess    - An SF encoding the process connectivity, or NULL
7094 
7095   Level: developer
7096 
7097 .seealso: PetscSFCreate(), DMPlexCreateTwoSidedProcessSF()
7098 @*/
7099 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
7100 {
7101   PetscInt           numRoots, numLeaves, l;
7102   const PetscInt    *localPoints;
7103   const PetscSFNode *remotePoints;
7104   PetscInt          *localPointsNew;
7105   PetscSFNode       *remotePointsNew;
7106   PetscInt          *ranks, *ranksNew;
7107   PetscMPIInt        size;
7108   PetscErrorCode     ierr;
7109 
7110   PetscFunctionBegin;
7111   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7112   PetscValidHeaderSpecific(sfPoint, PETSCSF_CLASSID, 2);
7113   if (processRanks) {PetscValidPointer(processRanks, 3);}
7114   if (sfProcess)    {PetscValidPointer(sfProcess, 4);}
7115   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) dm), &size);CHKERRQ(ierr);
7116   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
7117   ierr = PetscMalloc1(numLeaves, &ranks);CHKERRQ(ierr);
7118   for (l = 0; l < numLeaves; ++l) {
7119     ranks[l] = remotePoints[l].rank;
7120   }
7121   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
7122   ierr = PetscMalloc1(numLeaves, &ranksNew);CHKERRQ(ierr);
7123   ierr = PetscMalloc1(numLeaves, &localPointsNew);CHKERRQ(ierr);
7124   ierr = PetscMalloc1(numLeaves, &remotePointsNew);CHKERRQ(ierr);
7125   for (l = 0; l < numLeaves; ++l) {
7126     ranksNew[l]              = ranks[l];
7127     localPointsNew[l]        = l;
7128     remotePointsNew[l].index = 0;
7129     remotePointsNew[l].rank  = ranksNew[l];
7130   }
7131   ierr = PetscFree(ranks);CHKERRQ(ierr);
7132   if (processRanks) {ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);}
7133   else              {ierr = PetscFree(ranksNew);CHKERRQ(ierr);}
7134   if (sfProcess) {
7135     ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
7136     ierr = PetscObjectSetName((PetscObject) *sfProcess, "Process SF");CHKERRQ(ierr);
7137     ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
7138     ierr = PetscSFSetGraph(*sfProcess, size, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7139   }
7140   PetscFunctionReturn(0);
7141 }
7142 
7143 static PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7144 {
7145   PetscSF            sf, sfNew, sfProcess;
7146   IS                 processRanks;
7147   MPI_Datatype       depthType;
7148   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
7149   const PetscInt    *localPoints, *neighbors;
7150   const PetscSFNode *remotePoints;
7151   PetscInt          *localPointsNew;
7152   PetscSFNode       *remotePointsNew;
7153   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
7154   PetscInt           ldepth, depth, numNeighbors, pStartNew, pEndNew, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r, n;
7155   PetscInt           cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
7156   PetscErrorCode     ierr;
7157 
7158   PetscFunctionBegin;
7159   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
7160   ierr = DMPlexGetDepth(dm, &ldepth);CHKERRQ(ierr);
7161   ierr = MPIU_Allreduce(&ldepth, &depth, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
7162   if ((ldepth >= 0) && (depth != ldepth)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent Plex depth %d != %d", ldepth, depth);
7163   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7164   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7165   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7166   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7167   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7168   cMax = cMax < 0 ? cEnd : cMax;
7169   fMax = fMax < 0 ? fEnd : fMax;
7170   eMax = eMax < 0 ? eEnd : eMax;
7171   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
7172   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
7173   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
7174   /* Calculate size of new SF */
7175   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
7176   if (numRoots < 0) PetscFunctionReturn(0);
7177   for (l = 0; l < numLeaves; ++l) {
7178     const PetscInt p = localPoints[l];
7179 
7180     switch (refiner) {
7181     case REFINER_SIMPLEX_1D:
7182       if ((p >= vStart) && (p < vEnd)) {
7183         /* Interior vertices stay the same */
7184         ++numLeavesNew;
7185       } else if ((p >= cStart && p < cMax)) {
7186         /* Interior cells add new cells and interior vertices */
7187         numLeavesNew += 2 + 1;
7188       }
7189       break;
7190     case REFINER_SIMPLEX_2D:
7191     case REFINER_HYBRID_SIMPLEX_2D:
7192       if ((p >= vStart) && (p < vEnd)) {
7193         /* Interior vertices stay the same */
7194         ++numLeavesNew;
7195       } else if ((p >= fStart) && (p < fMax)) {
7196         /* Interior faces add new faces and vertex */
7197         numLeavesNew += 2 + 1;
7198       } else if ((p >= fMax) && (p < fEnd)) {
7199         /* Hybrid faces stay the same */
7200         ++numLeavesNew;
7201       } else if ((p >= cStart) && (p < cMax)) {
7202         /* Interior cells add new cells and interior faces */
7203         numLeavesNew += 4 + 3;
7204       } else if ((p >= cMax) && (p < cEnd)) {
7205         /* Hybrid cells add new cells and hybrid face */
7206         numLeavesNew += 2 + 1;
7207       }
7208       break;
7209     case REFINER_SIMPLEX_TO_HEX_2D:
7210       if ((p >= vStart) && (p < vEnd)) {
7211         /* Interior vertices stay the same */
7212         ++numLeavesNew;
7213       } else if ((p >= fStart) && (p < fEnd)) {
7214         /* Interior faces add new faces and vertex */
7215         numLeavesNew += 2 + 1;
7216       } else if ((p >= cStart) && (p < cEnd)) {
7217         /* Interior cells add new cells, interior faces, and vertex */
7218         numLeavesNew += 3 + 3 + 1;
7219       }
7220       break;
7221     case REFINER_HEX_2D:
7222     case REFINER_HYBRID_HEX_2D:
7223       if ((p >= vStart) && (p < vEnd)) {
7224         /* Interior vertices stay the same */
7225         ++numLeavesNew;
7226       } else if ((p >= fStart) && (p < fMax)) {
7227         /* Interior faces add new faces and vertex */
7228         numLeavesNew += 2 + 1;
7229       } else if ((p >= fMax) && (p < fEnd)) {
7230         /* Hybrid faces stay the same */
7231         ++numLeavesNew;
7232       } else if ((p >= cStart) && (p < cMax)) {
7233         /* Interior cells add new cells, interior faces, and vertex */
7234         numLeavesNew += 4 + 4 + 1;
7235       } else if ((p >= cMax) && (p < cEnd)) {
7236         /* Hybrid cells add new cells and hybrid face */
7237         numLeavesNew += 2 + 1;
7238       }
7239       break;
7240     case REFINER_SIMPLEX_3D:
7241     case REFINER_HYBRID_SIMPLEX_3D:
7242       if ((p >= vStart) && (p < vEnd)) {
7243         /* Interior vertices stay the same */
7244         ++numLeavesNew;
7245       } else if ((p >= eStart) && (p < eMax)) {
7246         /* Interior edges add new edges and vertex */
7247         numLeavesNew += 2 + 1;
7248       } else if ((p >= eMax) && (p < eEnd)) {
7249         /* Hybrid edges stay the same */
7250         ++numLeavesNew;
7251       } else if ((p >= fStart) && (p < fMax)) {
7252         /* Interior faces add new faces and edges */
7253         numLeavesNew += 4 + 3;
7254       } else if ((p >= fMax) && (p < fEnd)) {
7255         /* Hybrid faces add new faces and edges */
7256         numLeavesNew += 2 + 1;
7257       } else if ((p >= cStart) && (p < cMax)) {
7258         /* Interior cells add new cells, faces, and edges */
7259         numLeavesNew += 8 + 8 + 1;
7260       } else if ((p >= cMax) && (p < cEnd)) {
7261         /* Hybrid cells add new cells and faces */
7262         numLeavesNew += 4 + 3;
7263       }
7264       break;
7265     case REFINER_SIMPLEX_TO_HEX_3D:
7266       if ((p >= vStart) && (p < vEnd)) {
7267         /* Interior vertices stay the same */
7268         ++numLeavesNew;
7269       } else if ((p >= eStart) && (p < eEnd)) {
7270         /* Interior edges add new edges and vertex */
7271         numLeavesNew += 2 + 1;
7272       } else if ((p >= fStart) && (p < fEnd)) {
7273         /* Interior faces add new faces, edges and a vertex */
7274         numLeavesNew += 3 + 3 + 1;
7275       } else if ((p >= cStart) && (p < cEnd)) {
7276         /* Interior cells add new cells, faces, edges and a vertex */
7277         numLeavesNew += 4 + 6 + 4 + 1;
7278       }
7279       break;
7280     case REFINER_HEX_3D:
7281     case REFINER_HYBRID_HEX_3D:
7282       if ((p >= vStart) && (p < vEnd)) {
7283         /* Old vertices stay the same */
7284         ++numLeavesNew;
7285       } else if ((p >= eStart) && (p < eMax)) {
7286         /* Interior edges add new edges, and vertex */
7287         numLeavesNew += 2 + 1;
7288       } else if ((p >= eMax) && (p < eEnd)) {
7289         /* Hybrid edges stay the same */
7290         ++numLeavesNew;
7291       } else if ((p >= fStart) && (p < fMax)) {
7292         /* Interior faces add new faces, edges, and vertex */
7293         numLeavesNew += 4 + 4 + 1;
7294       } else if ((p >= fMax) && (p < fEnd)) {
7295         /* Hybrid faces add new faces and edges */
7296         numLeavesNew += 2 + 1;
7297       } else if ((p >= cStart) && (p < cMax)) {
7298         /* Interior cells add new cells, faces, edges, and vertex */
7299         numLeavesNew += 8 + 12 + 6 + 1;
7300       } else if ((p >= cStart) && (p < cEnd)) {
7301         /* Hybrid cells add new cells, faces, and edges */
7302         numLeavesNew += 4 + 4 + 1;
7303       }
7304       break;
7305     default:
7306       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7307     }
7308   }
7309   /* Communicate depthSizes for each remote rank */
7310   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
7311   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
7312   ierr = PetscMalloc5((depth+1)*numNeighbors,&rdepthSize,numNeighbors,&rvStartNew,numNeighbors,&reStartNew,numNeighbors,&rfStartNew,numNeighbors,&rcStartNew);CHKERRQ(ierr);
7313   ierr = PetscMalloc7(depth+1,&depthSizeOld,(depth+1)*numNeighbors,&rdepthSizeOld,(depth+1)*numNeighbors,&rdepthMaxOld,numNeighbors,&rvStart,numNeighbors,&reStart,numNeighbors,&rfStart,numNeighbors,&rcStart);CHKERRQ(ierr);
7314   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
7315   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
7316   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7317   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7318   for (n = 0; n < numNeighbors; ++n) {
7319     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
7320   }
7321   depthSizeOld[depth]   = cMax;
7322   depthSizeOld[0]       = vMax;
7323   depthSizeOld[depth-1] = fMax;
7324   depthSizeOld[1]       = eMax;
7325 
7326   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7327   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7328 
7329   depthSizeOld[depth]   = cEnd - cStart;
7330   depthSizeOld[0]       = vEnd - vStart;
7331   depthSizeOld[depth-1] = fEnd - fStart;
7332   depthSizeOld[1]       = eEnd - eStart;
7333 
7334   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7335   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7336   for (n = 0; n < numNeighbors; ++n) {
7337     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
7338     rdepthMaxOld[n*(depth+1)+depth]   = rdepthMaxOld[n*(depth+1)+depth]   < 0 ? rdepthSizeOld[n*(depth+1)+depth]  +rcStart[n]: rdepthMaxOld[n*(depth+1)+depth];
7339     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];
7340     rdepthMaxOld[n*(depth+1)+1]       = rdepthMaxOld[n*(depth+1)+1]       < 0 ? rdepthSizeOld[n*(depth+1)+1]      +reStart[n]: rdepthMaxOld[n*(depth+1)+1];
7341   }
7342   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
7343   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
7344   /* Calculate new point SF */
7345   ierr = PetscMalloc1(numLeavesNew, &localPointsNew);CHKERRQ(ierr);
7346   ierr = PetscMalloc1(numLeavesNew, &remotePointsNew);CHKERRQ(ierr);
7347   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
7348   for (l = 0, m = 0; l < numLeaves; ++l) {
7349     PetscInt    p     = localPoints[l];
7350     PetscInt    rp    = remotePoints[l].index, n;
7351     PetscMPIInt rrank = remotePoints[l].rank;
7352 
7353     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
7354     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
7355     switch (refiner) {
7356     case REFINER_SIMPLEX_1D:
7357       if ((p >= vStart) && (p < vEnd)) {
7358         /* Old vertices stay the same */
7359         localPointsNew[m]        = vStartNew     + (p  - vStart);
7360         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7361         remotePointsNew[m].rank  = rrank;
7362         ++m;
7363       } else if ((p >= cStart) && (p < cMax)) {
7364         /* Old interior cells add new cells and vertex */
7365         for (r = 0; r < 2; ++r, ++m) {
7366           localPointsNew[m]        = cStartNew     + (p  - cStart)*2     + r;
7367           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*2 + r;
7368           remotePointsNew[m].rank  = rrank;
7369         }
7370         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - cStart);
7371         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rcStart[n]);
7372         remotePointsNew[m].rank  = rrank;
7373         ++m;
7374       }
7375       break;
7376     case REFINER_SIMPLEX_2D:
7377     case REFINER_HYBRID_SIMPLEX_2D:
7378       if ((p >= vStart) && (p < vEnd)) {
7379         /* Old vertices stay the same */
7380         localPointsNew[m]        = vStartNew     + (p  - vStart);
7381         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7382         remotePointsNew[m].rank  = rrank;
7383         ++m;
7384       } else if ((p >= fStart) && (p < fMax)) {
7385         /* Old interior faces add new faces and vertex */
7386         for (r = 0; r < 2; ++r, ++m) {
7387           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7388           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7389           remotePointsNew[m].rank  = rrank;
7390         }
7391         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7392         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7393         remotePointsNew[m].rank  = rrank;
7394         ++m;
7395       } else if ((p >= fMax) && (p < fEnd)) {
7396         /* Old hybrid faces stay the same */
7397         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
7398         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
7399         remotePointsNew[m].rank  = rrank;
7400         ++m;
7401       } else if ((p >= cStart) && (p < cMax)) {
7402         /* Old interior cells add new cells and interior faces */
7403         for (r = 0; r < 4; ++r, ++m) {
7404           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7405           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7406           remotePointsNew[m].rank  = rrank;
7407         }
7408         for (r = 0; r < 3; ++r, ++m) {
7409           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
7410           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
7411           remotePointsNew[m].rank  = rrank;
7412         }
7413       } else if ((p >= cMax) && (p < cEnd)) {
7414         /* Old hybrid cells add new cells and hybrid face */
7415         for (r = 0; r < 2; ++r, ++m) {
7416           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7417           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7418           remotePointsNew[m].rank  = rrank;
7419         }
7420         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
7421         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]);
7422         remotePointsNew[m].rank  = rrank;
7423         ++m;
7424       }
7425       break;
7426     case REFINER_SIMPLEX_TO_HEX_2D:
7427       if ((p >= vStart) && (p < vEnd)) {
7428         /* Old vertices stay the same */
7429         localPointsNew[m]        = vStartNew     + (p  - vStart);
7430         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7431         remotePointsNew[m].rank  = rrank;
7432         ++m;
7433       } else if ((p >= fStart) && (p < fEnd)) {
7434         /* Old interior faces add new faces and vertex */
7435         for (r = 0; r < 2; ++r, ++m) {
7436           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7437           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7438           remotePointsNew[m].rank  = rrank;
7439         }
7440         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7441         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7442         remotePointsNew[m].rank  = rrank;
7443         ++m;
7444       } else if ((p >= cStart) && (p < cEnd)) {
7445         /* Old interior cells add new cells, interior faces, and a vertex */
7446         for (r = 0; r < 3; ++r, ++m) {
7447           localPointsNew[m]        = cStartNew     + (p  - cStart)*3     + r;
7448           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*3 + r;
7449           remotePointsNew[m].rank  = rrank;
7450         }
7451         for (r = 0; r < 3; ++r, ++m) {
7452           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
7453           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
7454           remotePointsNew[m].rank  = rrank;
7455         }
7456         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (fEnd - fStart)                    + (p  - cStart);
7457         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
7458         remotePointsNew[m].rank  = rrank;
7459         ++m;
7460       }
7461       break;
7462     case REFINER_HEX_2D:
7463     case REFINER_HYBRID_HEX_2D:
7464       if ((p >= vStart) && (p < vEnd)) {
7465         /* Old vertices stay the same */
7466         localPointsNew[m]        = vStartNew     + (p  - vStart);
7467         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7468         remotePointsNew[m].rank  = rrank;
7469         ++m;
7470       } else if ((p >= fStart) && (p < fMax)) {
7471         /* Old interior faces add new faces and vertex */
7472         for (r = 0; r < 2; ++r, ++m) {
7473           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7474           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7475           remotePointsNew[m].rank  = rrank;
7476         }
7477         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7478         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7479         remotePointsNew[m].rank  = rrank;
7480         ++m;
7481       } else if ((p >= fMax) && (p < fEnd)) {
7482         /* Old hybrid faces stay the same */
7483         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
7484         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
7485         remotePointsNew[m].rank  = rrank;
7486         ++m;
7487       } else if ((p >= cStart) && (p < cMax)) {
7488         /* Old interior cells add new cells, interior faces, and vertex */
7489         for (r = 0; r < 4; ++r, ++m) {
7490           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7491           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7492           remotePointsNew[m].rank  = rrank;
7493         }
7494         for (r = 0; r < 4; ++r, ++m) {
7495           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*4     + r;
7496           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*4 + r;
7497           remotePointsNew[m].rank  = rrank;
7498         }
7499         localPointsNew[m]        = vStartNew     + (vEnd - vStart)               + (fMax                              - fStart)     + (p  - cStart);
7500         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0]  + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]);
7501         remotePointsNew[m].rank  = rrank;
7502         ++m;
7503       } else if ((p >= cStart) && (p < cMax)) {
7504         /* Old hybrid cells add new cells and hybrid face */
7505         for (r = 0; r < 2; ++r, ++m) {
7506           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7507           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7508           remotePointsNew[m].rank  = rrank;
7509         }
7510         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*4     + (p  - cMax);
7511         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]);
7512         remotePointsNew[m].rank  = rrank;
7513         ++m;
7514       }
7515       break;
7516     case REFINER_SIMPLEX_3D:
7517     case REFINER_HYBRID_SIMPLEX_3D:
7518       if ((p >= vStart) && (p < vEnd)) {
7519         /* Interior vertices stay the same */
7520         localPointsNew[m]        = vStartNew     + (p  - vStart);
7521         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7522         remotePointsNew[m].rank  = rrank;
7523         ++m;
7524       } else if ((p >= eStart) && (p < eMax)) {
7525         /* Interior edges add new edges and vertex */
7526         for (r = 0; r < 2; ++r, ++m) {
7527           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
7528           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
7529           remotePointsNew[m].rank  = rrank;
7530         }
7531         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
7532         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
7533         remotePointsNew[m].rank  = rrank;
7534         ++m;
7535       } else if ((p >= eMax) && (p < eEnd)) {
7536         /* Hybrid edges stay the same */
7537         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - eMax);
7538         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]);
7539         remotePointsNew[m].rank  = rrank;
7540         ++m;
7541       } else if ((p >= fStart) && (p < fMax)) {
7542         /* Interior faces add new faces and edges */
7543         for (r = 0; r < 4; ++r, ++m) {
7544           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
7545           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
7546           remotePointsNew[m].rank  = rrank;
7547         }
7548         for (r = 0; r < 3; ++r, ++m) {
7549           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*3     + r;
7550           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
7551           remotePointsNew[m].rank  = rrank;
7552         }
7553       } else if ((p >= fMax) && (p < fEnd)) {
7554         /* Hybrid faces add new faces and edges */
7555         for (r = 0; r < 2; ++r, ++m) {
7556           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fMax)*2                              + r;
7557           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;
7558           remotePointsNew[m].rank  = rrank;
7559         }
7560         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (eEnd                                    - eMax)                        + (p  - fMax);
7561         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]);
7562         remotePointsNew[m].rank  = rrank;
7563         ++m;
7564       } else if ((p >= cStart) && (p < cMax)) {
7565         /* Interior cells add new cells, faces, and edges */
7566         for (r = 0; r < 8; ++r, ++m) {
7567           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
7568           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
7569           remotePointsNew[m].rank  = rrank;
7570         }
7571         for (r = 0; r < 8; ++r, ++m) {
7572           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*8     + r;
7573           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*8 + r;
7574           remotePointsNew[m].rank  = rrank;
7575         }
7576         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (p  - cStart)*1     + 0;
7577         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;
7578         remotePointsNew[m].rank  = rrank;
7579         ++m;
7580       } else if ((p >= cMax) && (p < cEnd)) {
7581         /* Hybrid cells add new cells and faces */
7582         for (r = 0; r < 4; ++r, ++m) {
7583           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
7584           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
7585           remotePointsNew[m].rank  = rrank;
7586         }
7587         for (r = 0; r < 3; ++r, ++m) {
7588           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*2                              + (p  - cMax)*3                            + r;
7589           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;
7590           remotePointsNew[m].rank  = rrank;
7591         }
7592       }
7593       break;
7594     case REFINER_SIMPLEX_TO_HEX_3D:
7595       if ((p >= vStart) && (p < vEnd)) {
7596         /* Interior vertices stay the same */
7597         localPointsNew[m]        = vStartNew     + (p  - vStart);
7598         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7599         remotePointsNew[m].rank  = rrank;
7600         ++m;
7601       } else if ((p >= eStart) && (p < eEnd)) {
7602         /* Interior edges add new edges and vertex */
7603         for (r = 0; r < 2; ++r, ++m) {
7604           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
7605           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
7606           remotePointsNew[m].rank  = rrank;
7607         }
7608         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
7609         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
7610         remotePointsNew[m].rank  = rrank;
7611         ++m;
7612       } else if ((p >= fStart) && (p < fEnd)) {
7613         /* Interior faces add new faces, edges and a vertex */
7614         for (r = 0; r < 3; ++r, ++m) {
7615           localPointsNew[m]        = fStartNew     + (p  - fStart)*3     + r;
7616           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*3 + r;
7617           remotePointsNew[m].rank  = rrank;
7618         }
7619         for (r = 0; r < 3; ++r, ++m) {
7620           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2                + (p  - fStart)*3     + r;
7621           remotePointsNew[m].index = reStartNew[n] + (rdepthSizeOld[n*(depth+1)+1])*2 + (rp - rfStart[n])*3 + r;
7622           remotePointsNew[m].rank  = rrank;
7623         }
7624         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eEnd - eStart)              + (p - fStart);
7625         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+1] + (rp - rfStart[n]);
7626         remotePointsNew[m].rank  = rrank;
7627         ++m;
7628       } else if ((p >= cStart) && (p < cEnd)) {
7629         /* Interior cells add new cells, faces, edges, and a vertex */
7630         for (r = 0; r < 4; ++r, ++m) {
7631           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7632           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7633           remotePointsNew[m].rank  = rrank;
7634         }
7635         for (r = 0; r < 6; ++r, ++m) {
7636           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*3                    + (p  - cStart)*6     + r;
7637           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*3 + (rp - rcStart[n])*6 + r;
7638           remotePointsNew[m].rank  = rrank;
7639         }
7640         for (r = 0; r < 4; ++r, ++m) {
7641           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (fEnd - fStart)*3                    + (p  - cStart)*4 + r;
7642           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + rdepthSizeOld[n*(depth+1)+depth-1]*3 + (rp - rcStart[n])*4 + r;
7643           remotePointsNew[m].rank  = rrank;
7644         }
7645         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eEnd - eStart)              + (fEnd - fStart)                    + (p - cStart);
7646         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+1] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
7647         remotePointsNew[m].rank  = rrank;
7648         ++m;
7649       }
7650       break;
7651     case REFINER_HEX_3D:
7652     case REFINER_HYBRID_HEX_3D:
7653       if ((p >= vStart) && (p < vEnd)) {
7654         /* Interior vertices stay the same */
7655         localPointsNew[m]        = vStartNew     + (p  - vStart);
7656         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7657         remotePointsNew[m].rank  = rrank;
7658         ++m;
7659       } else if ((p >= eStart) && (p < eMax)) {
7660         /* Interior edges add new edges and vertex */
7661         for (r = 0; r < 2; ++r, ++m) {
7662           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
7663           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
7664           remotePointsNew[m].rank  = rrank;
7665         }
7666         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
7667         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
7668         remotePointsNew[m].rank  = rrank;
7669         ++m;
7670       } else if ((p >= eMax) && (p < eEnd)) {
7671         /* Hybrid edges stay the same */
7672         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (p  - eMax);
7673         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]);
7674         remotePointsNew[m].rank  = rrank;
7675         ++m;
7676       } else if ((p >= fStart) && (p < fMax)) {
7677         /* Interior faces add new faces, edges, and vertex */
7678         for (r = 0; r < 4; ++r, ++m) {
7679           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
7680           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
7681           remotePointsNew[m].rank  = rrank;
7682         }
7683         for (r = 0; r < 4; ++r, ++m) {
7684           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*4     + r;
7685           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*4 + r;
7686           remotePointsNew[m].rank  = rrank;
7687         }
7688         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax                        - eStart)     + (p  - fStart);
7689         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
7690         remotePointsNew[m].rank  = rrank;
7691         ++m;
7692       } else if ((p >= fMax) && (p < fEnd)) {
7693         /* Hybrid faces add new faces and edges */
7694         for (r = 0; r < 2; ++r, ++m) {
7695           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (p  - fMax)*2                              + r;
7696           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;
7697           remotePointsNew[m].rank  = rrank;
7698         }
7699         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (p  - fMax);
7700         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]);
7701         remotePointsNew[m].rank  = rrank;
7702         ++m;
7703       } else if ((p >= cStart) && (p < cMax)) {
7704         /* Interior cells add new cells, faces, edges, and vertex */
7705         for (r = 0; r < 8; ++r, ++m) {
7706           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
7707           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
7708           remotePointsNew[m].rank  = rrank;
7709         }
7710         for (r = 0; r < 12; ++r, ++m) {
7711           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*12     + r;
7712           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*12 + r;
7713           remotePointsNew[m].rank  = rrank;
7714         }
7715         for (r = 0; r < 6; ++r, ++m) {
7716           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (p  - cStart)*6     + r;
7717           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;
7718           remotePointsNew[m].rank  = rrank;
7719         }
7720         for (r = 0; r < 1; ++r, ++m) {
7721           localPointsNew[m]        = vStartNew     + (eMax                        - eStart)     + (fMax                              - fStart)     + (p  - cStart)     + r;
7722           remotePointsNew[m].index = rvStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]) + r;
7723           remotePointsNew[m].rank  = rrank;
7724         }
7725       } else if ((p >= cMax) && (p < cEnd)) {
7726         /* Hybrid cells add new cells, faces, and edges */
7727         for (r = 0; r < 4; ++r, ++m) {
7728           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
7729           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
7730           remotePointsNew[m].rank  = rrank;
7731         }
7732         for (r = 0; r < 4; ++r, ++m) {
7733           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (fEnd                                          - fMax)*2                              + (p  - cMax)*4                            + r;
7734           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;
7735           remotePointsNew[m].rank  = rrank;
7736         }
7737         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (fEnd                                          - fMax)                              + (p  - cMax);
7738         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]);
7739         remotePointsNew[m].rank  = rrank;
7740         ++m;
7741       }
7742       break;
7743     default:
7744       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7745     }
7746   }
7747   if (m != numLeavesNew) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of leaf point %d should be %d", m, numLeavesNew);
7748   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
7749   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
7750   {
7751     PetscSFNode *rp, *rtmp;
7752     PetscInt    *lp, *idx, *ltmp, i;
7753 
7754     /* SF needs sorted leaves to correct calculate Gather */
7755     ierr = PetscMalloc1(numLeavesNew,&idx);CHKERRQ(ierr);
7756     ierr = PetscMalloc1(numLeavesNew, &lp);CHKERRQ(ierr);
7757     ierr = PetscMalloc1(numLeavesNew, &rp);CHKERRQ(ierr);
7758     for (i = 0; i < numLeavesNew; ++i) {
7759       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);
7760       idx[i] = i;
7761     }
7762     ierr = PetscSortIntWithPermutation(numLeavesNew, localPointsNew, idx);CHKERRQ(ierr);
7763     for (i = 0; i < numLeavesNew; ++i) {
7764       lp[i] = localPointsNew[idx[i]];
7765       rp[i] = remotePointsNew[idx[i]];
7766     }
7767     ltmp            = localPointsNew;
7768     localPointsNew  = lp;
7769     rtmp            = remotePointsNew;
7770     remotePointsNew = rp;
7771     ierr = PetscFree(idx);CHKERRQ(ierr);
7772     ierr = PetscFree(ltmp);CHKERRQ(ierr);
7773     ierr = PetscFree(rtmp);CHKERRQ(ierr);
7774   }
7775   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7776   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
7777   ierr = PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
7778   PetscFunctionReturn(0);
7779 }
7780 
7781 static PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7782 {
7783   PetscInt       numLabels, l;
7784   PetscInt       depth, newp, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r;
7785   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
7786   PetscErrorCode ierr;
7787 
7788   PetscFunctionBegin;
7789   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7790   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7791   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7792   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7793   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7794   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
7795   ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
7796   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7797   switch (refiner) {
7798   case REFINER_NOOP:
7799   case REFINER_SIMPLEX_1D:
7800   case REFINER_SIMPLEX_2D:
7801   case REFINER_SIMPLEX_TO_HEX_2D:
7802   case REFINER_HEX_2D:
7803   case REFINER_SIMPLEX_3D:
7804   case REFINER_HEX_3D:
7805   case REFINER_SIMPLEX_TO_HEX_3D:
7806     break;
7807   case REFINER_HYBRID_SIMPLEX_3D:
7808   case REFINER_HYBRID_HEX_3D:
7809     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
7810   case REFINER_HYBRID_SIMPLEX_2D:
7811   case REFINER_HYBRID_HEX_2D:
7812     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7813     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7814     break;
7815   default:
7816     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7817   }
7818   for (l = 0; l < numLabels; ++l) {
7819     DMLabel         label, labelNew;
7820     const char     *lname;
7821     PetscBool       isDepth;
7822     IS              valueIS;
7823     const PetscInt *values;
7824     PetscInt        defVal;
7825     PetscInt        numValues, val;
7826 
7827     ierr = DMGetLabelName(dm, l, &lname);CHKERRQ(ierr);
7828     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
7829     if (isDepth) continue;
7830     ierr = DMCreateLabel(rdm, lname);CHKERRQ(ierr);
7831     ierr = DMGetLabel(dm, lname, &label);CHKERRQ(ierr);
7832     ierr = DMGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
7833     ierr = DMLabelGetDefaultValue(label,&defVal);CHKERRQ(ierr);
7834     ierr = DMLabelSetDefaultValue(labelNew,defVal);CHKERRQ(ierr);
7835     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
7836     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
7837     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
7838     for (val = 0; val < numValues; ++val) {
7839       IS              pointIS;
7840       const PetscInt *points;
7841       PetscInt        numPoints, n;
7842 
7843       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
7844       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
7845       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
7846       /* Ensure refined label is created with same number of strata as
7847        * original (even if no entries here). */
7848       ierr = DMLabelAddStratum(labelNew, values[val]);CHKERRQ(ierr);
7849       for (n = 0; n < numPoints; ++n) {
7850         const PetscInt p = points[n];
7851         switch (refiner) {
7852         case REFINER_SIMPLEX_1D:
7853           if ((p >= vStart) && (p < vEnd)) {
7854             /* Old vertices stay the same */
7855             newp = vStartNew + (p - vStart);
7856             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7857           } else if ((p >= cStart) && (p < cEnd)) {
7858             /* Old cells add new cells and vertex */
7859             newp = vStartNew + (vEnd - vStart) + (p - cStart);
7860             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7861             for (r = 0; r < 2; ++r) {
7862               newp = cStartNew + (p - cStart)*2 + r;
7863               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7864             }
7865           }
7866           break;
7867         case REFINER_SIMPLEX_2D:
7868           if ((p >= vStart) && (p < vEnd)) {
7869             /* Old vertices stay the same */
7870             newp = vStartNew + (p - vStart);
7871             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7872           } else if ((p >= fStart) && (p < fEnd)) {
7873             /* Old faces add new faces and vertex */
7874             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7875             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7876             for (r = 0; r < 2; ++r) {
7877               newp = fStartNew + (p - fStart)*2 + r;
7878               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7879             }
7880           } else if ((p >= cStart) && (p < cEnd)) {
7881             /* Old cells add new cells and interior faces */
7882             for (r = 0; r < 4; ++r) {
7883               newp = cStartNew + (p - cStart)*4 + r;
7884               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7885             }
7886             for (r = 0; r < 3; ++r) {
7887               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7888               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7889             }
7890           }
7891           break;
7892         case REFINER_SIMPLEX_TO_HEX_2D:
7893           if ((p >= vStart) && (p < vEnd)) {
7894             /* Old vertices stay the same */
7895             newp = vStartNew + (p - vStart);
7896             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7897           } else if ((p >= fStart) && (p < fEnd)) {
7898             /* Old faces add new faces and vertex */
7899             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7900             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7901             for (r = 0; r < 2; ++r) {
7902               newp = fStartNew + (p - fStart)*2 + r;
7903               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7904             }
7905           } else if ((p >= cStart) && (p < cEnd)) {
7906             /* Old cells add new cells, interior faces, and a vertex */
7907             for (r = 0; r < 3; ++r) {
7908               newp = cStartNew + (p - cStart)*3 + r;
7909               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7910             }
7911             for (r = 0; r < 3; ++r) {
7912               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7913               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7914             }
7915             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + p;
7916             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7917           }
7918           break;
7919         case REFINER_HEX_2D:
7920           if ((p >= vStart) && (p < vEnd)) {
7921             /* Old vertices stay the same */
7922             newp = vStartNew + (p - vStart);
7923             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7924           } else if ((p >= fStart) && (p < fEnd)) {
7925             /* Old faces add new faces and vertex */
7926             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7927             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7928             for (r = 0; r < 2; ++r) {
7929               newp = fStartNew + (p - fStart)*2 + r;
7930               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7931             }
7932           } else if ((p >= cStart) && (p < cEnd)) {
7933             /* Old cells add new cells and interior faces and vertex */
7934             for (r = 0; r < 4; ++r) {
7935               newp = cStartNew + (p - cStart)*4 + r;
7936               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7937             }
7938             for (r = 0; r < 4; ++r) {
7939               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
7940               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7941             }
7942             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
7943             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7944           }
7945           break;
7946         case REFINER_HYBRID_SIMPLEX_2D:
7947           if ((p >= vStart) && (p < vEnd)) {
7948             /* Old vertices stay the same */
7949             newp = vStartNew + (p - vStart);
7950             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7951           } else if ((p >= fStart) && (p < fMax)) {
7952             /* Old interior faces add new faces and vertex */
7953             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7954             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7955             for (r = 0; r < 2; ++r) {
7956               newp = fStartNew + (p - fStart)*2 + r;
7957               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7958             }
7959           } else if ((p >= fMax) && (p < fEnd)) {
7960             /* Old hybrid faces stay the same */
7961             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7962             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7963           } else if ((p >= cStart) && (p < cMax)) {
7964             /* Old interior cells add new cells and interior faces */
7965             for (r = 0; r < 4; ++r) {
7966               newp = cStartNew + (p - cStart)*4 + r;
7967               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7968             }
7969             for (r = 0; r < 3; ++r) {
7970               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7971               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7972             }
7973           } else if ((p >= cMax) && (p < cEnd)) {
7974             /* Old hybrid cells add new cells and hybrid face */
7975             for (r = 0; r < 2; ++r) {
7976               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
7977               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7978             }
7979             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
7980             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7981           }
7982           break;
7983         case REFINER_HYBRID_HEX_2D:
7984           if ((p >= vStart) && (p < vEnd)) {
7985             /* Old vertices stay the same */
7986             newp = vStartNew + (p - vStart);
7987             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7988           } else if ((p >= fStart) && (p < fMax)) {
7989             /* Old interior faces add new faces and vertex */
7990             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7991             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7992             for (r = 0; r < 2; ++r) {
7993               newp = fStartNew + (p - fStart)*2 + r;
7994               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7995             }
7996           } else if ((p >= fMax) && (p < fEnd)) {
7997             /* Old hybrid faces stay the same */
7998             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7999             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8000           } else if ((p >= cStart) && (p < cMax)) {
8001             /* Old interior cells add new cells, interior faces, and vertex */
8002             for (r = 0; r < 4; ++r) {
8003               newp = cStartNew + (p - cStart)*4 + r;
8004               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8005             }
8006             for (r = 0; r < 4; ++r) {
8007               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
8008               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8009             }
8010             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
8011             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8012           } else if ((p >= cMax) && (p < cEnd)) {
8013             /* Old hybrid cells add new cells and hybrid face */
8014             for (r = 0; r < 2; ++r) {
8015               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
8016               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8017             }
8018             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (p - cMax);
8019             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8020           }
8021           break;
8022         case REFINER_SIMPLEX_3D:
8023           if ((p >= vStart) && (p < vEnd)) {
8024             /* Old vertices stay the same */
8025             newp = vStartNew + (p - vStart);
8026             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8027           } else if ((p >= eStart) && (p < eEnd)) {
8028             /* Old edges add new edges and vertex */
8029             for (r = 0; r < 2; ++r) {
8030               newp = eStartNew + (p - eStart)*2 + r;
8031               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8032             }
8033             newp = vStartNew + (vEnd - vStart) + (p - eStart);
8034             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8035           } else if ((p >= fStart) && (p < fEnd)) {
8036             /* Old faces add new faces and edges */
8037             for (r = 0; r < 4; ++r) {
8038               newp = fStartNew + (p - fStart)*4 + r;
8039               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8040             }
8041             for (r = 0; r < 3; ++r) {
8042               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
8043               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8044             }
8045           } else if ((p >= cStart) && (p < cEnd)) {
8046             /* Old cells add new cells and interior faces and edges */
8047             for (r = 0; r < 8; ++r) {
8048               newp = cStartNew + (p - cStart)*8 + r;
8049               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8050             }
8051             for (r = 0; r < 8; ++r) {
8052               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*8 + r;
8053               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8054             }
8055             for (r = 0; r < 1; ++r) {
8056               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*1 + r;
8057               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8058             }
8059           }
8060           break;
8061         case REFINER_SIMPLEX_TO_HEX_3D:
8062           if ((p >= vStart) && (p < vEnd)) {
8063             /* Old vertices stay the same */
8064             newp = vStartNew + (p - vStart);
8065             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8066           } else if ((p >= eStart) && (p < eEnd)) {
8067             /* Old edges add new edges and vertex */
8068             for (r = 0; r < 2; ++r) {
8069               newp = eStartNew + (p - eStart)*2 + r;
8070               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8071             }
8072             newp = vStartNew + (vEnd - vStart) + (p - eStart);
8073             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8074           } else if ((p >= fStart) && (p < fEnd)) {
8075             /* Old faces add new faces, edges and a vertex */
8076             for (r = 0; r < 3; ++r) {
8077               newp = fStartNew + (p - fStart)*3 + r;
8078               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8079             }
8080             for (r = 0; r < 3; ++r) {
8081               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
8082               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8083             }
8084           } else if ((p >= cStart) && (p < cEnd)) {
8085             /* Old cells add new cells and interior faces and edges and a vertex */
8086             for (r = 0; r < 4; ++r) {
8087               newp = cStartNew + (p - cStart)*4 + r;
8088               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8089             }
8090             for (r = 0; r < 6; ++r) {
8091               newp = fStartNew + (fEnd - fStart)*3 + (p - cStart)*6 + r;
8092               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8093             }
8094             for (r = 0; r < 4; ++r) {
8095               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*4 + r;
8096               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8097             }
8098             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + p - cStart;
8099             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8100           }
8101           break;
8102         case REFINER_HYBRID_SIMPLEX_3D:
8103           if ((p >= vStart) && (p < vEnd)) {
8104             /* Interior vertices stay the same */
8105             newp = vStartNew + (p - vStart);
8106             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8107           } else if ((p >= eStart) && (p < eMax)) {
8108             /* Interior edges add new edges and vertex */
8109             for (r = 0; r < 2; ++r) {
8110               newp = eStartNew + (p - eStart)*2 + r;
8111               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8112             }
8113             newp = vStartNew + (vEnd - vStart) + (p - eStart);
8114             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8115           } else if ((p >= eMax) && (p < eEnd)) {
8116             /* Hybrid edges stay the same */
8117             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - eMax);
8118             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8119           } else if ((p >= fStart) && (p < fMax)) {
8120             /* Interior faces add new faces and edges */
8121             for (r = 0; r < 4; ++r) {
8122               newp = fStartNew + (p - fStart)*4 + r;
8123               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8124             }
8125             for (r = 0; r < 3; ++r) {
8126               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
8127               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8128             }
8129           } else if ((p >= fMax) && (p < fEnd)) {
8130             /* Hybrid faces add new faces and edges */
8131             for (r = 0; r < 2; ++r) {
8132               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (p - fMax)*2 + r;
8133               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8134             }
8135             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - fMax);
8136             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8137           } else if ((p >= cStart) && (p < cMax)) {
8138             /* Interior cells add new cells, faces, and edges */
8139             for (r = 0; r < 8; ++r) {
8140               newp = cStartNew + (p - cStart)*8 + r;
8141               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8142             }
8143             for (r = 0; r < 8; ++r) {
8144               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*8 + r;
8145               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8146             }
8147             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart);
8148             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8149           } else if ((p >= cMax) && (p < cEnd)) {
8150             /* Hybrid cells add new cells and faces */
8151             for (r = 0; r < 4; ++r) {
8152               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
8153               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8154             }
8155             for (r = 0; r < 3; ++r) {
8156               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
8157               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8158             }
8159           }
8160           break;
8161         case REFINER_HEX_3D:
8162           if ((p >= vStart) && (p < vEnd)) {
8163             /* Old vertices stay the same */
8164             newp = vStartNew + (p - vStart);
8165             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8166           } else if ((p >= eStart) && (p < eEnd)) {
8167             /* Old edges add new edges and vertex */
8168             for (r = 0; r < 2; ++r) {
8169               newp = eStartNew + (p - eStart)*2 + r;
8170               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8171             }
8172             newp = vStartNew + (vEnd - vStart) + (p - eStart);
8173             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8174           } else if ((p >= fStart) && (p < fEnd)) {
8175             /* Old faces add new faces, edges, and vertex */
8176             for (r = 0; r < 4; ++r) {
8177               newp = fStartNew + (p - fStart)*4 + r;
8178               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8179             }
8180             for (r = 0; r < 4; ++r) {
8181               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*4 + r;
8182               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8183             }
8184             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (p - fStart);
8185             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8186           } else if ((p >= cStart) && (p < cEnd)) {
8187             /* Old cells add new cells, faces, edges, and vertex */
8188             for (r = 0; r < 8; ++r) {
8189               newp = cStartNew + (p - cStart)*8 + r;
8190               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8191             }
8192             for (r = 0; r < 12; ++r) {
8193               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*12 + r;
8194               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8195             }
8196             for (r = 0; r < 6; ++r) {
8197               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (p - cStart)*6 + r;
8198               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8199             }
8200             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (p - cStart);
8201             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8202           }
8203           break;
8204         case REFINER_HYBRID_HEX_3D:
8205           if ((p >= vStart) && (p < vEnd)) {
8206             /* Interior vertices stay the same */
8207             newp = vStartNew + (p - vStart);
8208             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8209           } else if ((p >= eStart) && (p < eMax)) {
8210             /* Interior edges add new edges and vertex */
8211             for (r = 0; r < 2; ++r) {
8212               newp = eStartNew + (p - eStart)*2 + r;
8213               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8214             }
8215             newp = vStartNew + (vEnd - vStart) + (p - eStart);
8216             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8217           } else if ((p >= eMax) && (p < eEnd)) {
8218             /* Hybrid edges stay the same */
8219             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - eMax);
8220             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8221           } else if ((p >= fStart) && (p < fMax)) {
8222             /* Interior faces add new faces, edges, and vertex */
8223             for (r = 0; r < 4; ++r) {
8224               newp = fStartNew + (p - fStart)*4 + r;
8225               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8226             }
8227             for (r = 0; r < 4; ++r) {
8228               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*4 + r;
8229               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8230             }
8231             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (p - fStart);
8232             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8233           } else if ((p >= fMax) && (p < fEnd)) {
8234             /* Hybrid faces add new faces and edges */
8235             for (r = 0; r < 2; ++r) {
8236               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (p - fMax)*2 + r;
8237               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8238             }
8239             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - fMax);
8240             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8241           } else if ((p >= cStart) && (p < cMax)) {
8242             /* Interior cells add new cells, faces, edges, and vertex */
8243             for (r = 0; r < 8; ++r) {
8244               newp = cStartNew + (p - cStart)*8 + r;
8245               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8246             }
8247             for (r = 0; r < 12; ++r) {
8248               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*12 + r;
8249               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8250             }
8251             for (r = 0; r < 6; ++r) {
8252               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (p - cStart)*6 + r;
8253               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8254             }
8255             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (p - cStart);
8256             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8257           } else if ((p >= cMax) && (p < cEnd)) {
8258             /* Hybrid cells add new cells, faces, and edges */
8259             for (r = 0; r < 4; ++r) {
8260               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
8261               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8262             }
8263             for (r = 0; r < 4; ++r) {
8264               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (p - cMax)*4 + r;
8265               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8266             }
8267             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (fEnd - fMax) + (p - cMax);
8268             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8269           }
8270           break;
8271         default:
8272           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
8273         }
8274       }
8275       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
8276       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
8277     }
8278     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
8279     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
8280     if (0) {
8281       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
8282     }
8283   }
8284   PetscFunctionReturn(0);
8285 }
8286 
8287 /* This will only work for interpolated meshes */
8288 PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
8289 {
8290   DM             rdm;
8291   PetscInt      *depthSize;
8292   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
8293   PetscErrorCode ierr;
8294 
8295   PetscFunctionBegin;
8296   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
8297   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
8298   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
8299   ierr = DMSetDimension(rdm, dim);CHKERRQ(ierr);
8300   /* Calculate number of new points of each depth */
8301   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
8302   if (depth >= 0 && dim != depth) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Mesh must be interpolated for regular refinement");
8303   ierr = PetscMalloc1(depth+1, &depthSize);CHKERRQ(ierr);
8304   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
8305   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
8306   /* Step 1: Set chart */
8307   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
8308   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
8309   /* Step 2: Set cone/support sizes */
8310   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
8311   /* Step 3: Setup refined DM */
8312   ierr = DMSetUp(rdm);CHKERRQ(ierr);
8313   /* Step 4: Set cones and supports */
8314   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
8315   /* Step 5: Stratify */
8316   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
8317   /* Step 6: Create pointSF */
8318   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
8319   /* Step 7: Create labels */
8320   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
8321   /* Step 8: Set coordinates */
8322   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
8323   ierr = PetscFree(depthSize);CHKERRQ(ierr);
8324 
8325   *dmRefined = rdm;
8326   PetscFunctionReturn(0);
8327 }
8328 
8329 /*@
8330   DMPlexCreateCoarsePointIS - Creates an IS covering the coarse DM chart with the fine points as data
8331 
8332   Input Parameter:
8333 . dm - The coarse DM
8334 
8335   Output Parameter:
8336 . fpointIS - The IS of all the fine points which exist in the original coarse mesh
8337 
8338   Level: developer
8339 
8340 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexCreateSubpointIS()
8341 @*/
8342 PetscErrorCode DMPlexCreateCoarsePointIS(DM dm, IS *fpointIS)
8343 {
8344   CellRefiner    cellRefiner;
8345   PetscInt      *depthSize, *fpoints;
8346   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
8347   PetscInt       depth, pStart, pEnd, p, vStart, vEnd, v;
8348   PetscErrorCode ierr;
8349 
8350   PetscFunctionBegin;
8351   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
8352   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
8353   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8354   ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr);
8355   ierr = PetscMalloc1(depth+1, &depthSize);CHKERRQ(ierr);
8356   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
8357   if (cellRefiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
8358   ierr = PetscMalloc1(pEnd-pStart,&fpoints);CHKERRQ(ierr);
8359   for (p = 0; p < pEnd-pStart; ++p) fpoints[p] = -1;
8360   switch (cellRefiner) {
8361   case REFINER_SIMPLEX_1D:
8362   case REFINER_SIMPLEX_2D:
8363   case REFINER_HYBRID_SIMPLEX_2D:
8364   case REFINER_HEX_2D:
8365   case REFINER_HYBRID_HEX_2D:
8366   case REFINER_SIMPLEX_3D:
8367   case REFINER_HYBRID_SIMPLEX_3D:
8368   case REFINER_HEX_3D:
8369   case REFINER_HYBRID_HEX_3D:
8370     for (v = vStart; v < vEnd; ++v) fpoints[v-pStart] = vStartNew + (v - vStart);
8371     break;
8372   default:
8373     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", cellRefiner);
8374   }
8375   ierr = ISCreateGeneral(PETSC_COMM_SELF, pEnd-pStart, fpoints, PETSC_OWN_POINTER, fpointIS);CHKERRQ(ierr);
8376   ierr = PetscFree(depthSize);CHKERRQ(ierr);
8377   PetscFunctionReturn(0);
8378 }
8379 
8380 /*@
8381   DMPlexSetRefinementUniform - Set the flag for uniform refinement
8382 
8383   Input Parameters:
8384 + dm - The DM
8385 - refinementUniform - The flag for uniform refinement
8386 
8387   Level: developer
8388 
8389 .seealso: DMRefine(), DMPlexGetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
8390 @*/
8391 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
8392 {
8393   DM_Plex *mesh = (DM_Plex*) dm->data;
8394 
8395   PetscFunctionBegin;
8396   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8397   mesh->refinementUniform = refinementUniform;
8398   PetscFunctionReturn(0);
8399 }
8400 
8401 /*@
8402   DMPlexGetRefinementUniform - Retrieve the flag for uniform refinement
8403 
8404   Input Parameter:
8405 . dm - The DM
8406 
8407   Output Parameter:
8408 . refinementUniform - The flag for uniform refinement
8409 
8410   Level: developer
8411 
8412 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
8413 @*/
8414 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
8415 {
8416   DM_Plex *mesh = (DM_Plex*) dm->data;
8417 
8418   PetscFunctionBegin;
8419   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8420   PetscValidPointer(refinementUniform,  2);
8421   *refinementUniform = mesh->refinementUniform;
8422   PetscFunctionReturn(0);
8423 }
8424 
8425 /*@
8426   DMPlexSetRefinementLimit - Set the maximum cell volume for refinement
8427 
8428   Input Parameters:
8429 + dm - The DM
8430 - refinementLimit - The maximum cell volume in the refined mesh
8431 
8432   Level: developer
8433 
8434 .seealso: DMRefine(), DMPlexGetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
8435 @*/
8436 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
8437 {
8438   DM_Plex *mesh = (DM_Plex*) dm->data;
8439 
8440   PetscFunctionBegin;
8441   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8442   mesh->refinementLimit = refinementLimit;
8443   PetscFunctionReturn(0);
8444 }
8445 
8446 /*@
8447   DMPlexGetRefinementLimit - Retrieve the maximum cell volume for refinement
8448 
8449   Input Parameter:
8450 . dm - The DM
8451 
8452   Output Parameter:
8453 . refinementLimit - The maximum cell volume in the refined mesh
8454 
8455   Level: developer
8456 
8457 .seealso: DMRefine(), DMPlexSetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
8458 @*/
8459 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
8460 {
8461   DM_Plex *mesh = (DM_Plex*) dm->data;
8462 
8463   PetscFunctionBegin;
8464   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8465   PetscValidPointer(refinementLimit,  2);
8466   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
8467   *refinementLimit = mesh->refinementLimit;
8468   PetscFunctionReturn(0);
8469 }
8470 
8471 /*@
8472   DMPlexSetRefinementFunction - Set the function giving the maximum cell volume for refinement
8473 
8474   Input Parameters:
8475 + dm - The DM
8476 - refinementFunc - Function giving the maximum cell volume in the refined mesh
8477 
8478   Note: The calling sequence is refinementFunc(coords, limit)
8479 $ coords - Coordinates of the current point, usually a cell centroid
8480 $ limit  - The maximum cell volume for a cell containing this point
8481 
8482   Level: developer
8483 
8484 .seealso: DMRefine(), DMPlexGetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
8485 @*/
8486 PetscErrorCode DMPlexSetRefinementFunction(DM dm, PetscErrorCode (*refinementFunc)(const PetscReal [], PetscReal *))
8487 {
8488   DM_Plex *mesh = (DM_Plex*) dm->data;
8489 
8490   PetscFunctionBegin;
8491   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8492   mesh->refinementFunc = refinementFunc;
8493   PetscFunctionReturn(0);
8494 }
8495 
8496 /*@
8497   DMPlexGetRefinementFunction - Get the function giving the maximum cell volume for refinement
8498 
8499   Input Parameter:
8500 . dm - The DM
8501 
8502   Output Parameter:
8503 . refinementFunc - Function giving the maximum cell volume in the refined mesh
8504 
8505   Note: The calling sequence is refinementFunc(coords, limit)
8506 $ coords - Coordinates of the current point, usually a cell centroid
8507 $ limit  - The maximum cell volume for a cell containing this point
8508 
8509   Level: developer
8510 
8511 .seealso: DMRefine(), DMPlexSetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
8512 @*/
8513 PetscErrorCode DMPlexGetRefinementFunction(DM dm, PetscErrorCode (**refinementFunc)(const PetscReal [], PetscReal *))
8514 {
8515   DM_Plex *mesh = (DM_Plex*) dm->data;
8516 
8517   PetscFunctionBegin;
8518   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8519   PetscValidPointer(refinementFunc,  2);
8520   *refinementFunc = mesh->refinementFunc;
8521   PetscFunctionReturn(0);
8522 }
8523 
8524 PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
8525 {
8526   PetscInt       dim, cStart, cEnd, coneSize, cMax, fMax;
8527   PetscErrorCode ierr;
8528 
8529   PetscFunctionBegin;
8530   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
8531   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8532   if (cEnd <= cStart) {*cellRefiner = REFINER_NOOP; PetscFunctionReturn(0);}
8533   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
8534   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, NULL, NULL);CHKERRQ(ierr);
8535   switch (dim) {
8536   case 1:
8537     switch (coneSize) {
8538     case 2:
8539       *cellRefiner = REFINER_SIMPLEX_1D;
8540       break;
8541     default:
8542       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
8543     }
8544     break;
8545   case 2:
8546     switch (coneSize) {
8547     case 3:
8548       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_2D;
8549       else *cellRefiner = REFINER_SIMPLEX_2D;
8550       break;
8551     case 4:
8552       if (cMax >= 0 && fMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_2D;
8553       else *cellRefiner = REFINER_HEX_2D;
8554       break;
8555     default:
8556       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
8557     }
8558     break;
8559   case 3:
8560     switch (coneSize) {
8561     case 4:
8562       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_3D;
8563       else *cellRefiner = REFINER_SIMPLEX_3D;
8564       break;
8565     case 6:
8566       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_3D;
8567       else *cellRefiner = REFINER_HEX_3D;
8568       break;
8569     default:
8570       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
8571     }
8572     break;
8573   default:
8574     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
8575   }
8576   PetscFunctionReturn(0);
8577 }
8578 
8579 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
8580 {
8581   PetscBool      isUniform;
8582   PetscErrorCode ierr;
8583 
8584   PetscFunctionBegin;
8585   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
8586   if (isUniform) {
8587     CellRefiner cellRefiner;
8588     PetscBool   localized;
8589 
8590     ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
8591     ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr);
8592     ierr = DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
8593     ierr = DMCopyBoundary(dm, *dmRefined);CHKERRQ(ierr);
8594     if (localized) {ierr = DMLocalizeCoordinates(*dmRefined);CHKERRQ(ierr);}
8595   } else {
8596     ierr = DMPlexRefine_Internal(dm, NULL, dmRefined);CHKERRQ(ierr);
8597   }
8598   PetscFunctionReturn(0);
8599 }
8600 
8601 PetscErrorCode DMRefineHierarchy_Plex(DM dm, PetscInt nlevels, DM dmRefined[])
8602 {
8603   DM             cdm = dm;
8604   PetscInt       r;
8605   PetscBool      isUniform, localized;
8606   PetscErrorCode ierr;
8607 
8608   PetscFunctionBegin;
8609   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
8610   ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
8611   if (isUniform) {
8612     for (r = 0; r < nlevels; ++r) {
8613       CellRefiner cellRefiner;
8614 
8615       ierr = DMPlexGetCellRefiner_Internal(cdm, &cellRefiner);CHKERRQ(ierr);
8616       ierr = DMPlexRefineUniform_Internal(cdm, cellRefiner, &dmRefined[r]);CHKERRQ(ierr);
8617       ierr = DMCopyBoundary(cdm, dmRefined[r]);CHKERRQ(ierr);
8618       if (localized) {ierr = DMLocalizeCoordinates(dmRefined[r]);CHKERRQ(ierr);}
8619       ierr = DMSetCoarseDM(dmRefined[r], cdm);CHKERRQ(ierr);
8620       ierr = DMPlexSetRegularRefinement(dmRefined[r], PETSC_TRUE);CHKERRQ(ierr);
8621       cdm  = dmRefined[r];
8622     }
8623   } else {
8624     for (r = 0; r < nlevels; ++r) {
8625       ierr = DMRefine(cdm, PetscObjectComm((PetscObject) dm), &dmRefined[r]);CHKERRQ(ierr);
8626       ierr = DMCopyBoundary(cdm, dmRefined[r]);CHKERRQ(ierr);
8627       if (localized) {ierr = DMLocalizeCoordinates(dmRefined[r]);CHKERRQ(ierr);}
8628       ierr = DMSetCoarseDM(dmRefined[r], cdm);CHKERRQ(ierr);
8629       cdm  = dmRefined[r];
8630     }
8631   }
8632   PetscFunctionReturn(0);
8633 }
8634