xref: /petsc/src/dm/impls/plex/plexrefine.c (revision fa17ad41d4319bf289742c142d49375a1b3c5cff)
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_HYBRID_SIMPLEX_TO_HEX_2D:
255     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
256     depthSize[0] = vEnd - vStart + fEnd - fStart + cEnd - cStart;           /* Add a vertex on every face and cell */
257     depthSize[1] = 2*(fEnd - fStart) + 3*(cMax - cStart) + 4*(cEnd - cMax); /* Every face is split into 2 faces and 3 faces are added for each cell. 4 for each hybrid cell */
258     depthSize[2] = 3*(cMax - cStart) + 4*(cEnd - cMax);                     /* Every cell split into 3 cells, hybrid cells split in 4 */
259     break;
260   case REFINER_HEX_2D:
261     depthSize[0] = vEnd - vStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every face and cell */
262     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
263     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
264     break;
265   case REFINER_HYBRID_HEX_2D:
266     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
267     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
268     /* Quadrilateral */
269     depthSize[0] = vEnd - vStart + fMax - fStart + cMax - cStart;                 /* Add a vertex on every face and cell */
270     depthSize[1] = 2*(fMax - fStart) + 4*(cMax - cStart);                         /* Every face is split into 2 faces, and 4 faces are added for each cell */
271     depthSize[2] = 4*(cMax - cStart);                                             /* Every cell split into 4 cells */
272     /* Segment Prisms */
273     depthSize[0] += 0;                                                            /* No hybrid vertices */
274     depthSize[1] +=   (fEnd - fMax)  +   (cEnd - cMax);                           /* Every hybrid face remains and 1 faces is added for each hybrid cell */
275     depthSize[2] += 2*(cEnd - cMax);                                              /* Every hybrid cell split into 2 cells */
276     break;
277   case REFINER_SIMPLEX_3D:
278     depthSize[0] =    vEnd - vStart  +    eEnd - eStart;                    /* Add a vertex on every edge */
279     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 */
280     depthSize[2] = 4*(fEnd - fStart) + 8*(cEnd - cStart);                   /* Every face split into 4 faces and 8 faces are added for each cell */
281     depthSize[3] = 8*(cEnd - cStart);                                       /* Every cell split into 8 cells */
282     break;
283   case REFINER_HYBRID_SIMPLEX_3D:
284     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
285     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
286     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
287     /* Tetrahedra */
288     depthSize[0]  =    vEnd - vStart  +    eMax - eStart;                    /* Add a vertex on every interior edge */
289     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 */
290     depthSize[2]  = 4*(fMax - fStart) + 8*(cMax - cStart);                   /* Every interior face split into 4 faces, 8 faces added for each interior cell */
291     depthSize[3]  = 8*(cMax - cStart);                                       /* Every interior cell split into 8 cells */
292     /* Triangular Prisms */
293     depthSize[0] += 0;                                                       /* No hybrid vertices */
294     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax);                     /* Every hybrid edge remains, 1 edge for every hybrid face */
295     depthSize[2] += 2*(fEnd - fMax)   + 3*(cEnd - cMax);                     /* Every hybrid face split into 2 faces and 3 faces are added for each hybrid cell */
296     depthSize[3] += 4*(cEnd - cMax);                                         /* Every hybrid cell split into 4 cells */
297     break;
298   case REFINER_SIMPLEX_TO_HEX_3D:
299     depthSize[0] = vEnd - vStart + fEnd - fStart + eEnd - eStart + cEnd - cStart; /* Add a vertex on every face, edge and cell */
300     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 */
301     depthSize[2] = 3*(fEnd - fStart) + 6*(cEnd - cStart);                         /* Every face is split into 3 faces and 6 faces are added for each cell */
302     depthSize[3] = 4*(cEnd - cStart);                                             /* Every cell split into 4 cells */
303     break;
304   case REFINER_HYBRID_SIMPLEX_TO_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     /* Tetrahedra */
309     depthSize[0]  =    vEnd - vStart  +    eMax - eStart  + fMax - fStart + cMax - cStart; /* Add a vertex on every interior edge, face and cell */
310     depthSize[1]  = 2*(eMax - eStart) + 3*(fMax - fStart) + 4*(cMax - cStart);             /* Every interior edge split into 2 edges, 3 edges added for each interior face, 4 edges for each interior cell */
311     depthSize[2]  = 3*(fMax - fStart) + 6*(cMax - cStart);                                 /* Every interior face split into 3 faces, 6 faces added for each interior cell */
312     depthSize[3]  = 4*(cMax - cStart);                                                     /* Every interior cell split into 8 cells */
313     /* Triangular 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 cell */
316     depthSize[2] += 2*(fEnd - fMax) + 3*(cEnd - cMax);                 /* Every hybrid face split into 2 faces and 3 faces are added for each hybrid cell */
317     depthSize[3] += 3*(cEnd - cMax);                                   /* Every hybrid cell split into 3 cells */
318     break;
319   case REFINER_HEX_3D:
320     depthSize[0] = vEnd - vStart + eEnd - eStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every edge, face and cell */
321     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 */
322     depthSize[2] = 4*(fEnd - fStart) + 12*(cEnd - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
323     depthSize[3] = 8*(cEnd - cStart);                                             /* Every cell split into 8 cells */
324     break;
325   case REFINER_HYBRID_HEX_3D:
326     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
327     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
328     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
329     /* Hexahedra */
330     depthSize[0] = vEnd - vStart + eMax - eStart + fMax - fStart + cMax - cStart; /* Add a vertex on every edge, face and cell */
331     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 */
332     depthSize[2] = 4*(fMax - fStart) + 12*(cMax - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
333     depthSize[3] = 8*(cMax - cStart);                                             /* Every cell split into 8 cells */
334     /* Quadrilateral Prisms */
335     depthSize[0] += 0;                                                            /* No hybrid vertices */
336     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax)   +   (cEnd - cMax);      /* Every hybrid edge remains, 1 edge for every hybrid face and hybrid cell */
337     depthSize[2] += 2*(fEnd - fMax)   + 4*(cEnd - cMax);                          /* Every hybrid face split into 2 faces and 4 faces are added for each hybrid cell */
338     depthSize[3] += 4*(cEnd - cMax);                                              /* Every hybrid cell split into 4 cells */
339     break;
340   default:
341     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
342   }
343   PetscFunctionReturn(0);
344 }
345 
346 /* Return triangle edge for orientation o, if it is r for o == 0 */
347 PETSC_STATIC_INLINE PetscInt GetTriEdge_Static(PetscInt o, PetscInt r) {
348   return (o < 0 ? 2-(o+r) : o+r)%3;
349 }
350 PETSC_STATIC_INLINE PetscInt GetTriEdgeInverse_Static(PetscInt o, PetscInt s) {
351   return (o < 0 ? 2-(o+s) : 3+s-o)%3;
352 }
353 
354 /* Return triangle subface for orientation o, if it is r for o == 0 */
355 PETSC_STATIC_INLINE PetscInt GetTriSubface_Static(PetscInt o, PetscInt r) {
356   return (o < 0 ? 3-(o+r) : o+r)%3;
357 }
358 PETSC_STATIC_INLINE PetscInt GetTriSubfaceInverse_Static(PetscInt o, PetscInt s) {
359   return (o < 0 ? 3-(o+s) : 3+s-o)%3;
360 }
361 
362 /* Return the interior edge number connecting the midpoints of the triangle edges r
363    and r+1 in the transitive closure for triangle orientation o */
364 PETSC_STATIC_INLINE PetscInt GetTriMidEdge_Static(PetscInt o, PetscInt r) {
365   return (o < 0 ? 1-(o+r) : o+r)%3;
366 }
367 PETSC_STATIC_INLINE PetscInt GetTriMidEdgeInverse_Static(PetscInt o, PetscInt s) {
368   return (o < 0 ? 1-(o+s) : 3+s-o)%3;
369 }
370 
371 /* Return the interior edge number connecting the midpoint of the triangle edge r
372    (in the transitive closure) and the vertex in the interior of the face for triangle orientation o */
373 PETSC_STATIC_INLINE PetscInt GetTriInteriorEdge_Static(PetscInt o, PetscInt r) {
374   return (o < 0 ? 2-(o+r) : o+r)%3;
375 }
376 PETSC_STATIC_INLINE PetscInt GetTriInteriorEdgeInverse_Static(PetscInt o, PetscInt s) {
377   return (o < 0 ? 2-(o+s) : 3+s-o)%3;
378 }
379 
380 /* Return quad edge for orientation o, if it is r for o == 0 */
381 PETSC_STATIC_INLINE PetscInt GetQuadEdge_Static(PetscInt o, PetscInt r) {
382   return (o < 0 ? 3-(o+r) : o+r)%4;
383 }
384 PETSC_STATIC_INLINE PetscInt GetQuadEdgeInverse_Static(PetscInt o, PetscInt s) {
385   return (o < 0 ? 3-(o+s) : 4+s-o)%4;
386 }
387 
388 /* Return quad subface for orientation o, if it is r for o == 0 */
389 PETSC_STATIC_INLINE PetscInt GetQuadSubface_Static(PetscInt o, PetscInt r) {
390   return (o < 0 ? 4-(o+r) : o+r)%4;
391 }
392 PETSC_STATIC_INLINE PetscInt GetQuadSubfaceInverse_Static(PetscInt o, PetscInt s) {
393   return (o < 0 ? 4-(o+s) : 4+s-o)%4;
394 }
395 
396 static PetscErrorCode DMLabelSetStratumBounds(DMLabel label, PetscInt value, PetscInt cStart, PetscInt cEnd)
397 {
398   IS             cIS;
399   PetscErrorCode ierr;
400 
401   PetscFunctionBegin;
402   ierr = ISCreateStride(PETSC_COMM_SELF, cEnd - cStart, cStart, 1, &cIS);CHKERRQ(ierr);
403   ierr = DMLabelSetStratumIS(label, value, cIS);CHKERRQ(ierr);
404   ierr = ISDestroy(&cIS);CHKERRQ(ierr);
405   PetscFunctionReturn(0);
406 }
407 
408 static PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
409 {
410   PetscInt       depth, cStart, cStartNew, cEnd, cEndNew, cMax, c, vStart, vStartNew, vEnd, vEndNew, vMax, v, fStart, fStartNew, fEnd, fEndNew, fMax, f, eStart, eStartNew, eEnd, eEndNew, eMax, e, r;
411   DMLabel        depthLabel;
412   PetscErrorCode ierr;
413 
414   PetscFunctionBegin;
415   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
416   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
417   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
418   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
419   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
420   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
421   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
422   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
423   ierr = DMCreateLabel(rdm,"depth");CHKERRQ(ierr);
424   ierr = DMPlexGetDepthLabel(rdm,&depthLabel);CHKERRQ(ierr);
425   ierr = DMLabelSetStratumBounds(depthLabel, 0, vStartNew, vEndNew);CHKERRQ(ierr);
426   if (depth > 2) ierr = DMLabelSetStratumBounds(depthLabel, 1, eStartNew, eEndNew);CHKERRQ(ierr);
427   if (depth > 1) ierr = DMLabelSetStratumBounds(depthLabel, depth - 1, fStartNew, fEndNew);CHKERRQ(ierr);
428   if (depth > 0) ierr = DMLabelSetStratumBounds(depthLabel, depth, cStartNew, cEndNew);CHKERRQ(ierr);
429   {
430     DM_Plex *plex = (DM_Plex *) rdm->data;
431     ierr = DMLabelGetState(depthLabel, &plex->depthState);CHKERRQ(ierr);
432   }
433   if (!refiner) PetscFunctionReturn(0);
434   switch (refiner) {
435   case REFINER_SIMPLEX_1D:
436     /* All cells have 2 vertices */
437     for (c = cStart; c < cEnd; ++c) {
438       for (r = 0; r < 2; ++r) {
439         const PetscInt newp = cStartNew + (c - cStart)*2 + r;
440 
441         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
442       }
443     }
444     /* Old vertices have identical supports */
445     for (v = vStart; v < vEnd; ++v) {
446       const PetscInt newp = vStartNew + (v - vStart);
447       PetscInt       size;
448 
449       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
450       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
451     }
452     /* Cell vertices have support 2 */
453     for (c = cStart; c < cEnd; ++c) {
454       const PetscInt newp = vStartNew + (vEnd - vStart) + (c - cStart);
455 
456       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
457     }
458     break;
459   case REFINER_SIMPLEX_2D:
460     /* All cells have 3 faces */
461     for (c = cStart; c < cEnd; ++c) {
462       for (r = 0; r < 4; ++r) {
463         const PetscInt newp = (c - cStart)*4 + r;
464 
465         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
466       }
467     }
468     /* Split faces have 2 vertices and the same cells as the parent */
469     for (f = fStart; f < fEnd; ++f) {
470       for (r = 0; r < 2; ++r) {
471         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
472         PetscInt       size;
473 
474         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
475         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
476         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
477       }
478     }
479     /* Interior faces have 2 vertices and 2 cells */
480     for (c = cStart; c < cEnd; ++c) {
481       for (r = 0; r < 3; ++r) {
482         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
483 
484         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
485         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
486       }
487     }
488     /* Old vertices have identical supports */
489     for (v = vStart; v < vEnd; ++v) {
490       const PetscInt newp = vStartNew + (v - vStart);
491       PetscInt       size;
492 
493       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
494       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
495     }
496     /* Face vertices have 2 + cells*2 supports */
497     for (f = fStart; f < fEnd; ++f) {
498       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
499       PetscInt       size;
500 
501       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
502       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
503     }
504     break;
505   case REFINER_SIMPLEX_TO_HEX_2D:
506     /* All cells have 4 faces */
507     for (c = cStart; c < cEnd; ++c) {
508       for (r = 0; r < 3; ++r) {
509         const PetscInt newp = (c - cStart)*3 + r;
510 
511         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
512       }
513     }
514     /* Split faces have 2 vertices and the same cells as the parent */
515     for (f = fStart; f < fEnd; ++f) {
516       for (r = 0; r < 2; ++r) {
517         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
518         PetscInt       size;
519 
520         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
521         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
522         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
523       }
524     }
525     /* Interior faces have 2 vertices and 2 cells */
526     for (c = cStart; c < cEnd; ++c) {
527       for (r = 0; r < 3; ++r) {
528         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
529 
530         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
531         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
532       }
533     }
534     /* Old vertices have identical supports */
535     for (v = vStart; v < vEnd; ++v) {
536       const PetscInt newp = vStartNew + (v - vStart);
537       PetscInt       size;
538 
539       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
540       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
541     }
542     /* Split-face vertices have cells + 2 supports */
543     for (f = fStart; f < fEnd; ++f) {
544       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
545       PetscInt       size;
546 
547       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
548       ierr = DMPlexSetSupportSize(rdm, newp, size + 2);CHKERRQ(ierr);
549     }
550     /* Interior vertices have 3 supports */
551     for (c = cStart; c < cEnd; ++c) {
552       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
553 
554       ierr = DMPlexSetSupportSize(rdm, newp, 3);CHKERRQ(ierr);
555     }
556     break;
557   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
558     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
559     /* the mesh is no longer hybrid */
560     cMax = PetscMin(cEnd, cMax);
561     /* All cells have 4 faces */
562     for (c = cStart; c < cMax; ++c) {
563       for (r = 0; r < 3; ++r) {
564         const PetscInt newp = (c - cStart)*3 + r;
565 
566         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
567       }
568     }
569     for (c = cMax; c < cEnd; ++c) {
570       for (r = 0; r < 4; ++r) {
571         const PetscInt newp = (cMax - cStart)*3 + (c - cMax)*4 + r;
572 
573         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
574       }
575     }
576     /* Split faces have 2 vertices and the same cells as the parent */
577     for (f = fStart; f < fEnd; ++f) {
578       for (r = 0; r < 2; ++r) {
579         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
580         PetscInt       size;
581 
582         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
583         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
584         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
585       }
586     }
587     /* Interior faces have 2 vertices and 2 cells */
588     for (c = cStart; c < cMax; ++c) {
589       for (r = 0; r < 3; ++r) {
590         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
591 
592         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
593         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
594       }
595     }
596     /* Hybrid interior faces have 2 vertices and 2 cells */
597     for (c = cMax; c < cEnd; ++c) {
598       for (r = 0; r < 4; ++r) {
599         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + r;
600 
601         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
602         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
603       }
604     }
605     /* Old vertices have identical supports */
606     for (v = vStart; v < vEnd; ++v) {
607       const PetscInt newp = vStartNew + (v - vStart);
608       PetscInt       size;
609 
610       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
611       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
612     }
613     /* Split-face vertices have cells + 2 supports */
614     for (f = fStart; f < fEnd; ++f) {
615       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
616       PetscInt       size;
617 
618       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
619       ierr = DMPlexSetSupportSize(rdm, newp, size + 2);CHKERRQ(ierr);
620     }
621     /* Interior vertices have 3 supports */
622     for (c = cStart; c < cMax; ++c) {
623       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
624 
625       ierr = DMPlexSetSupportSize(rdm, newp, 3);CHKERRQ(ierr);
626     }
627     /* Hybrid interior vertices have 4 supports */
628     for (c = cMax; c < cEnd; ++c) {
629       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
630 
631       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
632     }
633     break;
634   case REFINER_HEX_2D:
635     /* All cells have 4 faces */
636     for (c = cStart; c < cEnd; ++c) {
637       for (r = 0; r < 4; ++r) {
638         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
639 
640         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
641       }
642     }
643     /* Split faces have 2 vertices and the same cells as the parent */
644     for (f = fStart; f < fEnd; ++f) {
645       for (r = 0; r < 2; ++r) {
646         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
647         PetscInt       size;
648 
649         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
650         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
651         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
652       }
653     }
654     /* Interior faces have 2 vertices and 2 cells */
655     for (c = cStart; c < cEnd; ++c) {
656       for (r = 0; r < 4; ++r) {
657         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
658 
659         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
660         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
661       }
662     }
663     /* Old vertices have identical supports */
664     for (v = vStart; v < vEnd; ++v) {
665       const PetscInt newp = vStartNew + (v - vStart);
666       PetscInt       size;
667 
668       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
669       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
670     }
671     /* Face vertices have 2 + cells supports */
672     for (f = fStart; f < fEnd; ++f) {
673       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
674       PetscInt       size;
675 
676       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
677       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
678     }
679     /* Cell vertices have 4 supports */
680     for (c = cStart; c < cEnd; ++c) {
681       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
682 
683       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
684     }
685     break;
686   case REFINER_HYBRID_SIMPLEX_2D:
687     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
688     cMax = PetscMin(cEnd, cMax);
689     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
690     fMax = PetscMin(fEnd, fMax);
691     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
692     /* Interior cells have 3 faces */
693     for (c = cStart; c < cMax; ++c) {
694       for (r = 0; r < 4; ++r) {
695         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
696 
697         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
698       }
699     }
700     /* Hybrid cells have 4 faces */
701     for (c = cMax; c < cEnd; ++c) {
702       for (r = 0; r < 2; ++r) {
703         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
704 
705         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
706       }
707     }
708     /* Interior split faces have 2 vertices and the same cells as the parent */
709     for (f = fStart; f < fMax; ++f) {
710       for (r = 0; r < 2; ++r) {
711         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
712         PetscInt       size;
713 
714         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
715         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
716         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
717       }
718     }
719     /* Interior cell faces have 2 vertices and 2 cells */
720     for (c = cStart; c < cMax; ++c) {
721       for (r = 0; r < 3; ++r) {
722         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
723 
724         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
725         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
726       }
727     }
728     /* Hybrid faces have 2 vertices and the same cells */
729     for (f = fMax; f < fEnd; ++f) {
730       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
731       PetscInt       size;
732 
733       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
734       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
735       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
736     }
737     /* Hybrid cell faces have 2 vertices and 2 cells */
738     for (c = cMax; c < cEnd; ++c) {
739       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
740 
741       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
742       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
743     }
744     /* Old vertices have identical supports */
745     for (v = vStart; v < vEnd; ++v) {
746       const PetscInt newp = vStartNew + (v - vStart);
747       PetscInt       size;
748 
749       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
750       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
751     }
752     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
753     for (f = fStart; f < fMax; ++f) {
754       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
755       const PetscInt *support;
756       PetscInt       size, newSize = 2, s;
757 
758       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
759       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
760       for (s = 0; s < size; ++s) {
761         if (support[s] >= cMax) newSize += 1;
762         else newSize += 2;
763       }
764       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
765     }
766     break;
767   case REFINER_HYBRID_HEX_2D:
768     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
769     cMax = PetscMin(cEnd, cMax);
770     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
771     fMax = PetscMin(fEnd, fMax);
772     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
773     /* Interior cells have 4 faces */
774     for (c = cStart; c < cMax; ++c) {
775       for (r = 0; r < 4; ++r) {
776         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
777 
778         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
779       }
780     }
781     /* Hybrid cells have 4 faces */
782     for (c = cMax; c < cEnd; ++c) {
783       for (r = 0; r < 2; ++r) {
784         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
785 
786         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
787       }
788     }
789     /* Interior split faces have 2 vertices and the same cells as the parent */
790     for (f = fStart; f < fMax; ++f) {
791       for (r = 0; r < 2; ++r) {
792         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
793         PetscInt       size;
794 
795         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
796         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
797         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
798       }
799     }
800     /* Interior cell faces have 2 vertices and 2 cells */
801     for (c = cStart; c < cMax; ++c) {
802       for (r = 0; r < 4; ++r) {
803         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
804 
805         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
806         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
807       }
808     }
809     /* Hybrid faces have 2 vertices and the same cells */
810     for (f = fMax; f < fEnd; ++f) {
811       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
812       PetscInt       size;
813 
814       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
815       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
816       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
817     }
818     /* Hybrid cell faces have 2 vertices and 2 cells */
819     for (c = cMax; c < cEnd; ++c) {
820       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
821 
822       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
823       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
824     }
825     /* Old vertices have identical supports */
826     for (v = vStart; v < vEnd; ++v) {
827       const PetscInt newp = vStartNew + (v - vStart);
828       PetscInt       size;
829 
830       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
831       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
832     }
833     /* Face vertices have 2 + cells supports */
834     for (f = fStart; f < fMax; ++f) {
835       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
836       PetscInt       size;
837 
838       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
839       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
840     }
841     /* Cell vertices have 4 supports */
842     for (c = cStart; c < cMax; ++c) {
843       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
844 
845       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
846     }
847     break;
848   case REFINER_SIMPLEX_3D:
849     /* All cells have 4 faces */
850     for (c = cStart; c < cEnd; ++c) {
851       for (r = 0; r < 8; ++r) {
852         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
853 
854         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
855       }
856     }
857     /* Split faces have 3 edges and the same cells as the parent */
858     for (f = fStart; f < fEnd; ++f) {
859       for (r = 0; r < 4; ++r) {
860         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
861         PetscInt       size;
862 
863         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
864         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
865         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
866       }
867     }
868     /* Interior cell faces have 3 edges and 2 cells */
869     for (c = cStart; c < cEnd; ++c) {
870       for (r = 0; r < 8; ++r) {
871         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + r;
872 
873         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
874         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
875       }
876     }
877     /* Split edges have 2 vertices and the same faces */
878     for (e = eStart; e < eEnd; ++e) {
879       for (r = 0; r < 2; ++r) {
880         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
881         PetscInt       size;
882 
883         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
884         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
885         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
886       }
887     }
888     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
889     for (f = fStart; f < fEnd; ++f) {
890       for (r = 0; r < 3; ++r) {
891         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
892         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
893         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;
894 
895         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
896         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
897         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
898         for (s = 0; s < supportSize; ++s) {
899           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
900           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
901           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
902           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
903           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
904           er = GetTriMidEdgeInverse_Static(ornt[c], r);
905           if (er == eint[c]) {
906             intFaces += 1;
907           } else {
908             intFaces += 2;
909           }
910         }
911         ierr = DMPlexSetSupportSize(rdm, newp, 2+intFaces);CHKERRQ(ierr);
912       }
913     }
914     /* Interior cell edges have 2 vertices and 4 faces */
915     for (c = cStart; c < cEnd; ++c) {
916       const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
917 
918       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
919       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
920     }
921     /* Old vertices have identical supports */
922     for (v = vStart; v < vEnd; ++v) {
923       const PetscInt newp = vStartNew + (v - vStart);
924       PetscInt       size;
925 
926       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
927       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
928     }
929     /* Edge vertices have 2 + faces*2 + cells*0/1 supports */
930     for (e = eStart; e < eEnd; ++e) {
931       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
932       PetscInt       size, *star = NULL, starSize, s, cellSize = 0;
933 
934       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
935       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
936       for (s = 0; s < starSize*2; s += 2) {
937         const PetscInt *cone, *ornt;
938         PetscInt        e01, e23;
939 
940         if ((star[s] >= cStart) && (star[s] < cEnd)) {
941           /* Check edge 0-1 */
942           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
943           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
944           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
945           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
946           /* Check edge 2-3 */
947           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
948           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
949           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
950           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
951           if ((e01 == e) || (e23 == e)) ++cellSize;
952         }
953       }
954       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
955       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2 + cellSize);CHKERRQ(ierr);
956     }
957     break;
958   case REFINER_HYBRID_SIMPLEX_3D:
959     ierr = DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 8*(cMax - cStart),
960                                  eStartNew + 2*(eMax - eStart) + 3*(fMax - fStart) + (cMax - cStart), PETSC_DETERMINE);CHKERRQ(ierr);
961     /* Interior cells have 4 faces */
962     for (c = cStart; c < cMax; ++c) {
963       for (r = 0; r < 8; ++r) {
964         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
965 
966         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
967       }
968     }
969     /* Hybrid cells have 5 faces */
970     for (c = cMax; c < cEnd; ++c) {
971       for (r = 0; r < 4; ++r) {
972         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;
973 
974         ierr = DMPlexSetConeSize(rdm, newp, 5);CHKERRQ(ierr);
975       }
976     }
977     /* Interior split faces have 3 edges and the same cells as the parent */
978     for (f = fStart; f < fMax; ++f) {
979       for (r = 0; r < 4; ++r) {
980         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
981         PetscInt       size;
982 
983         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
984         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
985         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
986       }
987     }
988     /* Interior cell faces have 3 edges and 2 cells */
989     for (c = cStart; c < cMax; ++c) {
990       for (r = 0; r < 8; ++r) {
991         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + r;
992 
993         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
994         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
995       }
996     }
997     /* Hybrid split faces have 4 edges and the same cells as the parent */
998     for (f = fMax; f < fEnd; ++f) {
999       for (r = 0; r < 2; ++r) {
1000         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
1001         PetscInt       size;
1002 
1003         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1004         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1005         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1006       }
1007     }
1008     /* Hybrid cells faces have 4 edges and 2 cells */
1009     for (c = cMax; c < cEnd; ++c) {
1010       for (r = 0; r < 3; ++r) {
1011         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + r;
1012 
1013         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1014         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1015       }
1016     }
1017     /* Interior split edges have 2 vertices and the same faces */
1018     for (e = eStart; e < eMax; ++e) {
1019       for (r = 0; r < 2; ++r) {
1020         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1021         PetscInt       size;
1022 
1023         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1024         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1025         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1026       }
1027     }
1028     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
1029     for (f = fStart; f < fMax; ++f) {
1030       for (r = 0; r < 3; ++r) {
1031         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
1032         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
1033         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;
1034 
1035         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1036         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1037         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1038         for (s = 0; s < supportSize; ++s) {
1039           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1040           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1041           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1042           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
1043           if (support[s] < cMax) {
1044             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
1045             er = GetTriMidEdgeInverse_Static(ornt[c], r);
1046             if (er == eint[c]) {
1047               intFaces += 1;
1048             } else {
1049               intFaces += 2;
1050             }
1051           } else {
1052             intFaces += 1;
1053           }
1054         }
1055         ierr = DMPlexSetSupportSize(rdm, newp, 2+intFaces);CHKERRQ(ierr);
1056       }
1057     }
1058     /* Interior cell edges have 2 vertices and 4 faces */
1059     for (c = cStart; c < cMax; ++c) {
1060       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
1061 
1062       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1063       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1064     }
1065     /* Hybrid edges have 2 vertices and the same faces */
1066     for (e = eMax; e < eEnd; ++e) {
1067       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
1068       PetscInt       size;
1069 
1070       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1071       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1072       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1073     }
1074     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
1075     for (f = fMax; f < fEnd; ++f) {
1076       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
1077       PetscInt       size;
1078 
1079       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1080       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1081       ierr = DMPlexSetSupportSize(rdm, newp, 2+2*size);CHKERRQ(ierr);
1082     }
1083     /* Interior vertices have identical supports */
1084     for (v = vStart; v < vEnd; ++v) {
1085       const PetscInt newp = vStartNew + (v - vStart);
1086       PetscInt       size;
1087 
1088       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1089       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1090     }
1091     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
1092     for (e = eStart; e < eMax; ++e) {
1093       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
1094       const PetscInt *support;
1095       PetscInt        size, *star = NULL, starSize, s, faceSize = 0, cellSize = 0;
1096 
1097       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1098       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
1099       for (s = 0; s < size; ++s) {
1100         if (support[s] < fMax) faceSize += 2;
1101         else                   faceSize += 1;
1102       }
1103       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
1104       for (s = 0; s < starSize*2; s += 2) {
1105         const PetscInt *cone, *ornt;
1106         PetscInt        e01, e23;
1107 
1108         if ((star[s] >= cStart) && (star[s] < cMax)) {
1109           /* Check edge 0-1 */
1110           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
1111           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
1112           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
1113           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
1114           /* Check edge 2-3 */
1115           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
1116           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
1117           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
1118           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
1119           if ((e01 == e) || (e23 == e)) ++cellSize;
1120         }
1121       }
1122       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
1123       ierr = DMPlexSetSupportSize(rdm, newp, 2 + faceSize + cellSize);CHKERRQ(ierr);
1124     }
1125     break;
1126   case REFINER_SIMPLEX_TO_HEX_3D:
1127     /* All cells have 6 faces */
1128     for (c = cStart; c < cEnd; ++c) {
1129       for (r = 0; r < 4; ++r) {
1130         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
1131 
1132         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1133       }
1134     }
1135     /* Split faces have 4 edges and the same cells as the parent */
1136     for (f = fStart; f < fEnd; ++f) {
1137       for (r = 0; r < 3; ++r) {
1138         const PetscInt newp = fStartNew + (f - fStart)*3 + r;
1139         PetscInt       size;
1140 
1141         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1142         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1143         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1144       }
1145     }
1146     /* Interior cell faces have 4 edges and 2 cells */
1147     for (c = cStart; c < cEnd; ++c) {
1148       for (r = 0; r < 6; ++r) {
1149         const PetscInt newp = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + r;
1150 
1151         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1152         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1153       }
1154     }
1155     /* Split edges have 2 vertices and the same faces */
1156     for (e = eStart; e < eEnd; ++e) {
1157       for (r = 0; r < 2; ++r) {
1158         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1159         PetscInt       size;
1160 
1161         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1162         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1163         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1164       }
1165     }
1166     /* Face edges have 2 vertices and 2 + cell faces supports */
1167     for (f = fStart; f < fEnd; ++f) {
1168       for (r = 0; r < 3; ++r) {
1169         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
1170         PetscInt        size;
1171 
1172         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1173         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1174         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1175       }
1176     }
1177     /* Interior cell edges have 2 vertices and 3 faces */
1178     for (c = cStart; c < cEnd; ++c) {
1179       for (r = 0; r < 4; ++r) {
1180         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + r;
1181 
1182         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1183         ierr = DMPlexSetSupportSize(rdm, newp, 3);CHKERRQ(ierr);
1184       }
1185     }
1186     /* Old vertices have identical supports */
1187     for (v = vStart; v < vEnd; ++v) {
1188       const PetscInt newp = vStartNew + (v - vStart);
1189       PetscInt       size;
1190 
1191       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1192       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1193     }
1194     /* Edge vertices have 2 + faces supports */
1195     for (e = eStart; e < eEnd; ++e) {
1196       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1197       PetscInt       size;
1198 
1199       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1200       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1201     }
1202     /* Face vertices have 3 + cells supports */
1203     for (f = fStart; f < fEnd; ++f) {
1204       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + f - fStart;
1205       PetscInt       size;
1206 
1207       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1208       ierr = DMPlexSetSupportSize(rdm, newp, 3 + size);CHKERRQ(ierr);
1209     }
1210     /* Interior cell vertices have 4 supports */
1211     for (c = cStart; c < cEnd; ++c) {
1212       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + fEnd - fStart + c - cStart;
1213 
1214       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1215     }
1216     break;
1217   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
1218     /* the mesh is no longer hybrid */
1219     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
1220     cMax = PetscMin(cEnd, cMax);
1221     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
1222     fMax = PetscMin(fEnd, fMax);
1223     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
1224     eMax = PetscMin(eEnd, eMax);
1225     /* All cells have 6 faces */
1226     for (c = cStart; c < cMax; ++c) {
1227       for (r = 0; r < 4; ++r) {
1228         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
1229 
1230         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1231       }
1232     }
1233     for (c = cMax; c < cEnd; ++c) {
1234       for (r = 0; r < 3; ++r) {
1235         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + r;
1236 
1237         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1238       }
1239     }
1240     /* Interior split faces have 4 edges and the same cells as the parent */
1241     for (f = fStart; f < fMax; ++f) {
1242       for (r = 0; r < 3; ++r) {
1243         const PetscInt newp = fStartNew + (f - fStart)*3 + r;
1244         PetscInt       size;
1245 
1246         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1247         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1248         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1249       }
1250     }
1251     /* Interior cell faces have 4 edges and 2 cells */
1252     for (c = cStart; c < cMax; ++c) {
1253       for (r = 0; r < 6; ++r) {
1254         const PetscInt newp = fStartNew + (fMax - fStart)*3 + (c - cStart)*6 + r;
1255 
1256         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1257         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1258       }
1259     }
1260     /* Hybrid split faces have 4 edges and the same cells as the parent */
1261     for (f = fMax; f < fEnd; ++f) {
1262       for (r = 0; r < 2; ++r) {
1263         const PetscInt newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (f - fMax)*2 + r;
1264         PetscInt       size;
1265 
1266         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1267         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1268         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1269       }
1270     }
1271     /* Hybrid cell faces have 4 edges and 2 cells */
1272     for (c = cMax; c < cEnd; ++c) {
1273       for (r = 0; r < 3; ++r) {
1274         const PetscInt newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + r;
1275 
1276         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1277         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1278       }
1279     }
1280     /* Interior split edges have 2 vertices and the same faces */
1281     for (e = eStart; e < eMax; ++e) {
1282       for (r = 0; r < 2; ++r) {
1283         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1284         PetscInt       size;
1285 
1286         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1287         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1288         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1289       }
1290     }
1291     /* Interior face edges have 2 vertices and 2 + cell faces supports */
1292     for (f = fStart; f < fMax; ++f) {
1293       for (r = 0; r < 3; ++r) {
1294         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
1295         PetscInt        size;
1296 
1297         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1298         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1299         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1300       }
1301     }
1302     /* Interior cell edges have 2 vertices and 3 faces */
1303     for (c = cStart; c < cMax; ++c) {
1304       for (r = 0; r < 4; ++r) {
1305         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + r;
1306 
1307         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1308         ierr = DMPlexSetSupportSize(rdm, newp, 3);CHKERRQ(ierr);
1309       }
1310     }
1311     /* Hybrid edges have 2 vertices and the same faces */
1312     for (e = eMax; e < eEnd; ++e) {
1313       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (e - eMax);
1314       PetscInt       size;
1315 
1316       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1317       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1318       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1319     }
1320     /* Hybrid face edges have 2 vertices and 2+cells faces */
1321     for (f = fMax; f < fEnd; ++f) {
1322       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (f - fMax);
1323       PetscInt        size;
1324 
1325       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1326       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1327       ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1328     }
1329     /* Hybrid cell edges have 2 vertices and 3 faces */
1330     for (c = cMax; c < cEnd; ++c) {
1331       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
1332 
1333       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1334       ierr = DMPlexSetSupportSize(rdm, newp, 3);CHKERRQ(ierr);
1335     }
1336     /* Old vertices have identical supports */
1337     for (v = vStart; v < vEnd; ++v) {
1338       const PetscInt newp = vStartNew + (v - vStart);
1339       PetscInt       size;
1340 
1341       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1342       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1343     }
1344     /* Interior edge vertices have 2 + faces supports */
1345     for (e = eStart; e < eMax; ++e) {
1346       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1347       PetscInt       size;
1348 
1349       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1350       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1351     }
1352     /* Interior face vertices have 3 + cells supports */
1353     for (f = fStart; f < fMax; ++f) {
1354       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + f - fStart;
1355       PetscInt       size;
1356 
1357       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1358       ierr = DMPlexSetSupportSize(rdm, newp, 3 + size);CHKERRQ(ierr);
1359     }
1360     /* Interior cell vertices have 4 supports */
1361     for (c = cStart; c < cMax; ++c) {
1362       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + c - cStart;
1363 
1364       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1365     }
1366     break;
1367   case REFINER_HEX_3D:
1368     /* All cells have 6 faces */
1369     for (c = cStart; c < cEnd; ++c) {
1370       for (r = 0; r < 8; ++r) {
1371         const PetscInt newp = (c - cStart)*8 + r;
1372 
1373         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1374       }
1375     }
1376     /* Split faces have 4 edges and the same cells as the parent */
1377     for (f = fStart; f < fEnd; ++f) {
1378       for (r = 0; r < 4; ++r) {
1379         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
1380         PetscInt       size;
1381 
1382         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1383         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1384         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1385       }
1386     }
1387     /* Interior faces have 4 edges and 2 cells */
1388     for (c = cStart; c < cEnd; ++c) {
1389       for (r = 0; r < 12; ++r) {
1390         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
1391 
1392         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1393         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1394       }
1395     }
1396     /* Split edges have 2 vertices and the same faces as the parent */
1397     for (e = eStart; e < eEnd; ++e) {
1398       for (r = 0; r < 2; ++r) {
1399         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1400         PetscInt       size;
1401 
1402         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1403         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1404         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1405       }
1406     }
1407     /* Face edges have 2 vertices and 2+cells faces */
1408     for (f = fStart; f < fEnd; ++f) {
1409       for (r = 0; r < 4; ++r) {
1410         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
1411         PetscInt       size;
1412 
1413         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1414         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1415         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1416       }
1417     }
1418     /* Cell edges have 2 vertices and 4 faces */
1419     for (c = cStart; c < cEnd; ++c) {
1420       for (r = 0; r < 6; ++r) {
1421         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
1422 
1423         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1424         ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1425       }
1426     }
1427     /* Old vertices have identical supports */
1428     for (v = vStart; v < vEnd; ++v) {
1429       const PetscInt newp = vStartNew + (v - vStart);
1430       PetscInt       size;
1431 
1432       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1433       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1434     }
1435     /* Edge vertices have 2 + faces supports */
1436     for (e = eStart; e < eEnd; ++e) {
1437       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1438       PetscInt       size;
1439 
1440       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1441       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1442     }
1443     /* Face vertices have 4 + cells supports */
1444     for (f = fStart; f < fEnd; ++f) {
1445       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
1446       PetscInt       size;
1447 
1448       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1449       ierr = DMPlexSetSupportSize(rdm, newp, 4 + size);CHKERRQ(ierr);
1450     }
1451     /* Cell vertices have 6 supports */
1452     for (c = cStart; c < cEnd; ++c) {
1453       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
1454 
1455       ierr = DMPlexSetSupportSize(rdm, newp, 6);CHKERRQ(ierr);
1456     }
1457     break;
1458   case REFINER_HYBRID_HEX_3D:
1459     ierr = DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 12*(cMax - cStart),
1460                                  eStartNew + 2*(eMax - eStart) + 4*(fMax - fStart) + 6*(cMax - cStart), PETSC_DETERMINE);CHKERRQ(ierr);
1461     /* Interior cells have 6 faces */
1462     for (c = cStart; c < cMax; ++c) {
1463       for (r = 0; r < 8; ++r) {
1464         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
1465 
1466         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1467       }
1468     }
1469     /* Hybrid cells have 6 faces */
1470     for (c = cMax; c < cEnd; ++c) {
1471       for (r = 0; r < 4; ++r) {
1472         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;
1473 
1474         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1475       }
1476     }
1477     /* Interior split faces have 4 edges and the same cells as the parent */
1478     for (f = fStart; f < fMax; ++f) {
1479       for (r = 0; r < 4; ++r) {
1480         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
1481         PetscInt       size;
1482 
1483         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1484         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1485         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1486       }
1487     }
1488     /* Interior cell faces have 4 edges and 2 cells */
1489     for (c = cStart; c < cMax; ++c) {
1490       for (r = 0; r < 12; ++r) {
1491         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
1492 
1493         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1494         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1495       }
1496     }
1497     /* Hybrid split faces have 4 edges and the same cells as the parent */
1498     for (f = fMax; f < fEnd; ++f) {
1499       for (r = 0; r < 2; ++r) {
1500         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
1501         PetscInt       size;
1502 
1503         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1504         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1505         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1506       }
1507     }
1508     /* Hybrid cells faces have 4 edges and 2 cells */
1509     for (c = cMax; c < cEnd; ++c) {
1510       for (r = 0; r < 4; ++r) {
1511         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + r;
1512 
1513         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1514         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1515       }
1516     }
1517     /* Interior split edges have 2 vertices and the same faces as the parent */
1518     for (e = eStart; e < eMax; ++e) {
1519       for (r = 0; r < 2; ++r) {
1520         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1521         PetscInt       size;
1522 
1523         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1524         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1525         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1526       }
1527     }
1528     /* Interior face edges have 2 vertices and 2+cells faces */
1529     for (f = fStart; f < fMax; ++f) {
1530       for (r = 0; r < 4; ++r) {
1531         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
1532         PetscInt       size;
1533 
1534         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1535         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1536         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1537       }
1538     }
1539     /* Interior cell edges have 2 vertices and 4 faces */
1540     for (c = cStart; c < cMax; ++c) {
1541       for (r = 0; r < 6; ++r) {
1542         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
1543 
1544         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1545         ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1546       }
1547     }
1548     /* Hybrid edges have 2 vertices and the same faces */
1549     for (e = eMax; e < eEnd; ++e) {
1550       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
1551       PetscInt       size;
1552 
1553       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1554       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1555       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1556     }
1557     /* Hybrid face edges have 2 vertices and 2+cells faces */
1558     for (f = fMax; f < fEnd; ++f) {
1559       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
1560       PetscInt       size;
1561 
1562       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1563       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1564       ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1565     }
1566     /* Hybrid cell edges have 2 vertices and 4 faces */
1567     for (c = cMax; c < cEnd; ++c) {
1568       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
1569 
1570       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1571       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1572     }
1573     /* Interior vertices have identical supports */
1574     for (v = vStart; v < vEnd; ++v) {
1575       const PetscInt newp = vStartNew + (v - vStart);
1576       PetscInt       size;
1577 
1578       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1579       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1580     }
1581     /* Interior edge vertices have 2 + faces supports */
1582     for (e = eStart; e < eMax; ++e) {
1583       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1584       PetscInt       size;
1585 
1586       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1587       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1588     }
1589     /* Interior face vertices have 4 + cells supports */
1590     for (f = fStart; f < fMax; ++f) {
1591       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
1592       PetscInt       size;
1593 
1594       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1595       ierr = DMPlexSetSupportSize(rdm, newp, 4 + size);CHKERRQ(ierr);
1596     }
1597     /* Interior cell vertices have 6 supports */
1598     for (c = cStart; c < cMax; ++c) {
1599       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
1600 
1601       ierr = DMPlexSetSupportSize(rdm, newp, 6);CHKERRQ(ierr);
1602     }
1603     break;
1604   default:
1605     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
1606   }
1607   PetscFunctionReturn(0);
1608 }
1609 
1610 static PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
1611 {
1612   const PetscInt *faces, cellInd[4] = {0, 1, 2, 3};
1613   PetscInt        cStart,    cEnd,    cMax,    vStart,    vEnd, vMax, fStart,    fEnd,    fMax,    eStart,    eEnd,    eMax;
1614   PetscInt        cStartNew, cEndNew, cMaxNew, vStartNew, vEndNew,    fStartNew, fEndNew, fMaxNew, eStartNew, eEndNew, eMaxNew;
1615   PetscInt        depth, maxSupportSize, *supportRef, c, f, e, v, r, p;
1616   PetscErrorCode  ierr;
1617 
1618   PetscFunctionBegin;
1619   if (!refiner) PetscFunctionReturn(0);
1620   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1621   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
1622   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
1623   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1624   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
1625   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
1626   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
1627   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
1628   switch (refiner) {
1629   case REFINER_SIMPLEX_1D:
1630     /* Max support size of refined mesh is 2 */
1631     ierr = PetscMalloc1(2, &supportRef);CHKERRQ(ierr);
1632     /* All cells have 2 vertices */
1633     for (c = cStart; c < cEnd; ++c) {
1634       const PetscInt  newv = vStartNew + (vEnd - vStart) + (c - cStart);
1635 
1636       for (r = 0; r < 2; ++r) {
1637         const PetscInt newp = cStartNew + (c - cStart)*2 + r;
1638         const PetscInt *cone;
1639         PetscInt        coneNew[2];
1640 
1641         ierr             = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1642         coneNew[0]       = vStartNew + (cone[0] - vStart);
1643         coneNew[1]       = vStartNew + (cone[1] - vStart);
1644         coneNew[(r+1)%2] = newv;
1645         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1646 #if 1
1647         if ((newp < cStartNew) || (newp >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp, cStartNew, cEndNew);
1648         for (p = 0; p < 2; ++p) {
1649           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
1650         }
1651 #endif
1652       }
1653     }
1654     /* Old vertices have identical supports */
1655     for (v = vStart; v < vEnd; ++v) {
1656       const PetscInt  newp = vStartNew + (v - vStart);
1657       const PetscInt *support, *cone;
1658       PetscInt        size, s;
1659 
1660       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1661       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1662       for (s = 0; s < size; ++s) {
1663         PetscInt r = 0;
1664 
1665         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1666         if (cone[1] == v) r = 1;
1667         supportRef[s] = cStartNew + (support[s] - cStart)*2 + r;
1668       }
1669       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1670 #if 1
1671       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1672       for (p = 0; p < size; ++p) {
1673         if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
1674       }
1675 #endif
1676     }
1677     /* Cell vertices have support of 2 cells */
1678     for (c = cStart; c < cEnd; ++c) {
1679       const PetscInt  newp = vStartNew + (vEnd - vStart) + (c - cStart);
1680 
1681       supportRef[0] = cStartNew + (c - cStart)*2 + 0;
1682       supportRef[1] = cStartNew + (c - cStart)*2 + 1;
1683       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1684 #if 1
1685       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1686       for (p = 0; p < 2; ++p) {
1687         if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
1688       }
1689 #endif
1690     }
1691     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1692     break;
1693   case REFINER_SIMPLEX_2D:
1694     /*
1695      2
1696      |\
1697      | \
1698      |  \
1699      |   \
1700      | C  \
1701      |     \
1702      |      \
1703      2---1---1
1704      |\  D  / \
1705      | 2   0   \
1706      |A \ /  B  \
1707      0---0-------1
1708      */
1709     /* All cells have 3 faces */
1710     for (c = cStart; c < cEnd; ++c) {
1711       const PetscInt  newp = cStartNew + (c - cStart)*4;
1712       const PetscInt *cone, *ornt;
1713       PetscInt        coneNew[3], orntNew[3];
1714 
1715       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1716       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1717       /* A triangle */
1718       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1719       orntNew[0] = ornt[0];
1720       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1721       orntNew[1] = -2;
1722       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1723       orntNew[2] = ornt[2];
1724       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1725       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1726 #if 1
1727       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
1728       for (p = 0; p < 3; ++p) {
1729         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1730       }
1731 #endif
1732       /* B triangle */
1733       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1734       orntNew[0] = ornt[0];
1735       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1736       orntNew[1] = ornt[1];
1737       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1738       orntNew[2] = -2;
1739       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1740       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1741 #if 1
1742       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
1743       for (p = 0; p < 3; ++p) {
1744         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1745       }
1746 #endif
1747       /* C triangle */
1748       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1749       orntNew[0] = -2;
1750       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1751       orntNew[1] = ornt[1];
1752       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1753       orntNew[2] = ornt[2];
1754       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1755       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1756 #if 1
1757       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
1758       for (p = 0; p < 3; ++p) {
1759         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1760       }
1761 #endif
1762       /* D triangle */
1763       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1764       orntNew[0] = 0;
1765       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1766       orntNew[1] = 0;
1767       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1768       orntNew[2] = 0;
1769       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1770       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1771 #if 1
1772       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
1773       for (p = 0; p < 3; ++p) {
1774         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1775       }
1776 #endif
1777     }
1778     /* Split faces have 2 vertices and the same cells as the parent */
1779     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1780     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
1781     for (f = fStart; f < fEnd; ++f) {
1782       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1783 
1784       for (r = 0; r < 2; ++r) {
1785         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1786         const PetscInt *cone, *ornt, *support;
1787         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1788 
1789         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1790         coneNew[0]       = vStartNew + (cone[0] - vStart);
1791         coneNew[1]       = vStartNew + (cone[1] - vStart);
1792         coneNew[(r+1)%2] = newv;
1793         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1794 #if 1
1795         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1796         for (p = 0; p < 2; ++p) {
1797           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
1798         }
1799 #endif
1800         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1801         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1802         for (s = 0; s < supportSize; ++s) {
1803           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1804           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1805           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1806           for (c = 0; c < coneSize; ++c) {
1807             if (cone[c] == f) break;
1808           }
1809           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1810         }
1811         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1812 #if 1
1813         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1814         for (p = 0; p < supportSize; ++p) {
1815           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
1816         }
1817 #endif
1818       }
1819     }
1820     /* Interior faces have 2 vertices and 2 cells */
1821     for (c = cStart; c < cEnd; ++c) {
1822       const PetscInt *cone;
1823 
1824       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1825       for (r = 0; r < 3; ++r) {
1826         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
1827         PetscInt       coneNew[2];
1828         PetscInt       supportNew[2];
1829 
1830         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
1831         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
1832         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1833 #if 1
1834         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1835         for (p = 0; p < 2; ++p) {
1836           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
1837         }
1838 #endif
1839         supportNew[0] = (c - cStart)*4 + (r+1)%3;
1840         supportNew[1] = (c - cStart)*4 + 3;
1841         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1842 #if 1
1843         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1844         for (p = 0; p < 2; ++p) {
1845           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
1846         }
1847 #endif
1848       }
1849     }
1850     /* Old vertices have identical supports */
1851     for (v = vStart; v < vEnd; ++v) {
1852       const PetscInt  newp = vStartNew + (v - vStart);
1853       const PetscInt *support, *cone;
1854       PetscInt        size, s;
1855 
1856       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1857       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1858       for (s = 0; s < size; ++s) {
1859         PetscInt r = 0;
1860 
1861         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1862         if (cone[1] == v) r = 1;
1863         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1864       }
1865       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1866 #if 1
1867       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1868       for (p = 0; p < size; ++p) {
1869         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
1870       }
1871 #endif
1872     }
1873     /* Face vertices have 2 + cells*2 supports */
1874     for (f = fStart; f < fEnd; ++f) {
1875       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1876       const PetscInt *cone, *support;
1877       PetscInt        size, s;
1878 
1879       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1880       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1881       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1882       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1883       for (s = 0; s < size; ++s) {
1884         PetscInt r = 0;
1885 
1886         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1887         if      (cone[1] == f) r = 1;
1888         else if (cone[2] == f) r = 2;
1889         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
1890         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
1891       }
1892       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1893 #if 1
1894       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1895       for (p = 0; p < 2+size*2; ++p) {
1896         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
1897       }
1898 #endif
1899     }
1900     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1901     break;
1902   case REFINER_SIMPLEX_TO_HEX_2D:
1903     /*
1904      2
1905      |\
1906      | \
1907      |  \
1908      |   \
1909      | C  \
1910      |     \
1911      2      1
1912      |\    / \
1913      | 2  1   \
1914      |  \/     \
1915      |   |      \
1916      |A  |   B   \
1917      |   0        \
1918      |   |         \
1919      0---0----------1
1920      */
1921     /* All cells have 4 faces */
1922     for (c = cStart; c < cEnd; ++c) {
1923       const PetscInt  newp = cStartNew + (c - cStart)*3;
1924       const PetscInt *cone, *ornt;
1925       PetscInt        coneNew[4], orntNew[4];
1926 
1927       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1928       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1929       /* A quad */
1930       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1931       orntNew[0] = ornt[0];
1932       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1933       orntNew[1] = 0;
1934       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1935       orntNew[2] = -2;
1936       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1937       orntNew[3] = ornt[2];
1938       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1939       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1940 #if 1
1941       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
1942       for (p = 0; p < 4; ++p) {
1943         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1944       }
1945 #endif
1946       /* B quad */
1947       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1948       orntNew[0] = ornt[0];
1949       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1950       orntNew[1] = ornt[1];
1951       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1952       orntNew[2] = 0;
1953       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1954       orntNew[3] = -2;
1955       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1956       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1957 #if 1
1958       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
1959       for (p = 0; p < 4; ++p) {
1960         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1961       }
1962 #endif
1963       /* C quad */
1964       coneNew[0] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1965       orntNew[0] = ornt[1];
1966       coneNew[1] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1967       orntNew[1] = ornt[2];
1968       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1969       orntNew[2] = 0;
1970       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1971       orntNew[3] = -2;
1972       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1973       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1974 #if 1
1975       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
1976       for (p = 0; p < 4; ++p) {
1977         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1978       }
1979 #endif
1980     }
1981     /* Split faces have 2 vertices and the same cells as the parent */
1982     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1983     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
1984     for (f = fStart; f < fEnd; ++f) {
1985       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1986 
1987       for (r = 0; r < 2; ++r) {
1988         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1989         const PetscInt *cone, *ornt, *support;
1990         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1991 
1992         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1993         coneNew[0]       = vStartNew + (cone[0] - vStart);
1994         coneNew[1]       = vStartNew + (cone[1] - vStart);
1995         coneNew[(r+1)%2] = newv;
1996         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1997 #if 1
1998         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1999         for (p = 0; p < 2; ++p) {
2000           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2001         }
2002 #endif
2003         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2004         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2005         for (s = 0; s < supportSize; ++s) {
2006           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2007           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2008           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2009           for (c = 0; c < coneSize; ++c) {
2010             if (cone[c] == f) break;
2011           }
2012           supportRef[s] = cStartNew + (support[s] - cStart)*3 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
2013         }
2014         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2015 #if 1
2016         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2017         for (p = 0; p < supportSize; ++p) {
2018           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
2019         }
2020 #endif
2021       }
2022     }
2023     /* Interior faces have 2 vertices and 2 cells */
2024     for (c = cStart; c < cEnd; ++c) {
2025       const PetscInt *cone;
2026 
2027       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2028       for (r = 0; r < 3; ++r) {
2029         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
2030         PetscInt       coneNew[2];
2031         PetscInt       supportNew[2];
2032 
2033         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2034         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
2035         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2036 #if 1
2037         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2038         for (p = 0; p < 2; ++p) {
2039           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2040         }
2041 #endif
2042         supportNew[0] = (c - cStart)*3 + r%3;
2043         supportNew[1] = (c - cStart)*3 + (r+1)%3;
2044         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2045 #if 1
2046         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2047         for (p = 0; p < 2; ++p) {
2048           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
2049         }
2050 #endif
2051       }
2052     }
2053     /* Old vertices have identical supports */
2054     for (v = vStart; v < vEnd; ++v) {
2055       const PetscInt  newp = vStartNew + (v - vStart);
2056       const PetscInt *support, *cone;
2057       PetscInt        size, s;
2058 
2059       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2060       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2061       for (s = 0; s < size; ++s) {
2062         PetscInt r = 0;
2063 
2064         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2065         if (cone[1] == v) r = 1;
2066         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2067       }
2068       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2069 #if 1
2070       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2071       for (p = 0; p < size; ++p) {
2072         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
2073       }
2074 #endif
2075     }
2076     /* Split-face vertices have cells + 2 supports */
2077     for (f = fStart; f < fEnd; ++f) {
2078       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2079       const PetscInt *cone, *support;
2080       PetscInt        size, s;
2081 
2082       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2083       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2084       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2085       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2086       for (s = 0; s < size; ++s) {
2087         PetscInt r = 0;
2088 
2089         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2090         if      (cone[1] == f) r = 1;
2091         else if (cone[2] == f) r = 2;
2092         supportRef[2+s+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
2093       }
2094       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2095 #if 1
2096       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2097       for (p = 0; p < 2+size; ++p) {
2098         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
2099       }
2100 #endif
2101     }
2102     /* Interior vertices have 3 supports */
2103     for (c = cStart; c < cEnd; ++c) {
2104       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
2105 
2106       supportRef[0] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 0;
2107       supportRef[1] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 1;
2108       supportRef[2] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 2;
2109       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2110     }
2111     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2112     break;
2113   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
2114     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
2115     cMax = PetscMin(cEnd, cMax);
2116     for (c = cStart; c < cMax; ++c) {
2117       const PetscInt  newp = cStartNew + (c - cStart)*3;
2118       const PetscInt *cone, *ornt;
2119       PetscInt        coneNew[4], orntNew[4];
2120 
2121       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2122       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2123       /* A quad */
2124       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2125       orntNew[0] = ornt[0];
2126       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
2127       orntNew[1] = 0;
2128       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
2129       orntNew[2] = -2;
2130       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2131       orntNew[3] = ornt[2];
2132       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2133       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2134 #if 1
2135       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
2136       for (p = 0; p < 4; ++p) {
2137         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2138       }
2139 #endif
2140       /* B quad */
2141       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2142       orntNew[0] = ornt[0];
2143       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2144       orntNew[1] = ornt[1];
2145       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
2146       orntNew[2] = 0;
2147       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
2148       orntNew[3] = -2;
2149       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2150       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2151 #if 1
2152       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
2153       for (p = 0; p < 4; ++p) {
2154         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2155       }
2156 #endif
2157       /* C quad */
2158       coneNew[0] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2159       orntNew[0] = ornt[1];
2160       coneNew[1] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2161       orntNew[1] = ornt[2];
2162       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
2163       orntNew[2] = 0;
2164       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
2165       orntNew[3] = -2;
2166       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2167       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2168 #if 1
2169       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
2170       for (p = 0; p < 4; ++p) {
2171         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2172       }
2173 #endif
2174     }
2175     /*
2176      2---------1---------3
2177      |         |         |
2178      |    D    1    C    |
2179      |         |         |
2180      2----2----0----3----3
2181      |         |         |
2182      |    A    0    B    |
2183      |         |         |
2184      0---------0---------1
2185      */
2186     /* Parent cells are input as prisms but children are quads, since the mesh is no longer hybrid */
2187     for (c = cMax; c < cEnd; ++c) {
2188       const PetscInt  newp  = cStartNew + (cMax - cStart)*3 + (c - cMax)*4;
2189       const PetscInt  newpt = (cMax - cStart)*3 + (c - cMax)*4;
2190       const PetscInt *cone, *ornt;
2191       PetscInt        coneNew[4], orntNew[4];
2192 
2193       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2194       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2195       /* A quad */
2196       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2197       orntNew[0] = ornt[0];
2198       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + newpt + 0;
2199       orntNew[1] = 0;
2200       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + newpt + 2;
2201       orntNew[2] = -2;
2202       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2203       orntNew[3] = ornt[2] < 0 ? 0 : -2;
2204       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2205       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2206 #if 1
2207       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
2208       for (p = 0; p < 4; ++p) {
2209         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2210       }
2211 #endif
2212       /* B quad */
2213       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2214       orntNew[0] = ornt[0];
2215       coneNew[1] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
2216       orntNew[1] = ornt[3];
2217       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + newpt + 3;
2218       orntNew[2] = 0;
2219       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + newpt + 0;
2220       orntNew[3] = -2;
2221       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2222       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2223 #if 1
2224       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
2225       for (p = 0; p < 4; ++p) {
2226         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2227       }
2228 #endif
2229       /* C quad */
2230       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + newpt + 3;
2231       orntNew[0] = -2;
2232       coneNew[1] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
2233       orntNew[1] = ornt[3];
2234       coneNew[2] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2235       orntNew[2] = ornt[1] < 0 ? 0 : -2;
2236       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + newpt + 1;
2237       orntNew[3] = 0;
2238       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2239       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2240 #if 1
2241       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
2242       for (p = 0; p < 4; ++p) {
2243         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2244       }
2245 #endif
2246       /* D quad */
2247       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + newpt + 2;
2248       orntNew[0] = 0;
2249       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + newpt + 1;
2250       orntNew[1] = -2;
2251       coneNew[2] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2252       orntNew[2] = ornt[1] < 0 ? 0 : -2;
2253       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2254       orntNew[3] = ornt[2] < 0 ? 0 : -2;
2255       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2256       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2257 #if 1
2258       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
2259       for (p = 0; p < 4; ++p) {
2260         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2261       }
2262 #endif
2263     }
2264     /* Split faces have 2 vertices and the same cells as the parent */
2265     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2266     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2267     for (f = fStart; f < fEnd; ++f) {
2268       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
2269 
2270       for (r = 0; r < 2; ++r) {
2271         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2272         const PetscInt *cone, *ornt, *support;
2273         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2274 
2275         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2276         coneNew[0]       = vStartNew + (cone[0] - vStart);
2277         coneNew[1]       = vStartNew + (cone[1] - vStart);
2278         coneNew[(r+1)%2] = newv;
2279         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2280 #if 1
2281         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2282         for (p = 0; p < 2; ++p) {
2283           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2284         }
2285 #endif
2286         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2287         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2288         for (s = 0; s < supportSize; ++s) {
2289           const PetscInt p2q[4][2] = { {0, 1},
2290                                        {3, 2},
2291                                        {0, 3},
2292                                        {1, 2} };
2293 
2294           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2295           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2296           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2297           for (c = 0; c < coneSize; ++c) {
2298             if (cone[c] == f) break;
2299           }
2300           if (coneSize == 3)      supportRef[s] = cStartNew + (support[s] - cStart)*3 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
2301           else if (coneSize == 4) supportRef[s] = cStartNew + (cMax - cStart)*3 + (support[s] - cMax)*4 + (ornt[c] < 0 ? p2q[c][(r+1)%2] : p2q[c][r]);
2302           else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected cone size %D", coneSize);
2303         }
2304         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2305 #if 1
2306         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2307         for (p = 0; p < supportSize; ++p) {
2308           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
2309         }
2310 #endif
2311       }
2312     }
2313     /* Interior faces have 2 vertices and 2 cells */
2314     for (c = cStart; c < cMax; ++c) {
2315       const PetscInt *cone;
2316 
2317       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2318       for (r = 0; r < 3; ++r) {
2319         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
2320         PetscInt       coneNew[2];
2321         PetscInt       supportNew[2];
2322 
2323         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2324         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
2325         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2326 #if 1
2327         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2328         for (p = 0; p < 2; ++p) {
2329           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2330         }
2331 #endif
2332         supportNew[0] = (c - cStart)*3 + r%3;
2333         supportNew[1] = (c - cStart)*3 + (r+1)%3;
2334         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2335 #if 1
2336         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2337         for (p = 0; p < 2; ++p) {
2338           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
2339         }
2340 #endif
2341       }
2342     }
2343     /* Hybrid interior faces have 2 vertices and 2 cells */
2344     for (c = cMax; c < cEnd; ++c) {
2345       const PetscInt *cone;
2346       PetscInt        coneNew[2], supportNew[2];
2347 
2348       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2349       for (r = 0; r < 4; ++r) {
2350         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + r;
2351 
2352         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2353         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (cMax - cStart) + (c - cMax);
2354 	ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2355 #if 1
2356         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2357         for (p = 0; p < 2; ++p) {
2358           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2359         }
2360 #endif
2361         if (r==0) {
2362           supportNew[0] = (cMax - cStart)*3 + (c - cMax)*4 + 0;
2363           supportNew[1] = (cMax - cStart)*3 + (c - cMax)*4 + 1;
2364         } else if (r==1) {
2365           supportNew[0] = (cMax - cStart)*3 + (c - cMax)*4 + 2;
2366           supportNew[1] = (cMax - cStart)*3 + (c - cMax)*4 + 3;
2367         } else if (r==2) {
2368           supportNew[0] = (cMax - cStart)*3 + (c - cMax)*4 + 0;
2369           supportNew[1] = (cMax - cStart)*3 + (c - cMax)*4 + 3;
2370         } else {
2371           supportNew[0] = (cMax - cStart)*3 + (c - cMax)*4 + 1;
2372           supportNew[1] = (cMax - cStart)*3 + (c - cMax)*4 + 2;
2373         }
2374         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2375 #if 1
2376         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2377         for (p = 0; p < 2; ++p) {
2378           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
2379         }
2380 #endif
2381       }
2382     }
2383     /* Old vertices have identical supports */
2384     for (v = vStart; v < vEnd; ++v) {
2385       const PetscInt  newp = vStartNew + (v - vStart);
2386       const PetscInt *support, *cone;
2387       PetscInt        size, s;
2388 
2389       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2390       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2391       for (s = 0; s < size; ++s) {
2392         PetscInt r = 0;
2393 
2394         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2395         if (cone[1] == v) r = 1;
2396         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2397       }
2398       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2399 #if 1
2400       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2401       for (p = 0; p < size; ++p) {
2402         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
2403       }
2404 #endif
2405     }
2406     /* Split-face vertices have cells + 2 supports */
2407     for (f = fStart; f < fEnd; ++f) {
2408       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2409       const PetscInt *cone, *support;
2410       PetscInt        size, s;
2411 
2412       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2413       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2414       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2415       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2416       for (s = 0; s < size; ++s) {
2417         PetscInt r = 0, coneSize;
2418 
2419         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2420         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2421         if (coneSize == 3) {
2422           if      (cone[1] == f) r = 1;
2423           else if (cone[2] == f) r = 2;
2424           supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
2425         } else if (coneSize == 4) {
2426           if      (cone[1] == f) r = 1;
2427           else if (cone[2] == f) r = 2;
2428           else if (cone[3] == f) r = 3;
2429           supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (support[s] - cMax)*4 + r;
2430         } else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected cone size %D", coneSize);
2431       }
2432       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2433 #if 1
2434       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2435       for (p = 0; p < 2+size; ++p) {
2436         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
2437       }
2438 #endif
2439     }
2440     /* Interior vertices have 3 supports */
2441     for (c = cStart; c < cMax; ++c) {
2442       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
2443 
2444       supportRef[0] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 0;
2445       supportRef[1] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 1;
2446       supportRef[2] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 2;
2447       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2448     }
2449     /* Hybrid interior vertices have 4 supports */
2450     for (c = cMax; c < cEnd; ++c) {
2451       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
2452 
2453       supportRef[0] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + 0;
2454       supportRef[1] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + 1;
2455       supportRef[2] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + 2;
2456       supportRef[3] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + 3;
2457       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2458     }
2459     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2460     break;
2461   case REFINER_HEX_2D:
2462     /*
2463      3---------2---------2
2464      |         |         |
2465      |    D    2    C    |
2466      |         |         |
2467      3----3----0----1----1
2468      |         |         |
2469      |    A    0    B    |
2470      |         |         |
2471      0---------0---------1
2472      */
2473     /* All cells have 4 faces */
2474     for (c = cStart; c < cEnd; ++c) {
2475       const PetscInt  newp = (c - cStart)*4;
2476       const PetscInt *cone, *ornt;
2477       PetscInt        coneNew[4], orntNew[4];
2478 
2479       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2480       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2481       /* A quad */
2482       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2483       orntNew[0] = ornt[0];
2484       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
2485       orntNew[1] = 0;
2486       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
2487       orntNew[2] = -2;
2488       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
2489       orntNew[3] = ornt[3];
2490       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2491       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2492 #if 1
2493       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
2494       for (p = 0; p < 4; ++p) {
2495         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2496       }
2497 #endif
2498       /* B quad */
2499       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2500       orntNew[0] = ornt[0];
2501       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2502       orntNew[1] = ornt[1];
2503       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
2504       orntNew[2] = -2;
2505       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
2506       orntNew[3] = -2;
2507       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2508       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2509 #if 1
2510       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
2511       for (p = 0; p < 4; ++p) {
2512         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2513       }
2514 #endif
2515       /* C quad */
2516       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
2517       orntNew[0] = 0;
2518       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2519       orntNew[1] = ornt[1];
2520       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2521       orntNew[2] = ornt[2];
2522       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
2523       orntNew[3] = -2;
2524       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2525       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2526 #if 1
2527       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
2528       for (p = 0; p < 4; ++p) {
2529         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2530       }
2531 #endif
2532       /* D quad */
2533       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
2534       orntNew[0] = 0;
2535       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
2536       orntNew[1] = 0;
2537       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2538       orntNew[2] = ornt[2];
2539       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
2540       orntNew[3] = ornt[3];
2541       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2542       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2543 #if 1
2544       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
2545       for (p = 0; p < 4; ++p) {
2546         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2547       }
2548 #endif
2549     }
2550     /* Split faces have 2 vertices and the same cells as the parent */
2551     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2552     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2553     for (f = fStart; f < fEnd; ++f) {
2554       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
2555 
2556       for (r = 0; r < 2; ++r) {
2557         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2558         const PetscInt *cone, *ornt, *support;
2559         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2560 
2561         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2562         coneNew[0]       = vStartNew + (cone[0] - vStart);
2563         coneNew[1]       = vStartNew + (cone[1] - vStart);
2564         coneNew[(r+1)%2] = newv;
2565         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2566 #if 1
2567         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2568         for (p = 0; p < 2; ++p) {
2569           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2570         }
2571 #endif
2572         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2573         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2574         for (s = 0; s < supportSize; ++s) {
2575           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2576           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2577           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2578           for (c = 0; c < coneSize; ++c) {
2579             if (cone[c] == f) break;
2580           }
2581           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
2582         }
2583         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2584 #if 1
2585         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2586         for (p = 0; p < supportSize; ++p) {
2587           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
2588         }
2589 #endif
2590       }
2591     }
2592     /* Interior faces have 2 vertices and 2 cells */
2593     for (c = cStart; c < cEnd; ++c) {
2594       const PetscInt *cone;
2595       PetscInt        coneNew[2], supportNew[2];
2596 
2597       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2598       for (r = 0; r < 4; ++r) {
2599         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
2600 
2601 	if (r==1 || r==2) {
2602           coneNew[0] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
2603           coneNew[1] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2604 	} else {
2605           coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2606           coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
2607 	}
2608 	ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2609 #if 1
2610         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2611         for (p = 0; p < 2; ++p) {
2612           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2613         }
2614 #endif
2615         supportNew[0] = (c - cStart)*4 + r;
2616         supportNew[1] = (c - cStart)*4 + (r+1)%4;
2617         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2618 #if 1
2619         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2620         for (p = 0; p < 2; ++p) {
2621           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
2622         }
2623 #endif
2624       }
2625     }
2626     /* Old vertices have identical supports */
2627     for (v = vStart; v < vEnd; ++v) {
2628       const PetscInt  newp = vStartNew + (v - vStart);
2629       const PetscInt *support, *cone;
2630       PetscInt        size, s;
2631 
2632       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2633       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2634       for (s = 0; s < size; ++s) {
2635         PetscInt r = 0;
2636 
2637         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2638         if (cone[1] == v) r = 1;
2639         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2640       }
2641       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2642 #if 1
2643       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2644       for (p = 0; p < size; ++p) {
2645         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
2646       }
2647 #endif
2648     }
2649     /* Face vertices have 2 + cells supports */
2650     for (f = fStart; f < fEnd; ++f) {
2651       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2652       const PetscInt *cone, *support;
2653       PetscInt        size, s;
2654 
2655       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2656       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2657       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2658       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2659       for (s = 0; s < size; ++s) {
2660         PetscInt r = 0;
2661 
2662         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2663         if      (cone[1] == f) r = 1;
2664         else if (cone[2] == f) r = 2;
2665         else if (cone[3] == f) r = 3;
2666         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
2667       }
2668       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2669 #if 1
2670       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2671       for (p = 0; p < 2+size; ++p) {
2672         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
2673       }
2674 #endif
2675     }
2676     /* Cell vertices have 4 supports */
2677     for (c = cStart; c < cEnd; ++c) {
2678       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
2679       PetscInt       supportNew[4];
2680 
2681       for (r = 0; r < 4; ++r) {
2682         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
2683       }
2684       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2685     }
2686     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2687     break;
2688   case REFINER_HYBRID_SIMPLEX_2D:
2689     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
2690     cMax = PetscMin(cEnd, cMax);
2691     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
2692     fMax = PetscMin(fEnd, fMax);
2693     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);CHKERRQ(ierr);
2694     /* Interior cells have 3 faces */
2695     for (c = cStart; c < cMax; ++c) {
2696       const PetscInt  newp = cStartNew + (c - cStart)*4;
2697       const PetscInt *cone, *ornt;
2698       PetscInt        coneNew[3], orntNew[3];
2699 
2700       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2701       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2702       /* A triangle */
2703       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2704       orntNew[0] = ornt[0];
2705       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
2706       orntNew[1] = -2;
2707       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2708       orntNew[2] = ornt[2];
2709       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2710       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2711 #if 1
2712       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+0, cStartNew, cMaxNew);
2713       for (p = 0; p < 3; ++p) {
2714         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2715       }
2716 #endif
2717       /* B triangle */
2718       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2719       orntNew[0] = ornt[0];
2720       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2721       orntNew[1] = ornt[1];
2722       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
2723       orntNew[2] = -2;
2724       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2725       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2726 #if 1
2727       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+1, cStartNew, cMaxNew);
2728       for (p = 0; p < 3; ++p) {
2729         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2730       }
2731 #endif
2732       /* C triangle */
2733       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
2734       orntNew[0] = -2;
2735       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2736       orntNew[1] = ornt[1];
2737       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2738       orntNew[2] = ornt[2];
2739       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2740       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2741 #if 1
2742       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+2, cStartNew, cMaxNew);
2743       for (p = 0; p < 3; ++p) {
2744         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2745       }
2746 #endif
2747       /* D triangle */
2748       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
2749       orntNew[0] = 0;
2750       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
2751       orntNew[1] = 0;
2752       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
2753       orntNew[2] = 0;
2754       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2755       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2756 #if 1
2757       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+3, cStartNew, cMaxNew);
2758       for (p = 0; p < 3; ++p) {
2759         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2760       }
2761 #endif
2762     }
2763     /*
2764      2----3----3
2765      |         |
2766      |    B    |
2767      |         |
2768      0----4--- 1
2769      |         |
2770      |    A    |
2771      |         |
2772      0----2----1
2773      */
2774     /* Hybrid cells have 4 faces */
2775     for (c = cMax; c < cEnd; ++c) {
2776       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
2777       const PetscInt *cone, *ornt;
2778       PetscInt        coneNew[4], orntNew[4], r;
2779 
2780       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2781       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2782       r    = (ornt[0] < 0 ? 1 : 0);
2783       /* A quad */
2784       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + r;
2785       orntNew[0]   = ornt[0];
2786       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + r;
2787       orntNew[1]   = ornt[1];
2788       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2+r] - fMax);
2789       orntNew[2+r] = 0;
2790       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
2791       orntNew[3-r] = 0;
2792       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2793       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2794 #if 1
2795       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
2796       for (p = 0; p < 4; ++p) {
2797         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2798       }
2799 #endif
2800       /* B quad */
2801       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + 1-r;
2802       orntNew[0]   = ornt[0];
2803       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + 1-r;
2804       orntNew[1]   = ornt[1];
2805       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
2806       orntNew[2+r] = 0;
2807       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3-r] - fMax);
2808       orntNew[3-r] = 0;
2809       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2810       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2811 #if 1
2812       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
2813       for (p = 0; p < 4; ++p) {
2814         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2815       }
2816 #endif
2817     }
2818     /* Interior split faces have 2 vertices and the same cells as the parent */
2819     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2820     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2821     for (f = fStart; f < fMax; ++f) {
2822       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
2823 
2824       for (r = 0; r < 2; ++r) {
2825         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2826         const PetscInt *cone, *ornt, *support;
2827         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2828 
2829         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2830         coneNew[0]       = vStartNew + (cone[0] - vStart);
2831         coneNew[1]       = vStartNew + (cone[1] - vStart);
2832         coneNew[(r+1)%2] = newv;
2833         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2834 #if 1
2835         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2836         for (p = 0; p < 2; ++p) {
2837           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2838         }
2839 #endif
2840         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2841         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2842         for (s = 0; s < supportSize; ++s) {
2843           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2844           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2845           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2846           for (c = 0; c < coneSize; ++c) if (cone[c] == f) break;
2847           if (support[s] >= cMax) {
2848             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[c] < 0 ? 1-r : r);
2849           } else {
2850             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
2851           }
2852         }
2853         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2854 #if 1
2855         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2856         for (p = 0; p < supportSize; ++p) {
2857           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
2858         }
2859 #endif
2860       }
2861     }
2862     /* Interior cell faces have 2 vertices and 2 cells */
2863     for (c = cStart; c < cMax; ++c) {
2864       const PetscInt *cone;
2865 
2866       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2867       for (r = 0; r < 3; ++r) {
2868         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
2869         PetscInt       coneNew[2];
2870         PetscInt       supportNew[2];
2871 
2872         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
2873         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
2874         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2875 #if 1
2876         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2877         for (p = 0; p < 2; ++p) {
2878           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2879         }
2880 #endif
2881         supportNew[0] = (c - cStart)*4 + (r+1)%3;
2882         supportNew[1] = (c - cStart)*4 + 3;
2883         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2884 #if 1
2885         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2886         for (p = 0; p < 2; ++p) {
2887           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
2888         }
2889 #endif
2890       }
2891     }
2892     /* Interior hybrid faces have 2 vertices and the same cells */
2893     for (f = fMax; f < fEnd; ++f) {
2894       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
2895       const PetscInt *cone, *ornt;
2896       const PetscInt *support;
2897       PetscInt        coneNew[2];
2898       PetscInt        supportNew[2];
2899       PetscInt        size, s, r;
2900 
2901       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2902       coneNew[0] = vStartNew + (cone[0] - vStart);
2903       coneNew[1] = vStartNew + (cone[1] - vStart);
2904       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2905 #if 1
2906       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2907       for (p = 0; p < 2; ++p) {
2908         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2909       }
2910 #endif
2911       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2912       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2913       for (s = 0; s < size; ++s) {
2914         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2915         ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2916         for (r = 0; r < 2; ++r) {
2917           if (cone[r+2] == f) break;
2918         }
2919         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[0] < 0 ? 1-r : r);
2920       }
2921       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2922 #if 1
2923       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2924       for (p = 0; p < size; ++p) {
2925         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
2926       }
2927 #endif
2928     }
2929     /* Cell hybrid faces have 2 vertices and 2 cells */
2930     for (c = cMax; c < cEnd; ++c) {
2931       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
2932       const PetscInt *cone;
2933       PetscInt        coneNew[2];
2934       PetscInt        supportNew[2];
2935 
2936       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2937       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
2938       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
2939       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2940 #if 1
2941       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2942       for (p = 0; p < 2; ++p) {
2943         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2944       }
2945 #endif
2946       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
2947       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
2948       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2949 #if 1
2950       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2951       for (p = 0; p < 2; ++p) {
2952         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
2953       }
2954 #endif
2955     }
2956     /* Old vertices have identical supports */
2957     for (v = vStart; v < vEnd; ++v) {
2958       const PetscInt  newp = vStartNew + (v - vStart);
2959       const PetscInt *support, *cone;
2960       PetscInt        size, s;
2961 
2962       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2963       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2964       for (s = 0; s < size; ++s) {
2965         if (support[s] >= fMax) {
2966           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
2967         } else {
2968           PetscInt r = 0;
2969 
2970           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2971           if (cone[1] == v) r = 1;
2972           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2973         }
2974       }
2975       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2976 #if 1
2977       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2978       for (p = 0; p < size; ++p) {
2979         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
2980       }
2981 #endif
2982     }
2983     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
2984     for (f = fStart; f < fMax; ++f) {
2985       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2986       const PetscInt *cone, *support;
2987       PetscInt        size, newSize = 2, s;
2988 
2989       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2990       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2991       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2992       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2993       for (s = 0; s < size; ++s) {
2994         PetscInt r = 0;
2995 
2996         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2997         if (support[s] >= cMax) {
2998           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
2999 
3000           newSize += 1;
3001         } else {
3002           if      (cone[1] == f) r = 1;
3003           else if (cone[2] == f) r = 2;
3004           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
3005           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
3006 
3007           newSize += 2;
3008         }
3009       }
3010       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3011 #if 1
3012       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3013       for (p = 0; p < newSize; ++p) {
3014         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
3015       }
3016 #endif
3017     }
3018     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3019     break;
3020   case REFINER_HYBRID_HEX_2D:
3021     /* Hybrid Hex 2D */
3022     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
3023     cMax = PetscMin(cEnd, cMax);
3024     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
3025     fMax = PetscMin(fEnd, fMax);
3026     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);CHKERRQ(ierr);
3027     /* Interior cells have 4 faces */
3028     for (c = cStart; c < cMax; ++c) {
3029       const PetscInt  newp = cStartNew + (c - cStart)*4;
3030       const PetscInt *cone, *ornt;
3031       PetscInt        coneNew[4], orntNew[4];
3032 
3033       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3034       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3035       /* A quad */
3036       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
3037       orntNew[0] = ornt[0];
3038       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
3039       orntNew[1] = 0;
3040       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
3041       orntNew[2] = -2;
3042       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
3043       orntNew[3] = ornt[3];
3044       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3045       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3046 #if 1
3047       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+0, cStartNew, cMaxNew);
3048       for (p = 0; p < 4; ++p) {
3049         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3050       }
3051 #endif
3052       /* B quad */
3053       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
3054       orntNew[0] = ornt[0];
3055       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
3056       orntNew[1] = ornt[1];
3057       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
3058       orntNew[2] = 0;
3059       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
3060       orntNew[3] = -2;
3061       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3062       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3063 #if 1
3064       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+1, cStartNew, cMaxNew);
3065       for (p = 0; p < 4; ++p) {
3066         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3067       }
3068 #endif
3069       /* C quad */
3070       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
3071       orntNew[0] = -2;
3072       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
3073       orntNew[1] = ornt[1];
3074       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
3075       orntNew[2] = ornt[2];
3076       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
3077       orntNew[3] = 0;
3078       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3079       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3080 #if 1
3081       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+2, cStartNew, cMaxNew);
3082       for (p = 0; p < 4; ++p) {
3083         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3084       }
3085 #endif
3086       /* D quad */
3087       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
3088       orntNew[0] = 0;
3089       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
3090       orntNew[1] = -2;
3091       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
3092       orntNew[2] = ornt[2];
3093       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
3094       orntNew[3] = ornt[3];
3095       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3096       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3097 #if 1
3098       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+3, cStartNew, cMaxNew);
3099       for (p = 0; p < 4; ++p) {
3100         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3101       }
3102 #endif
3103     }
3104     /*
3105      2----3----3
3106      |         |
3107      |    B    |
3108      |         |
3109      0----4--- 1
3110      |         |
3111      |    A    |
3112      |         |
3113      0----2----1
3114      */
3115     /* Hybrid cells have 4 faces */
3116     for (c = cMax; c < cEnd; ++c) {
3117       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
3118       const PetscInt *cone, *ornt;
3119       PetscInt        coneNew[4], orntNew[4];
3120 
3121       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3122       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3123       /* A quad */
3124       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
3125       orntNew[0] = ornt[0];
3126       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
3127       orntNew[1] = ornt[1];
3128       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[2] - fMax);
3129       orntNew[2] = 0;
3130       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
3131       orntNew[3] = 0;
3132       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3133       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3134 #if 1
3135       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
3136       for (p = 0; p < 4; ++p) {
3137         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
3138       }
3139 #endif
3140       /* B quad */
3141       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
3142       orntNew[0] = ornt[0];
3143       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
3144       orntNew[1] = ornt[1];
3145       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
3146       orntNew[2] = 0;
3147       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[3] - fMax);
3148       orntNew[3] = 0;
3149       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3150       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3151 #if 1
3152       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
3153       for (p = 0; p < 4; ++p) {
3154         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
3155       }
3156 #endif
3157     }
3158     /* Interior split faces have 2 vertices and the same cells as the parent */
3159     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3160     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
3161     for (f = fStart; f < fMax; ++f) {
3162       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
3163 
3164       for (r = 0; r < 2; ++r) {
3165         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
3166         const PetscInt *cone, *ornt, *support;
3167         PetscInt        coneNew[2], coneSize, c, supportSize, s;
3168 
3169         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3170         coneNew[0]       = vStartNew + (cone[0] - vStart);
3171         coneNew[1]       = vStartNew + (cone[1] - vStart);
3172         coneNew[(r+1)%2] = newv;
3173         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3174 #if 1
3175         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3176         for (p = 0; p < 2; ++p) {
3177           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
3178         }
3179 #endif
3180         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3181         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3182         for (s = 0; s < supportSize; ++s) {
3183           if (support[s] >= cMax) {
3184             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
3185           } else {
3186             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3187             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3188             ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3189             for (c = 0; c < coneSize; ++c) {
3190               if (cone[c] == f) break;
3191             }
3192             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
3193           }
3194         }
3195         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3196 #if 1
3197         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3198         for (p = 0; p < supportSize; ++p) {
3199           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
3200         }
3201 #endif
3202       }
3203     }
3204     /* Interior cell faces have 2 vertices and 2 cells */
3205     for (c = cStart; c < cMax; ++c) {
3206       const PetscInt *cone;
3207 
3208       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3209       for (r = 0; r < 4; ++r) {
3210         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
3211         PetscInt       coneNew[2], supportNew[2];
3212 
3213         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
3214         coneNew[1] = vStartNew + (vEnd - vStart) + (fMax    - fStart) + (c - cStart);
3215         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3216 #if 1
3217         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3218         for (p = 0; p < 2; ++p) {
3219           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
3220         }
3221 #endif
3222         supportNew[0] = (c - cStart)*4 + r;
3223         supportNew[1] = (c - cStart)*4 + (r+1)%4;
3224         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3225 #if 1
3226         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3227         for (p = 0; p < 2; ++p) {
3228           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
3229         }
3230 #endif
3231       }
3232     }
3233     /* Hybrid faces have 2 vertices and the same cells */
3234     for (f = fMax; f < fEnd; ++f) {
3235       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
3236       const PetscInt *cone, *support;
3237       PetscInt        coneNew[2], supportNew[2];
3238       PetscInt        size, s, r;
3239 
3240       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3241       coneNew[0] = vStartNew + (cone[0] - vStart);
3242       coneNew[1] = vStartNew + (cone[1] - vStart);
3243       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3244 #if 1
3245       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3246       for (p = 0; p < 2; ++p) {
3247         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
3248       }
3249 #endif
3250       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3251       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3252       for (s = 0; s < size; ++s) {
3253         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3254         for (r = 0; r < 2; ++r) {
3255           if (cone[r+2] == f) break;
3256         }
3257         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
3258       }
3259       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3260 #if 1
3261       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3262       for (p = 0; p < size; ++p) {
3263         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
3264       }
3265 #endif
3266     }
3267     /* Cell hybrid faces have 2 vertices and 2 cells */
3268     for (c = cMax; c < cEnd; ++c) {
3269       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
3270       const PetscInt *cone;
3271       PetscInt        coneNew[2], supportNew[2];
3272 
3273       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3274       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
3275       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
3276       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3277 #if 1
3278       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3279       for (p = 0; p < 2; ++p) {
3280         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
3281       }
3282 #endif
3283       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
3284       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
3285       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3286 #if 1
3287       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3288       for (p = 0; p < 2; ++p) {
3289         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
3290       }
3291 #endif
3292     }
3293     /* Old vertices have identical supports */
3294     for (v = vStart; v < vEnd; ++v) {
3295       const PetscInt  newp = vStartNew + (v - vStart);
3296       const PetscInt *support, *cone;
3297       PetscInt        size, s;
3298 
3299       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
3300       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
3301       for (s = 0; s < size; ++s) {
3302         if (support[s] >= fMax) {
3303           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (support[s] - fMax);
3304         } else {
3305           PetscInt r = 0;
3306 
3307           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3308           if (cone[1] == v) r = 1;
3309           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
3310         }
3311       }
3312       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3313 #if 1
3314       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3315       for (p = 0; p < size; ++p) {
3316         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
3317       }
3318 #endif
3319     }
3320     /* Face vertices have 2 + cells supports */
3321     for (f = fStart; f < fMax; ++f) {
3322       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
3323       const PetscInt *cone, *support;
3324       PetscInt        size, s;
3325 
3326       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3327       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3328       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
3329       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
3330       for (s = 0; s < size; ++s) {
3331         PetscInt r = 0;
3332 
3333         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3334         if (support[s] >= cMax) {
3335           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (support[s] - cMax);
3336         } else {
3337           if      (cone[1] == f) r = 1;
3338           else if (cone[2] == f) r = 2;
3339           else if (cone[3] == f) r = 3;
3340           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*4 + r;
3341         }
3342       }
3343       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3344 #if 1
3345       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3346       for (p = 0; p < 2+size; ++p) {
3347         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
3348       }
3349 #endif
3350     }
3351     /* Cell vertices have 4 supports */
3352     for (c = cStart; c < cMax; ++c) {
3353       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
3354       PetscInt       supportNew[4];
3355 
3356       for (r = 0; r < 4; ++r) {
3357         supportNew[r] = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
3358       }
3359       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3360     }
3361     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3362     break;
3363   case REFINER_SIMPLEX_3D:
3364     /* All cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
3365     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
3366     for (c = cStart; c < cEnd; ++c) {
3367       const PetscInt  newp = cStartNew + (c - cStart)*8;
3368       const PetscInt *cone, *ornt;
3369       PetscInt        coneNew[4], orntNew[4];
3370 
3371       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3372       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3373       /* A tetrahedron: {0, a, c, d} */
3374       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
3375       orntNew[0] = ornt[0];
3376       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
3377       orntNew[1] = ornt[1];
3378       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
3379       orntNew[2] = ornt[2];
3380       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
3381       orntNew[3] = 0;
3382       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3383       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3384 #if 1
3385       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
3386       for (p = 0; p < 4; ++p) {
3387         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
3388       }
3389 #endif
3390       /* B tetrahedron: {a, 1, b, e} */
3391       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
3392       orntNew[0] = ornt[0];
3393       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
3394       orntNew[1] = ornt[1];
3395       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
3396       orntNew[2] = 0;
3397       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
3398       orntNew[3] = ornt[3];
3399       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3400       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3401 #if 1
3402       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
3403       for (p = 0; p < 4; ++p) {
3404         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
3405       }
3406 #endif
3407       /* C tetrahedron: {c, b, 2, f} */
3408       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
3409       orntNew[0] = ornt[0];
3410       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
3411       orntNew[1] = 0;
3412       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
3413       orntNew[2] = ornt[2];
3414       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
3415       orntNew[3] = ornt[3];
3416       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3417       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3418 #if 1
3419       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
3420       for (p = 0; p < 4; ++p) {
3421         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
3422       }
3423 #endif
3424       /* D tetrahedron: {d, e, f, 3} */
3425       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
3426       orntNew[0] = 0;
3427       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
3428       orntNew[1] = ornt[1];
3429       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
3430       orntNew[2] = ornt[2];
3431       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
3432       orntNew[3] = ornt[3];
3433       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3434       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3435 #if 1
3436       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
3437       for (p = 0; p < 4; ++p) {
3438         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
3439       }
3440 #endif
3441       /* A' tetrahedron: {c, d, a, f} */
3442       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
3443       orntNew[0] = -3;
3444       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
3445       orntNew[1] = ornt[2] < 0 ? -(GetTriMidEdge_Static(ornt[2], 0)+1) : GetTriMidEdge_Static(ornt[2], 0);
3446       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
3447       orntNew[2] = 0;
3448       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
3449       orntNew[3] = 2;
3450       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
3451       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
3452 #if 1
3453       if ((newp+4 < cStartNew) || (newp+4 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+4, cStartNew, cEndNew);
3454       for (p = 0; p < 4; ++p) {
3455         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
3456       }
3457 #endif
3458       /* B' tetrahedron: {e, b, a, f} */
3459       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
3460       orntNew[0] = -2;
3461       coneNew[1] = fStartNew + (cone[3] - fStart)*4 + 3;
3462       orntNew[1] = ornt[3] < 0 ? -(GetTriMidEdge_Static(ornt[3], 1)+1) : GetTriMidEdge_Static(ornt[3], 1);
3463       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
3464       orntNew[2] = 0;
3465       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
3466       orntNew[3] = 0;
3467       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
3468       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
3469 #if 1
3470       if ((newp+5 < cStartNew) || (newp+5 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+5, cStartNew, cEndNew);
3471       for (p = 0; p < 4; ++p) {
3472         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
3473       }
3474 #endif
3475       /* C' tetrahedron: {f, a, c, b} */
3476       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
3477       orntNew[0] = -2;
3478       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
3479       orntNew[1] = -2;
3480       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
3481       orntNew[2] = -1;
3482       coneNew[3] = fStartNew + (cone[0] - fStart)*4 + 3;
3483       orntNew[3] = ornt[0] < 0 ? -(GetTriMidEdge_Static(ornt[0], 2)+1) : GetTriMidEdge_Static(ornt[0], 2);
3484       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
3485       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
3486 #if 1
3487       if ((newp+6 < cStartNew) || (newp+6 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+6, cStartNew, cEndNew);
3488       for (p = 0; p < 4; ++p) {
3489         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
3490       }
3491 #endif
3492       /* D' tetrahedron: {f, a, e, d} */
3493       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
3494       orntNew[0] = -2;
3495       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
3496       orntNew[1] = -1;
3497       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
3498       orntNew[2] = -2;
3499       coneNew[3] = fStartNew + (cone[1] - fStart)*4 + 3;
3500       orntNew[3] = ornt[1] < 0 ? -(GetTriMidEdge_Static(ornt[1], 1)+1) : GetTriMidEdge_Static(ornt[1], 1);
3501       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
3502       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
3503 #if 1
3504       if ((newp+7 < cStartNew) || (newp+7 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+7, cStartNew, cEndNew);
3505       for (p = 0; p < 4; ++p) {
3506         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
3507       }
3508 #endif
3509     }
3510     /* Split faces have 3 edges and the same cells as the parent */
3511     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3512     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
3513     for (f = fStart; f < fEnd; ++f) {
3514       const PetscInt  newp = fStartNew + (f - fStart)*4;
3515       const PetscInt *cone, *ornt, *support;
3516       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
3517 
3518       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3519       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3520       /* A triangle */
3521       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
3522       orntNew[0] = ornt[0];
3523       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
3524       orntNew[1] = -2;
3525       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
3526       orntNew[2] = ornt[2];
3527       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3528       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3529 #if 1
3530       if ((newp+0 < fStartNew) || (newp+0 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+0, fStartNew, fEndNew);
3531       for (p = 0; p < 3; ++p) {
3532         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3533       }
3534 #endif
3535       /* B triangle */
3536       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
3537       orntNew[0] = ornt[0];
3538       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
3539       orntNew[1] = ornt[1];
3540       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
3541       orntNew[2] = -2;
3542       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3543       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3544 #if 1
3545       if ((newp+1 < fStartNew) || (newp+1 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+1, fStartNew, fEndNew);
3546       for (p = 0; p < 3; ++p) {
3547         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3548       }
3549 #endif
3550       /* C triangle */
3551       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
3552       orntNew[0] = -2;
3553       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
3554       orntNew[1] = ornt[1];
3555       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
3556       orntNew[2] = ornt[2];
3557       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3558       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3559 #if 1
3560       if ((newp+2 < fStartNew) || (newp+2 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+2, fStartNew, fEndNew);
3561       for (p = 0; p < 3; ++p) {
3562         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3563       }
3564 #endif
3565       /* D triangle */
3566       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
3567       orntNew[0] = 0;
3568       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
3569       orntNew[1] = 0;
3570       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
3571       orntNew[2] = 0;
3572       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3573       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3574 #if 1
3575       if ((newp+3 < fStartNew) || (newp+3 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+3, fStartNew, fEndNew);
3576       for (p = 0; p < 3; ++p) {
3577         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3578       }
3579 #endif
3580       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3581       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3582       for (r = 0; r < 4; ++r) {
3583         for (s = 0; s < supportSize; ++s) {
3584           PetscInt subf;
3585           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3586           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3587           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3588           for (c = 0; c < coneSize; ++c) {
3589             if (cone[c] == f) break;
3590           }
3591           subf = GetTriSubfaceInverse_Static(ornt[c], r);
3592           supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
3593         }
3594         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
3595 #if 1
3596         if ((newp+r < fStartNew) || (newp+r >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+r, fStartNew, fEndNew);
3597         for (p = 0; p < supportSize; ++p) {
3598           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
3599         }
3600 #endif
3601       }
3602     }
3603     /* Interior faces have 3 edges and 2 cells */
3604     for (c = cStart; c < cEnd; ++c) {
3605       PetscInt        newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8;
3606       const PetscInt *cone, *ornt;
3607       PetscInt        coneNew[3], orntNew[3];
3608       PetscInt        supportNew[2];
3609 
3610       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3611       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3612       /* Face A: {c, a, d} */
3613       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3614       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3615       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3616       orntNew[1] = ornt[1] < 0 ? -2 : 0;
3617       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 2);
3618       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3619       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3620       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3621 #if 1
3622       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3623       for (p = 0; p < 3; ++p) {
3624         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3625       }
3626 #endif
3627       supportNew[0] = (c - cStart)*8 + 0;
3628       supportNew[1] = (c - cStart)*8 + 0+4;
3629       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3630 #if 1
3631       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3632       for (p = 0; p < 2; ++p) {
3633         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
3634       }
3635 #endif
3636       ++newp;
3637       /* Face B: {a, b, e} */
3638       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3639       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3640       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 0);
3641       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3642       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3643       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3644       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3645       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3646 #if 1
3647       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3648       for (p = 0; p < 3; ++p) {
3649         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3650       }
3651 #endif
3652       supportNew[0] = (c - cStart)*8 + 1;
3653       supportNew[1] = (c - cStart)*8 + 1+4;
3654       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3655 #if 1
3656       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3657       for (p = 0; p < 2; ++p) {
3658         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
3659       }
3660 #endif
3661       ++newp;
3662       /* Face C: {c, f, b} */
3663       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3664       orntNew[0] = ornt[2] < 0 ? -2 : 0;
3665       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3666       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3667       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 1);
3668       orntNew[2] = ornt[0] < 0 ? -2 : 0;
3669       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3670       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3671 #if 1
3672       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3673       for (p = 0; p < 3; ++p) {
3674         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3675       }
3676 #endif
3677       supportNew[0] = (c - cStart)*8 + 2;
3678       supportNew[1] = (c - cStart)*8 + 2+4;
3679       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3680 #if 1
3681       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3682       for (p = 0; p < 2; ++p) {
3683         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
3684       }
3685 #endif
3686       ++newp;
3687       /* Face D: {d, e, f} */
3688       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 0);
3689       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3690       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3691       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3692       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3693       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3694       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3695       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3696 #if 1
3697       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3698       for (p = 0; p < 3; ++p) {
3699         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3700       }
3701 #endif
3702       supportNew[0] = (c - cStart)*8 + 3;
3703       supportNew[1] = (c - cStart)*8 + 3+4;
3704       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3705 #if 1
3706       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3707       for (p = 0; p < 2; ++p) {
3708         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
3709       }
3710 #endif
3711       ++newp;
3712       /* Face E: {d, f, a} */
3713       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3714       orntNew[0] = ornt[2] < 0 ? 0 : -2;
3715       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3716       orntNew[1] = -2;
3717       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3718       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3719       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3720       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3721 #if 1
3722       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3723       for (p = 0; p < 3; ++p) {
3724         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3725       }
3726 #endif
3727       supportNew[0] = (c - cStart)*8 + 0+4;
3728       supportNew[1] = (c - cStart)*8 + 3+4;
3729       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3730 #if 1
3731       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3732       for (p = 0; p < 2; ++p) {
3733         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
3734       }
3735 #endif
3736       ++newp;
3737       /* Face F: {c, a, f} */
3738       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3739       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3740       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3741       orntNew[1] = 0;
3742       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3743       orntNew[2] = ornt[2] < 0 ? 0 : -2;
3744       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3745       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3746 #if 1
3747       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3748       for (p = 0; p < 3; ++p) {
3749         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3750       }
3751 #endif
3752       supportNew[0] = (c - cStart)*8 + 0+4;
3753       supportNew[1] = (c - cStart)*8 + 2+4;
3754       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3755 #if 1
3756       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3757       for (p = 0; p < 2; ++p) {
3758         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
3759       }
3760 #endif
3761       ++newp;
3762       /* Face G: {e, a, f} */
3763       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3764       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3765       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3766       orntNew[1] = 0;
3767       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3768       orntNew[2] = ornt[3] < 0 ? 0 : -2;
3769       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3770       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3771 #if 1
3772       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3773       for (p = 0; p < 3; ++p) {
3774         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3775       }
3776 #endif
3777       supportNew[0] = (c - cStart)*8 + 1+4;
3778       supportNew[1] = (c - cStart)*8 + 3+4;
3779       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3780 #if 1
3781       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3782       for (p = 0; p < 2; ++p) {
3783         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
3784       }
3785 #endif
3786       ++newp;
3787       /* Face H: {a, b, f} */
3788       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3789       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3790       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3791       orntNew[1] = ornt[3] < 0 ? 0 : -2;
3792       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3793       orntNew[2] = -2;
3794       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3795       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3796 #if 1
3797       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3798       for (p = 0; p < 3; ++p) {
3799         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3800       }
3801 #endif
3802       supportNew[0] = (c - cStart)*8 + 1+4;
3803       supportNew[1] = (c - cStart)*8 + 2+4;
3804       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3805 #if 1
3806       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3807       for (p = 0; p < 2; ++p) {
3808         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
3809       }
3810 #endif
3811       ++newp;
3812     }
3813     /* Split Edges have 2 vertices and the same faces as the parent */
3814     for (e = eStart; e < eEnd; ++e) {
3815       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
3816 
3817       for (r = 0; r < 2; ++r) {
3818         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
3819         const PetscInt *cone, *ornt, *support;
3820         PetscInt        coneNew[2], coneSize, c, supportSize, s;
3821 
3822         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3823         coneNew[0]       = vStartNew + (cone[0] - vStart);
3824         coneNew[1]       = vStartNew + (cone[1] - vStart);
3825         coneNew[(r+1)%2] = newv;
3826         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3827 #if 1
3828         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3829         for (p = 0; p < 2; ++p) {
3830           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
3831         }
3832 #endif
3833         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
3834         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3835         for (s = 0; s < supportSize; ++s) {
3836           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3837           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3838           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3839           for (c = 0; c < coneSize; ++c) {
3840             if (cone[c] == e) break;
3841           }
3842           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
3843         }
3844         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3845 #if 1
3846         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3847         for (p = 0; p < supportSize; ++p) {
3848           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
3849         }
3850 #endif
3851       }
3852     }
3853     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
3854     for (f = fStart; f < fEnd; ++f) {
3855       const PetscInt *cone, *ornt, *support;
3856       PetscInt        coneSize, supportSize, s;
3857 
3858       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3859       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3860       for (r = 0; r < 3; ++r) {
3861         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
3862         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
3863         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
3864                                     -1, -1,  1,  6,  0,  4,
3865                                      2,  5,  3,  4, -1, -1,
3866                                     -1, -1,  3,  6,  2,  7};
3867 
3868         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3869         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
3870         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
3871         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3872 #if 1
3873         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3874         for (p = 0; p < 2; ++p) {
3875           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
3876         }
3877 #endif
3878         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
3879         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
3880         for (s = 0; s < supportSize; ++s) {
3881           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3882           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3883           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3884           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
3885           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
3886           er = GetTriMidEdgeInverse_Static(ornt[c], r);
3887           if (er == eint[c]) {
3888             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
3889           } else {
3890             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
3891             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
3892           }
3893         }
3894         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3895 #if 1
3896         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3897         for (p = 0; p < intFaces; ++p) {
3898           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
3899         }
3900 #endif
3901       }
3902     }
3903     /* Interior edges have 2 vertices and 4 faces */
3904     for (c = cStart; c < cEnd; ++c) {
3905       const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3906       const PetscInt *cone, *ornt, *fcone;
3907       PetscInt        coneNew[2], supportNew[4], find;
3908 
3909       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3910       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3911       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
3912       find = GetTriEdge_Static(ornt[0], 0);
3913       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3914       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
3915       find = GetTriEdge_Static(ornt[2], 1);
3916       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3917       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3918 #if 1
3919       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3920       for (p = 0; p < 2; ++p) {
3921         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
3922       }
3923 #endif
3924       supportNew[0] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 4;
3925       supportNew[1] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 5;
3926       supportNew[2] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 6;
3927       supportNew[3] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 7;
3928       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3929 #if 1
3930       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3931       for (p = 0; p < 4; ++p) {
3932         if ((supportNew[p] < fStartNew) || (supportNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportNew[p], fStartNew, fEndNew);
3933       }
3934 #endif
3935     }
3936     /* Old vertices have identical supports */
3937     for (v = vStart; v < vEnd; ++v) {
3938       const PetscInt  newp = vStartNew + (v - vStart);
3939       const PetscInt *support, *cone;
3940       PetscInt        size, s;
3941 
3942       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
3943       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
3944       for (s = 0; s < size; ++s) {
3945         PetscInt r = 0;
3946 
3947         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3948         if (cone[1] == v) r = 1;
3949         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
3950       }
3951       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3952 #if 1
3953       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3954       for (p = 0; p < size; ++p) {
3955         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
3956       }
3957 #endif
3958     }
3959     /* Edge vertices have 2 + face*2 + 0/1 supports */
3960     for (e = eStart; e < eEnd; ++e) {
3961       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
3962       const PetscInt *cone, *support;
3963       PetscInt       *star = NULL, starSize, cellSize = 0, coneSize, size, s;
3964 
3965       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
3966       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3967       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
3968       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
3969       for (s = 0; s < size; ++s) {
3970         PetscInt r = 0;
3971 
3972         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3973         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3974         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
3975         supportRef[2+s*2+0] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
3976         supportRef[2+s*2+1] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
3977       }
3978       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
3979       for (s = 0; s < starSize*2; s += 2) {
3980         const PetscInt *cone, *ornt;
3981         PetscInt        e01, e23;
3982 
3983         if ((star[s] >= cStart) && (star[s] < cEnd)) {
3984           /* Check edge 0-1 */
3985           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
3986           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
3987           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
3988           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
3989           /* Check edge 2-3 */
3990           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
3991           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
3992           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
3993           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
3994           if ((e01 == e) || (e23 == e)) {supportRef[2+size*2+cellSize++] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (star[s] - cStart);}
3995         }
3996       }
3997       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
3998       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3999 #if 1
4000       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4001       for (p = 0; p < 2+size*2+cellSize; ++p) {
4002         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
4003       }
4004 #endif
4005     }
4006     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4007     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
4008     break;
4009   case REFINER_HYBRID_SIMPLEX_3D:
4010     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
4011     /* Interior cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
4012     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
4013     for (c = cStart; c < cMax; ++c) {
4014       const PetscInt  newp = cStartNew + (c - cStart)*8;
4015       const PetscInt *cone, *ornt;
4016       PetscInt        coneNew[4], orntNew[4];
4017 
4018       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4019       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4020       /* A tetrahedron: {0, a, c, d} */
4021       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
4022       orntNew[0] = ornt[0];
4023       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
4024       orntNew[1] = ornt[1];
4025       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
4026       orntNew[2] = ornt[2];
4027       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
4028       orntNew[3] = 0;
4029       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4030       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4031 #if 1
4032       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cMaxNew);
4033       for (p = 0; p < 4; ++p) {
4034         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
4035       }
4036 #endif
4037       /* B tetrahedron: {a, 1, b, e} */
4038       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
4039       orntNew[0] = ornt[0];
4040       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
4041       orntNew[1] = ornt[1];
4042       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
4043       orntNew[2] = 0;
4044       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
4045       orntNew[3] = ornt[3];
4046       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4047       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4048 #if 1
4049       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cMaxNew);
4050       for (p = 0; p < 4; ++p) {
4051         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
4052       }
4053 #endif
4054       /* C tetrahedron: {c, b, 2, f} */
4055       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
4056       orntNew[0] = ornt[0];
4057       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
4058       orntNew[1] = 0;
4059       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
4060       orntNew[2] = ornt[2];
4061       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
4062       orntNew[3] = ornt[3];
4063       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4064       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4065 #if 1
4066       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cMaxNew);
4067       for (p = 0; p < 4; ++p) {
4068         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
4069       }
4070 #endif
4071       /* D tetrahedron: {d, e, f, 3} */
4072       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
4073       orntNew[0] = 0;
4074       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
4075       orntNew[1] = ornt[1];
4076       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
4077       orntNew[2] = ornt[2];
4078       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
4079       orntNew[3] = ornt[3];
4080       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4081       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4082 #if 1
4083       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cMaxNew);
4084       for (p = 0; p < 4; ++p) {
4085         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
4086       }
4087 #endif
4088       /* A' tetrahedron: {d, a, c, f} */
4089       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
4090       orntNew[0] = -3;
4091       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
4092       orntNew[1] = ornt[2] < 0 ? -(GetTriMidEdge_Static(ornt[2], 0)+1) : GetTriMidEdge_Static(ornt[2], 0);
4093       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
4094       orntNew[2] = 0;
4095       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
4096       orntNew[3] = 2;
4097       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
4098       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
4099 #if 1
4100       if ((newp+4 < cStartNew) || (newp+4 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+4, cStartNew, cMaxNew);
4101       for (p = 0; p < 4; ++p) {
4102         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
4103       }
4104 #endif
4105       /* B' tetrahedron: {e, b, a, f} */
4106       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
4107       orntNew[0] = -3;
4108       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
4109       orntNew[1] = 1;
4110       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
4111       orntNew[2] = 0;
4112       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + 3;
4113       orntNew[3] = ornt[3] < 0 ? -(GetTriMidEdge_Static(ornt[3], 0)+1) : GetTriMidEdge_Static(ornt[3], 0);
4114       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
4115       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
4116 #if 1
4117       if ((newp+5 < cStartNew) || (newp+5 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+5, cStartNew, cMaxNew);
4118       for (p = 0; p < 4; ++p) {
4119         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
4120       }
4121 #endif
4122       /* C' tetrahedron: {b, f, c, a} */
4123       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
4124       orntNew[0] = -3;
4125       coneNew[1] = fStartNew + (cone[0] - fStart)*4 + 3;
4126       orntNew[1] = ornt[0] < 0 ? -(GetTriMidEdge_Static(ornt[0], 2)+1) : GetTriMidEdge_Static(ornt[0], 2);
4127       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
4128       orntNew[2] = -3;
4129       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
4130       orntNew[3] = -2;
4131       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
4132       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
4133 #if 1
4134       if ((newp+6 < cStartNew) || (newp+6 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+6, cStartNew, cMaxNew);
4135       for (p = 0; p < 4; ++p) {
4136         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
4137       }
4138 #endif
4139       /* D' tetrahedron: {f, e, d, a} */
4140       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
4141       orntNew[0] = -3;
4142       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
4143       orntNew[1] = -3;
4144       coneNew[2] = fStartNew + (cone[1] - fStart)*4 + 3;
4145       orntNew[2] = ornt[1] < 0 ? -(GetTriMidEdge_Static(ornt[1], 0)+1) : GetTriMidEdge_Static(ornt[1], 0);
4146       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
4147       orntNew[3] = -3;
4148       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
4149       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
4150 #if 1
4151       if ((newp+7 < cStartNew) || (newp+7 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+7, cStartNew, cMaxNew);
4152       for (p = 0; p < 4; ++p) {
4153         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
4154       }
4155 #endif
4156     }
4157     /* Hybrid cells have 5 faces */
4158     for (c = cMax; c < cEnd; ++c) {
4159       const PetscInt  newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4;
4160       const PetscInt *cone, *ornt, *fornt;
4161       PetscInt        coneNew[5], orntNew[5], o, of, i;
4162 
4163       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4164       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4165       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
4166       o = ornt[0] < 0 ? -1 : 1;
4167       for (r = 0; r < 3; ++r) {
4168         coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], r);
4169         orntNew[0] = ornt[0];
4170         coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], r);
4171         orntNew[1] = ornt[1];
4172         of = fornt[GetTriEdge_Static(ornt[0], r)]       < 0 ? -1 : 1;
4173         i  = GetTriEdgeInverse_Static(ornt[0], r)       + 2;
4174         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], r)]       - fMax)*2 + (o*of < 0 ? 1 : 0);
4175         orntNew[i] = 0;
4176         i  = GetTriEdgeInverse_Static(ornt[0], (r+1)%3) + 2;
4177         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + GetTriSubface_Static(ornt[0], r);
4178         orntNew[i] = 0;
4179         of = fornt[GetTriEdge_Static(ornt[0], (r+2)%3)] < 0 ? -1 : 1;
4180         i  = GetTriEdgeInverse_Static(ornt[0], (r+2)%3) + 2;
4181         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);
4182         orntNew[i] = 0;
4183         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
4184         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
4185 #if 1
4186         if ((newp+r < cMaxNew) || (newp+r >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", newp+r, cMaxNew, cEndNew);
4187         for (p = 0; p < 2; ++p) {
4188           if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
4189         }
4190         for (p = 2; p < 5; ++p) {
4191           if ((coneNew[p] < fMaxNew)   || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", coneNew[p], fMaxNew, fEndNew);
4192         }
4193 #endif
4194       }
4195       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + 3;
4196       orntNew[0] = 0;
4197       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + 3;
4198       orntNew[1] = 0;
4199       coneNew[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
4200       orntNew[2] = 0;
4201       coneNew[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
4202       orntNew[3] = 0;
4203       coneNew[4] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
4204       orntNew[4] = 0;
4205       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4206       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4207 #if 1
4208       if ((newp+3 < cMaxNew) || (newp+3 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", newp+3, cMaxNew, cEndNew);
4209       for (p = 0; p < 2; ++p) {
4210         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
4211       }
4212       for (p = 2; p < 5; ++p) {
4213         if ((coneNew[p] < fMaxNew)   || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", coneNew[p], fMaxNew, fEndNew);
4214       }
4215 #endif
4216     }
4217     /* Split faces have 3 edges and the same cells as the parent */
4218     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4219     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
4220     for (f = fStart; f < fMax; ++f) {
4221       const PetscInt  newp = fStartNew + (f - fStart)*4;
4222       const PetscInt *cone, *ornt, *support;
4223       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
4224 
4225       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4226       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4227       /* A triangle */
4228       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
4229       orntNew[0] = ornt[0];
4230       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
4231       orntNew[1] = -2;
4232       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
4233       orntNew[2] = ornt[2];
4234       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4235       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4236 #if 1
4237       if ((newp+0 < fStartNew) || (newp+0 >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+0, fStartNew, fMaxNew);
4238       for (p = 0; p < 3; ++p) {
4239         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
4240       }
4241 #endif
4242       /* B triangle */
4243       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
4244       orntNew[0] = ornt[0];
4245       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
4246       orntNew[1] = ornt[1];
4247       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
4248       orntNew[2] = -2;
4249       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4250       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4251 #if 1
4252       if ((newp+1 < fStartNew) || (newp+1 >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+1, fStartNew, fMaxNew);
4253       for (p = 0; p < 3; ++p) {
4254         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
4255       }
4256 #endif
4257       /* C triangle */
4258       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
4259       orntNew[0] = -2;
4260       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
4261       orntNew[1] = ornt[1];
4262       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
4263       orntNew[2] = ornt[2];
4264       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4265       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4266 #if 1
4267       if ((newp+2 < fStartNew) || (newp+2 >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+2, fStartNew, fMaxNew);
4268       for (p = 0; p < 3; ++p) {
4269         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
4270       }
4271 #endif
4272       /* D triangle */
4273       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
4274       orntNew[0] = 0;
4275       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
4276       orntNew[1] = 0;
4277       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
4278       orntNew[2] = 0;
4279       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4280       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4281 #if 1
4282       if ((newp+3 < fStartNew) || (newp+3 >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+3, fStartNew, fMaxNew);
4283       for (p = 0; p < 3; ++p) {
4284         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
4285       }
4286 #endif
4287       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4288       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4289       for (r = 0; r < 4; ++r) {
4290         for (s = 0; s < supportSize; ++s) {
4291           PetscInt subf;
4292           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4293           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4294           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4295           for (c = 0; c < coneSize; ++c) {
4296             if (cone[c] == f) break;
4297           }
4298           subf = GetTriSubfaceInverse_Static(ornt[c], r);
4299           if (support[s] < cMax) {
4300             supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
4301           } else {
4302             supportRef[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (r==3 ? r : subf);
4303           }
4304         }
4305         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
4306 #if 1
4307         if ((newp+r < fStartNew) || (newp+r >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+r, fStartNew, fMaxNew);
4308         for (p = 0; p < supportSize; ++p) {
4309           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an interior or hybrid cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
4310         }
4311 #endif
4312       }
4313     }
4314     /* Interior cell faces have 3 edges and 2 cells */
4315     for (c = cStart; c < cMax; ++c) {
4316       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8;
4317       const PetscInt *cone, *ornt;
4318       PetscInt        coneNew[3], orntNew[3];
4319       PetscInt        supportNew[2];
4320 
4321       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4322       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4323       /* Face A: {c, a, d} */
4324       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
4325       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4326       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
4327       orntNew[1] = ornt[1] < 0 ? -2 : 0;
4328       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 2);
4329       orntNew[2] = ornt[2] < 0 ? -2 : 0;
4330       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4331       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4332 #if 1
4333       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4334       for (p = 0; p < 3; ++p) {
4335         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
4336       }
4337 #endif
4338       supportNew[0] = (c - cStart)*8 + 0;
4339       supportNew[1] = (c - cStart)*8 + 0+4;
4340       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4341 #if 1
4342       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4343       for (p = 0; p < 2; ++p) {
4344         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
4345       }
4346 #endif
4347       ++newp;
4348       /* Face B: {a, b, e} */
4349       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
4350       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4351       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 0);
4352       orntNew[1] = ornt[3] < 0 ? -2 : 0;
4353       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
4354       orntNew[2] = ornt[1] < 0 ? -2 : 0;
4355       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4356       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4357 #if 1
4358       if ((newp+1 < fStartNew) || (newp+1 >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+1, fStartNew, fMaxNew);
4359       for (p = 0; p < 3; ++p) {
4360         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
4361       }
4362 #endif
4363       supportNew[0] = (c - cStart)*8 + 1;
4364       supportNew[1] = (c - cStart)*8 + 1+4;
4365       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4366 #if 1
4367       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4368       for (p = 0; p < 2; ++p) {
4369         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
4370       }
4371 #endif
4372       ++newp;
4373       /* Face C: {c, f, b} */
4374       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
4375       orntNew[0] = ornt[2] < 0 ? -2 : 0;
4376       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
4377       orntNew[1] = ornt[3] < 0 ? -2 : 0;
4378       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 1);
4379       orntNew[2] = ornt[0] < 0 ? -2 : 0;
4380       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4381       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4382 #if 1
4383       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4384       for (p = 0; p < 3; ++p) {
4385         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
4386       }
4387 #endif
4388       supportNew[0] = (c - cStart)*8 + 2;
4389       supportNew[1] = (c - cStart)*8 + 2+4;
4390       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4391 #if 1
4392       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4393       for (p = 0; p < 2; ++p) {
4394         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
4395       }
4396 #endif
4397       ++newp;
4398       /* Face D: {d, e, f} */
4399       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 0);
4400       orntNew[0] = ornt[1] < 0 ? -2 : 0;
4401       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
4402       orntNew[1] = ornt[3] < 0 ? -2 : 0;
4403       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
4404       orntNew[2] = ornt[2] < 0 ? -2 : 0;
4405       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4406       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4407 #if 1
4408       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4409       for (p = 0; p < 3; ++p) {
4410         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
4411       }
4412 #endif
4413       supportNew[0] = (c - cStart)*8 + 3;
4414       supportNew[1] = (c - cStart)*8 + 3+4;
4415       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4416 #if 1
4417       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4418       for (p = 0; p < 2; ++p) {
4419         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
4420       }
4421 #endif
4422       ++newp;
4423       /* Face E: {d, f, a} */
4424       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
4425       orntNew[0] = ornt[2] < 0 ? 0 : -2;
4426       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4427       orntNew[1] = -2;
4428       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
4429       orntNew[2] = ornt[1] < 0 ? -2 : 0;
4430       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4431       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4432 #if 1
4433       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4434       for (p = 0; p < 3; ++p) {
4435         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
4436       }
4437 #endif
4438       supportNew[0] = (c - cStart)*8 + 0+4;
4439       supportNew[1] = (c - cStart)*8 + 3+4;
4440       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4441 #if 1
4442       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4443       for (p = 0; p < 2; ++p) {
4444         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
4445       }
4446 #endif
4447       ++newp;
4448       /* Face F: {c, a, f} */
4449       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
4450       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4451       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4452       orntNew[1] = 0;
4453       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
4454       orntNew[2] = ornt[2] < 0 ? 0 : -2;
4455       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4456       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4457 #if 1
4458       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4459       for (p = 0; p < 3; ++p) {
4460         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
4461       }
4462 #endif
4463       supportNew[0] = (c - cStart)*8 + 0+4;
4464       supportNew[1] = (c - cStart)*8 + 2+4;
4465       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4466 #if 1
4467       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4468       for (p = 0; p < 2; ++p) {
4469         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
4470       }
4471 #endif
4472       ++newp;
4473       /* Face G: {e, a, f} */
4474       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
4475       orntNew[0] = ornt[1] < 0 ? -2 : 0;
4476       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4477       orntNew[1] = 0;
4478       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
4479       orntNew[2] = ornt[3] < 0 ? 0 : -2;
4480       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4481       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4482 #if 1
4483       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4484       for (p = 0; p < 3; ++p) {
4485         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
4486       }
4487 #endif
4488       supportNew[0] = (c - cStart)*8 + 1+4;
4489       supportNew[1] = (c - cStart)*8 + 3+4;
4490       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4491 #if 1
4492       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4493       for (p = 0; p < 2; ++p) {
4494         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
4495       }
4496 #endif
4497       ++newp;
4498       /* Face H: {a, b, f} */
4499       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
4500       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4501       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
4502       orntNew[1] = ornt[3] < 0 ? 0 : -2;
4503       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4504       orntNew[2] = -2;
4505       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4506       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4507 #if 1
4508       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4509       for (p = 0; p < 3; ++p) {
4510         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
4511       }
4512 #endif
4513       supportNew[0] = (c - cStart)*8 + 1+4;
4514       supportNew[1] = (c - cStart)*8 + 2+4;
4515       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4516 #if 1
4517       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4518       for (p = 0; p < 2; ++p) {
4519         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
4520       }
4521 #endif
4522       ++newp;
4523     }
4524     /* Hybrid split faces have 4 edges and same cells */
4525     for (f = fMax; f < fEnd; ++f) {
4526       const PetscInt *cone, *ornt, *support;
4527       PetscInt        coneNew[4], orntNew[4];
4528       PetscInt        supportNew[2], size, s, c;
4529 
4530       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4531       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4532       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4533       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4534       for (r = 0; r < 2; ++r) {
4535         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
4536 
4537         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
4538         orntNew[0]   = ornt[0];
4539         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
4540         orntNew[1]   = ornt[1];
4541         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (cone[2+r] - eMax);
4542         orntNew[2+r] = 0;
4543         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd      - eMax) + (f - fMax);
4544         orntNew[3-r] = 0;
4545         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4546         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4547 #if 1
4548         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
4549         for (p = 0; p < 2; ++p) {
4550           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
4551         }
4552         for (p = 2; p < 4; ++p) {
4553           if ((coneNew[p] < eMaxNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", coneNew[p], eMaxNew, eEndNew);
4554         }
4555 #endif
4556         for (s = 0; s < size; ++s) {
4557           const PetscInt *coneCell, *orntCell, *fornt;
4558           PetscInt        o, of;
4559 
4560           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
4561           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
4562           o = orntCell[0] < 0 ? -1 : 1;
4563           for (c = 2; c < 5; ++c) if (coneCell[c] == f) break;
4564           if (c >= 5) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
4565           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
4566           of = fornt[c-2] < 0 ? -1 : 1;
4567           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetTriEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%3;
4568         }
4569         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4570 #if 1
4571         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
4572         for (p = 0; p < size; ++p) {
4573           if ((supportNew[p] < cMaxNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", supportNew[p], cMaxNew, cEndNew);
4574         }
4575 #endif
4576       }
4577     }
4578     /* Hybrid cell faces have 4 edges and 2 cells */
4579     for (c = cMax; c < cEnd; ++c) {
4580       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3;
4581       const PetscInt *cone, *ornt;
4582       PetscInt        coneNew[4], orntNew[4];
4583       PetscInt        supportNew[2];
4584 
4585       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4586       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4587       for (r = 0; r < 3; ++r) {
4588         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + (r+2)%3;
4589         orntNew[0] = 0;
4590         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + (r+2)%3;
4591         orntNew[1] = 0;
4592         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+(r+2)%3] - fMax);
4593         orntNew[2] = 0;
4594         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+r]       - fMax);
4595         orntNew[3] = 0;
4596         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
4597         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
4598 #if 1
4599         if ((newp+r < fMaxNew) || (newp+r >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp+r, fMaxNew, fEndNew);
4600         for (p = 0; p < 2; ++p) {
4601           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
4602         }
4603         for (p = 2; p < 4; ++p) {
4604           if ((coneNew[p] < eMaxNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", coneNew[p], eMaxNew, eEndNew);
4605         }
4606 #endif
4607         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetTriSubface_Static(ornt[0], r);
4608         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + 3;
4609         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
4610 #if 1
4611         if ((newp+r < fMaxNew) || (newp+r >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp+r, fMaxNew, fEndNew);
4612         for (p = 0; p < 2; ++p) {
4613           if ((supportNew[p] < cMaxNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", supportNew[p], cMaxNew, cEndNew);
4614         }
4615 #endif
4616       }
4617     }
4618     /* Interior split edges have 2 vertices and the same faces as the parent */
4619     for (e = eStart; e < eMax; ++e) {
4620       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
4621 
4622       for (r = 0; r < 2; ++r) {
4623         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
4624         const PetscInt *cone, *ornt, *support;
4625         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4626 
4627         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4628         coneNew[0]       = vStartNew + (cone[0] - vStart);
4629         coneNew[1]       = vStartNew + (cone[1] - vStart);
4630         coneNew[(r+1)%2] = newv;
4631         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4632 #if 1
4633         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4634         for (p = 0; p < 2; ++p) {
4635           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4636         }
4637 #endif
4638         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
4639         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4640         for (s = 0; s < supportSize; ++s) {
4641           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4642           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4643           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4644           for (c = 0; c < coneSize; ++c) if (cone[c] == e) break;
4645           if (support[s] < fMax) {
4646             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
4647           } else {
4648             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
4649           }
4650         }
4651         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4652 #if 1
4653         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4654         for (p = 0; p < supportSize; ++p) {
4655           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an interior or hybrid face [%d, %d)", supportRef[p], fStartNew, fEndNew);
4656         }
4657 #endif
4658       }
4659     }
4660     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
4661     for (f = fStart; f < fMax; ++f) {
4662       const PetscInt *cone, *ornt, *support;
4663       PetscInt        coneSize, supportSize, s;
4664 
4665       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4666       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4667       for (r = 0; r < 3; ++r) {
4668         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
4669         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
4670         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
4671                                     -1, -1,  1,  6,  0,  4,
4672                                      2,  5,  3,  4, -1, -1,
4673                                     -1, -1,  3,  6,  2,  7};
4674 
4675         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4676         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
4677         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
4678         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4679 #if 1
4680         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4681         for (p = 0; p < 2; ++p) {
4682           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4683         }
4684 #endif
4685         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
4686         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
4687         for (s = 0; s < supportSize; ++s) {
4688           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4689           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4690           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4691           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
4692           if (support[s] < cMax) {
4693             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
4694             er = GetTriMidEdgeInverse_Static(ornt[c], r);
4695             if (er == eint[c]) {
4696               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
4697             } else {
4698               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
4699               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
4700             }
4701           } else {
4702             supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (r + 1)%3;
4703           }
4704         }
4705         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4706 #if 1
4707         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4708         for (p = 0; p < intFaces; ++p) {
4709           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an interior or hybrid face [%d, %d)", supportRef[p], fStartNew, fEndNew);
4710         }
4711 #endif
4712       }
4713     }
4714     /* Interior cell edges have 2 vertices and 4 faces */
4715     for (c = cStart; c < cMax; ++c) {
4716       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4717       const PetscInt *cone, *ornt, *fcone;
4718       PetscInt        coneNew[2], supportNew[4], find;
4719 
4720       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4721       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4722       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
4723       find = GetTriEdge_Static(ornt[0], 0);
4724       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4725       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
4726       find = GetTriEdge_Static(ornt[2], 1);
4727       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4728       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4729 #if 1
4730       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4731       for (p = 0; p < 2; ++p) {
4732         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4733       }
4734 #endif
4735       supportNew[0] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 4;
4736       supportNew[1] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 5;
4737       supportNew[2] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 6;
4738       supportNew[3] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 7;
4739       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4740 #if 1
4741       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4742       for (p = 0; p < 4; ++p) {
4743         if ((supportNew[p] < fStartNew) || (supportNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportNew[p], fStartNew, fMaxNew);
4744       }
4745 #endif
4746     }
4747     /* Hybrid edges have two vertices and the same faces */
4748     for (e = eMax; e < eEnd; ++e) {
4749       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
4750       const PetscInt *cone, *support, *fcone;
4751       PetscInt        coneNew[2], size, fsize, s;
4752 
4753       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4754       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4755       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4756       coneNew[0] = vStartNew + (cone[0] - vStart);
4757       coneNew[1] = vStartNew + (cone[1] - vStart);
4758       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4759 #if 1
4760       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4761       for (p = 0; p < 2; ++p) {
4762         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4763       }
4764 #endif
4765       for (s = 0; s < size; ++s) {
4766         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
4767         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
4768         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
4769         if ((c < 2) || (c > 3)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
4770         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + c-2;
4771       }
4772       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4773 #if 1
4774       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4775       for (p = 0; p < size; ++p) {
4776         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", supportRef[p], fMaxNew, fEndNew);
4777       }
4778 #endif
4779     }
4780     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
4781     for (f = fMax; f < fEnd; ++f) {
4782       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
4783       const PetscInt *cone, *support, *ccone, *cornt;
4784       PetscInt        coneNew[2], size, csize, s;
4785 
4786       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4787       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4788       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4789       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
4790       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
4791       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4792 #if 1
4793       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4794       for (p = 0; p < 2; ++p) {
4795         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4796       }
4797 #endif
4798       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 0;
4799       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 1;
4800       for (s = 0; s < size; ++s) {
4801         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
4802         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
4803         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
4804         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
4805         if ((c < 2) || (c >= csize)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Hybrid face %d is not in cone of hybrid cell %d", f, support[s]);
4806         supportRef[2+s*2+0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + c-2;
4807         supportRef[2+s*2+1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (c-1)%3;
4808       }
4809       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4810 #if 1
4811       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4812       for (p = 0; p < 2+size*2; ++p) {
4813         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", supportRef[p], fMaxNew, fEndNew);
4814       }
4815 #endif
4816     }
4817     /* Interior vertices have identical supports */
4818     for (v = vStart; v < vEnd; ++v) {
4819       const PetscInt  newp = vStartNew + (v - vStart);
4820       const PetscInt *support, *cone;
4821       PetscInt        size, s;
4822 
4823       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4824       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4825       for (s = 0; s < size; ++s) {
4826         PetscInt r = 0;
4827 
4828         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4829         if (cone[1] == v) r = 1;
4830         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4831         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (support[s] - eMax);
4832       }
4833       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4834 #if 1
4835       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4836       for (p = 0; p < size; ++p) {
4837         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an interior or hybrid edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
4838       }
4839 #endif
4840     }
4841     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
4842     for (e = eStart; e < eMax; ++e) {
4843       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4844       const PetscInt *cone, *support;
4845       PetscInt       *star = NULL, starSize, faceSize = 0, cellSize = 0, coneSize, size, s;
4846 
4847       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4848       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4849       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4850       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4851       for (s = 0; s < size; ++s) {
4852         PetscInt r = 0;
4853 
4854         if (support[s] < fMax) {
4855           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4856           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4857           for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
4858           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
4859           supportRef[2+faceSize+1] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
4860           faceSize += 2;
4861         } else {
4862           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (support[s] - fMax);
4863           ++faceSize;
4864         }
4865       }
4866       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4867       for (s = 0; s < starSize*2; s += 2) {
4868         const PetscInt *cone, *ornt;
4869         PetscInt        e01, e23;
4870 
4871         if ((star[s] >= cStart) && (star[s] < cMax)) {
4872           /* Check edge 0-1 */
4873           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
4874           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
4875           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
4876           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
4877           /* Check edge 2-3 */
4878           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
4879           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
4880           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
4881           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
4882           if ((e01 == e) || (e23 == e)) {supportRef[2+faceSize+cellSize++] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (star[s] - cStart);}
4883         }
4884       }
4885       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4886       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4887 #if 1
4888       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4889       for (p = 0; p < 2+faceSize+cellSize; ++p) {
4890         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an interior or hybrid edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
4891       }
4892 #endif
4893     }
4894     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4895     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
4896     break;
4897   case REFINER_SIMPLEX_TO_HEX_3D:
4898     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
4899     /* All cells have 6 faces */
4900     for (c = cStart; c < cEnd; ++c) {
4901       const PetscInt  newp = cStartNew + (c - cStart)*4;
4902       const PetscInt *cone, *ornt;
4903       PetscInt        coneNew[6];
4904       PetscInt        orntNew[6];
4905 
4906       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4907       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4908       /* A hex */
4909       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 0); /* B */
4910       orntNew[0] = ornt[0] < 0 ? -1 : 1;
4911       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 3;               /* T */
4912       orntNew[1] = -4;
4913       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 0); /* F */
4914       orntNew[2] = ornt[2] < 0 ? -1 : 1;
4915       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 0;               /* K */
4916       orntNew[3] = -1;
4917       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 2;               /* R */
4918       orntNew[4] = 0;
4919       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 0); /* L */
4920       orntNew[5] = ornt[1] < 0 ? -1 : 1;
4921       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4922       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4923 #if 1
4924       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
4925       for (p = 0; p < 6; ++p) {
4926         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4927       }
4928 #endif
4929       /* B hex */
4930       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 1); /* B */
4931       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4932       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 4;               /* T */
4933       orntNew[1] = 0;
4934       coneNew[2] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 0;               /* F */
4935       orntNew[2] = 0;
4936       coneNew[3] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 1); /* K */
4937       orntNew[3] = ornt[3] < 0 ? -2 : 0;
4938       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 1;               /* R */
4939       orntNew[4] = 0;
4940       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 2); /* L */
4941       orntNew[5] = ornt[1] < 0 ? -4 : 2;
4942       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4943       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4944 #if 1
4945       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
4946       for (p = 0; p < 6; ++p) {
4947         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4948       }
4949 #endif
4950       /* C hex */
4951       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 2); /* B */
4952       orntNew[0] = ornt[0] < 0 ? -4 : 2;
4953       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 5;               /* T */
4954       orntNew[1] = -4;
4955       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 1); /* F */
4956       orntNew[2] = ornt[2] < 0 ? -2 : 0;
4957       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 1;               /* K */
4958       orntNew[3] = -1;
4959       coneNew[4] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 0); /* R */
4960       orntNew[4] = ornt[3] < 0 ? -1 : 1;
4961       coneNew[5] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 2;               /* L */
4962       orntNew[5] = -4;
4963       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4964       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4965 #if 1
4966       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
4967       for (p = 0; p < 6; ++p) {
4968         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4969       }
4970 #endif
4971       /* D hex */
4972       coneNew[0] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 3;               /* B */
4973       orntNew[0] = 0;
4974       coneNew[1] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 2); /* T */
4975       orntNew[1] = ornt[3] < 0 ? -1 : 1;
4976       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 2); /* F */
4977       orntNew[2] = ornt[2] < 0 ? -4 : 2;
4978       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 4;               /* K */
4979       orntNew[3] = -1;
4980       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 5;               /* R */
4981       orntNew[4] = 0;
4982       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 1); /* L */
4983       orntNew[5] = ornt[1] < 0 ? -2 : 0;
4984       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4985       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4986 #if 1
4987       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
4988       for (p = 0; p < 6; ++p) {
4989         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4990       }
4991 #endif
4992     }
4993     /* Split faces have 4 edges and the same cells as the parent */
4994     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4995     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
4996     for (f = fStart; f < fEnd; ++f) {
4997       const PetscInt  newp = fStartNew + (f - fStart)*3;
4998       const PetscInt *cone, *ornt, *support;
4999       PetscInt        coneNew[4], orntNew[4], coneSize, supportSize, s;
5000 
5001       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5002       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
5003       /* A quad */
5004       coneNew[0] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
5005       orntNew[0] = ornt[2];
5006       coneNew[1] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
5007       orntNew[1] = ornt[0];
5008       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
5009       orntNew[2] = 0;
5010       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
5011       orntNew[3] = -2;
5012       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5013       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5014 #if 1
5015       if ((newp+0 < fStartNew) || (newp+0 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+0, fStartNew, fEndNew);
5016       for (p = 0; p < 4; ++p) {
5017         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5018       }
5019 #endif
5020       /* B quad */
5021       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
5022       orntNew[0] = ornt[0];
5023       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
5024       orntNew[1] = ornt[1];
5025       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
5026       orntNew[2] = 0;
5027       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
5028       orntNew[3] = -2;
5029       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5030       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5031 #if 1
5032       if ((newp+1 < fStartNew) || (newp+1 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+1, fStartNew, fEndNew);
5033       for (p = 0; p < 4; ++p) {
5034         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5035       }
5036 #endif
5037       /* C quad */
5038       coneNew[0] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
5039       orntNew[0] = ornt[1];
5040       coneNew[1] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
5041       orntNew[1] = ornt[2];
5042       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
5043       orntNew[2] = 0;
5044       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
5045       orntNew[3] = -2;
5046       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5047       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5048 #if 1
5049       if ((newp+2 < fStartNew) || (newp+2 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+2, fStartNew, fEndNew);
5050       for (p = 0; p < 4; ++p) {
5051         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5052       }
5053 #endif
5054       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5055       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5056       for (r = 0; r < 3; ++r) {
5057         for (s = 0; s < supportSize; ++s) {
5058           PetscInt subf;
5059           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5060           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5061           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5062           for (c = 0; c < coneSize; ++c) {
5063             if (cone[c] == f) break;
5064           }
5065           subf = GetTriSubfaceInverse_Static(ornt[c], r);
5066           supportRef[s] = cStartNew + (support[s] - cStart)*4 + faces[c*3+subf];
5067         }
5068         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
5069 #if 1
5070         if ((newp+r < fStartNew) || (newp+r >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+r, fStartNew, fEndNew);
5071         for (p = 0; p < supportSize; ++p) {
5072           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
5073         }
5074 #endif
5075       }
5076     }
5077     /* Interior faces have 4 edges and 2 cells */
5078     for (c = cStart; c < cEnd; ++c) {
5079       PetscInt        newp = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6;
5080       const PetscInt *cone, *ornt;
5081       PetscInt        coneNew[4], orntNew[4];
5082       PetscInt        supportNew[2];
5083 
5084       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5085       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5086       /* Face {a, g, m, h} */
5087       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],0);
5088       orntNew[0] = 0;
5089       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
5090       orntNew[1] = 0;
5091       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
5092       orntNew[2] = -2;
5093       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],2);
5094       orntNew[3] = -2;
5095       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5096       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5097 #if 1
5098       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5099       for (p = 0; p < 4; ++p) {
5100         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5101       }
5102 #endif
5103       supportNew[0] = (c - cStart)*4 + 0;
5104       supportNew[1] = (c - cStart)*4 + 1;
5105       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5106 #if 1
5107       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5108       for (p = 0; p < 2; ++p) {
5109         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
5110       }
5111 #endif
5112       ++newp;
5113       /* Face {g, b, l , m} */
5114       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],1);
5115       orntNew[0] = -2;
5116       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],0);
5117       orntNew[1] = 0;
5118       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
5119       orntNew[2] = 0;
5120       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
5121       orntNew[3] = -2;
5122       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5123       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5124 #if 1
5125       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5126       for (p = 0; p < 4; ++p) {
5127         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5128       }
5129 #endif
5130       supportNew[0] = (c - cStart)*4 + 1;
5131       supportNew[1] = (c - cStart)*4 + 2;
5132       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5133 #if 1
5134       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5135       for (p = 0; p < 2; ++p) {
5136         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
5137       }
5138 #endif
5139       ++newp;
5140       /* Face {c, g, m, i} */
5141       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],2);
5142       orntNew[0] = 0;
5143       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
5144       orntNew[1] = 0;
5145       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
5146       orntNew[2] = -2;
5147       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],0);
5148       orntNew[3] = -2;
5149       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5150       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5151 #if 1
5152       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5153       for (p = 0; p < 4; ++p) {
5154         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5155       }
5156 #endif
5157       supportNew[0] = (c - cStart)*4 + 0;
5158       supportNew[1] = (c - cStart)*4 + 2;
5159       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5160 #if 1
5161       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5162       for (p = 0; p < 2; ++p) {
5163         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
5164       }
5165 #endif
5166       ++newp;
5167       /* Face {d, h, m, i} */
5168       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],0);
5169       orntNew[0] = 0;
5170       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
5171       orntNew[1] = 0;
5172       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
5173       orntNew[2] = -2;
5174       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],2);
5175       orntNew[3] = -2;
5176       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5177       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5178 #if 1
5179       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5180       for (p = 0; p < 4; ++p) {
5181         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5182       }
5183 #endif
5184       supportNew[0] = (c - cStart)*4 + 0;
5185       supportNew[1] = (c - cStart)*4 + 3;
5186       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5187 #if 1
5188       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5189       for (p = 0; p < 2; ++p) {
5190         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
5191       }
5192 #endif
5193       ++newp;
5194       /* Face {h, m, l, e} */
5195       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
5196       orntNew[0] = 0;
5197       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
5198       orntNew[1] = -2;
5199       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],1);
5200       orntNew[2] = -2;
5201       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],1);
5202       orntNew[3] = 0;
5203       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5204       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5205 #if 1
5206       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5207       for (p = 0; p < 4; ++p) {
5208         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5209       }
5210 #endif
5211       supportNew[0] = (c - cStart)*4 + 1;
5212       supportNew[1] = (c - cStart)*4 + 3;
5213       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5214 #if 1
5215       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5216       for (p = 0; p < 2; ++p) {
5217         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
5218       }
5219 #endif
5220       ++newp;
5221       /* Face {i, m, l, f} */
5222       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
5223       orntNew[0] = 0;
5224       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
5225       orntNew[1] = -2;
5226       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],2);
5227       orntNew[2] = -2;
5228       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],1);
5229       orntNew[3] = 0;
5230       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5231       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5232 #if 1
5233       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5234       for (p = 0; p < 4; ++p) {
5235         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5236       }
5237 #endif
5238       supportNew[0] = (c - cStart)*4 + 2;
5239       supportNew[1] = (c - cStart)*4 + 3;
5240       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5241 #if 1
5242       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5243       for (p = 0; p < 2; ++p) {
5244         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
5245       }
5246 #endif
5247       ++newp;
5248     }
5249     /* Split Edges have 2 vertices and the same faces as the parent */
5250     for (e = eStart; e < eEnd; ++e) {
5251       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
5252 
5253       for (r = 0; r < 2; ++r) {
5254         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
5255         const PetscInt *cone, *ornt, *support;
5256         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5257 
5258         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
5259         coneNew[0]       = vStartNew + (cone[0] - vStart);
5260         coneNew[1]       = vStartNew + (cone[1] - vStart);
5261         coneNew[(r+1)%2] = newv;
5262         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5263 #if 1
5264         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5265         for (p = 0; p < 2; ++p) {
5266           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
5267         }
5268 #endif
5269         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
5270         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5271         for (s = 0; s < supportSize; ++s) {
5272           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5273           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5274           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5275           for (c = 0; c < coneSize; ++c) {
5276             if (cone[c] == e) break;
5277           }
5278           supportRef[s] = fStartNew + (support[s] - fStart)*3 + (c + (ornt[c] < 0 ? 1-r : r))%3;
5279         }
5280         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5281 #if 1
5282         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5283         for (p = 0; p < supportSize; ++p) {
5284           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
5285         }
5286 #endif
5287       }
5288     }
5289     /* Face edges have 2 vertices and 2 + cell faces supports */
5290     for (f = fStart; f < fEnd; ++f) {
5291       const PetscInt *cone, *ornt, *support;
5292       PetscInt        coneSize, supportSize, s;
5293 
5294       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5295       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5296       for (r = 0; r < 3; ++r) {
5297         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
5298         PetscInt        coneNew[2];
5299         PetscInt        fint[4][3] = { {0, 1, 2},
5300                                        {3, 4, 0},
5301                                        {2, 5, 3},
5302                                        {1, 4, 5} };
5303 
5304         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5305         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
5306         coneNew[1] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + f - fStart;
5307         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5308 #if 1
5309         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5310         for (p = 0; p < 2; ++p) {
5311           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
5312         }
5313 #endif
5314         supportRef[0] = fStartNew + (f - fStart)*3 + (r+0)%3;
5315         supportRef[1] = fStartNew + (f - fStart)*3 + (r+1)%3;
5316         for (s = 0; s < supportSize; ++s) {
5317           PetscInt er;
5318           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5319           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5320           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5321           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
5322           er = GetTriInteriorEdgeInverse_Static(ornt[c], r);
5323           supportRef[2+s] = fStartNew + (fEnd - fStart)*3 + (support[s] - cStart)*6 + fint[c][er];
5324         }
5325         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5326 #if 1
5327         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5328         for (p = 0; p < supportSize + 2; ++p) {
5329           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
5330         }
5331 #endif
5332       }
5333     }
5334     /* Interior cell edges have 2 vertices and 3 faces */
5335     for (c = cStart; c < cEnd; ++c) {
5336       const PetscInt *cone;
5337       PetscInt       fint[4][3] = { {0,1,2},
5338                                     {0,3,4},
5339                                     {2,3,5},
5340                                     {1,4,5} } ;
5341 
5342       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5343       for (r = 0; r < 4; r++) {
5344         PetscInt       coneNew[2], supportNew[3];
5345         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + r;
5346 
5347         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
5348         coneNew[1] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd -fStart) + c - cStart;
5349         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5350 #if 1
5351         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5352         for (p = 0; p < 2; ++p) {
5353           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
5354         }
5355 #endif
5356         supportNew[0] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][0];
5357         supportNew[1] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][1];
5358         supportNew[2] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][2];
5359         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5360 #if 1
5361         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5362         for (p = 0; p < 3; ++p) {
5363           if ((supportNew[p] < fStartNew) || (supportNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportNew[p], fStartNew, fEndNew);
5364         }
5365 #endif
5366       }
5367     }
5368     /* Old vertices have identical supports */
5369     for (v = vStart; v < vEnd; ++v) {
5370       const PetscInt  newp = vStartNew + (v - vStart);
5371       const PetscInt *support, *cone;
5372       PetscInt        size, s;
5373 
5374       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5375       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5376       for (s = 0; s < size; ++s) {
5377         PetscInt r = 0;
5378 
5379         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5380         if (cone[1] == v) r = 1;
5381         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
5382       }
5383       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5384 #if 1
5385       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5386       for (p = 0; p < size; ++p) {
5387         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
5388       }
5389 #endif
5390     }
5391     /* Edge vertices have 2 + faces supports */
5392     for (e = eStart; e < eEnd; ++e) {
5393       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
5394       const PetscInt *cone, *support;
5395       PetscInt        size, s;
5396 
5397       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
5398       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5399       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
5400       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
5401       for (s = 0; s < size; ++s) {
5402         PetscInt r = 0, coneSize;
5403 
5404         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5405         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5406         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
5407         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + r;
5408       }
5409       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5410 #if 1
5411       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5412       for (p = 0; p < 2+size; ++p) {
5413         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
5414       }
5415 #endif
5416     }
5417     /* Face vertices have 3 + cells supports */
5418     for (f = fStart; f < fEnd; ++f) {
5419       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
5420       const PetscInt *cone, *support;
5421       PetscInt        size, s;
5422 
5423       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5424       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5425       supportRef[0] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 0;
5426       supportRef[1] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 1;
5427       supportRef[2] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 2;
5428       for (s = 0; s < size; ++s) {
5429         PetscInt r = 0, coneSize;
5430 
5431         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5432         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5433         for (r = 0; r < coneSize; ++r) {if (cone[r] == f) break;}
5434         supportRef[3+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (support[s] - cStart)*4 + r;
5435       }
5436       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5437 #if 1
5438       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5439       for (p = 0; p < 3+size; ++p) {
5440         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
5441       }
5442 #endif
5443     }
5444     /* Interior cell vertices have 4 supports */
5445     for (c = cStart; c < cEnd; ++c) {
5446       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + c - cStart;
5447       supportRef[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
5448       supportRef[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
5449       supportRef[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
5450       supportRef[3] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
5451       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5452 #if 1
5453       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5454       for (p = 0; p < 4; ++p) {
5455         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
5456       }
5457 #endif
5458     }
5459     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5460     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
5461     break;
5462   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
5463     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5464     cMax = PetscMin(cEnd, cMax);
5465     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5466     fMax = PetscMin(fEnd, fMax);
5467     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5468     eMax = PetscMin(eEnd, eMax);
5469     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
5470     /* All cells have 6 faces */
5471     for (c = cStart; c < cMax; ++c) {
5472       const PetscInt  newp = cStartNew + (c - cStart)*4;
5473       const PetscInt *cone, *ornt;
5474       PetscInt        coneNew[6];
5475       PetscInt        orntNew[6];
5476 
5477       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5478 #if 1
5479       for (p = 0; p < 4; ++p) {
5480         if (cone[p] >= fMax) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position %D for cell %D", cone[p], p, fMax, c);
5481       }
5482 #endif
5483       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5484       /* A hex */
5485       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 0); /* B */
5486       orntNew[0] = ornt[0] < 0 ? -1 : 1;
5487       coneNew[1] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 3;               /* T */
5488       orntNew[1] = -4;
5489       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 0); /* F */
5490       orntNew[2] = ornt[2] < 0 ? -1 : 1;
5491       coneNew[3] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 0;               /* K */
5492       orntNew[3] = -1;
5493       coneNew[4] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 2;               /* R */
5494       orntNew[4] = 0;
5495       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 0); /* L */
5496       orntNew[5] = ornt[1] < 0 ? -1 : 1;
5497       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5498       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5499 #if 1
5500       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
5501       for (p = 0; p < 6; ++p) {
5502         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
5503       }
5504 #endif
5505       /* B hex */
5506       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 1); /* B */
5507       orntNew[0] = ornt[0] < 0 ? -2 : 0;
5508       coneNew[1] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 4;               /* T */
5509       orntNew[1] = 0;
5510       coneNew[2] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 0;               /* F */
5511       orntNew[2] = 0;
5512       coneNew[3] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 1); /* K */
5513       orntNew[3] = ornt[3] < 0 ? -2 : 0;
5514       coneNew[4] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 1;               /* R */
5515       orntNew[4] = 0;
5516       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 2); /* L */
5517       orntNew[5] = ornt[1] < 0 ? -4 : 2;
5518       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5519       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5520 #if 1
5521       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
5522       for (p = 0; p < 6; ++p) {
5523         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
5524       }
5525 #endif
5526       /* C hex */
5527       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 2); /* B */
5528       orntNew[0] = ornt[0] < 0 ? -4 : 2;
5529       coneNew[1] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 5;               /* T */
5530       orntNew[1] = -4;
5531       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 1); /* F */
5532       orntNew[2] = ornt[2] < 0 ? -2 : 0;
5533       coneNew[3] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 1;               /* K */
5534       orntNew[3] = -1;
5535       coneNew[4] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 0); /* R */
5536       orntNew[4] = ornt[3] < 0 ? -1 : 1;
5537       coneNew[5] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 2;               /* L */
5538       orntNew[5] = -4;
5539       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5540       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5541 #if 1
5542       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
5543       for (p = 0; p < 6; ++p) {
5544         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
5545       }
5546 #endif
5547       /* D hex */
5548       coneNew[0] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 3;               /* B */
5549       orntNew[0] = 0;
5550       coneNew[1] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 2); /* T */
5551       orntNew[1] = ornt[3] < 0 ? -1 : 1;
5552       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 2); /* F */
5553       orntNew[2] = ornt[2] < 0 ? -4 : 2;
5554       coneNew[3] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 4;               /* K */
5555       orntNew[3] = -1;
5556       coneNew[4] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 5;               /* R */
5557       orntNew[4] = 0;
5558       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 1); /* L */
5559       orntNew[5] = ornt[1] < 0 ? -2 : 0;
5560       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5561       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5562 #if 1
5563       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
5564       for (p = 0; p < 6; ++p) {
5565         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
5566       }
5567 #endif
5568     }
5569     for (c = cMax; c < cEnd; ++c) {
5570       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*3;
5571       const PetscInt *cone, *ornt, *fornt;
5572       PetscInt        coneNew[6], orntNew[6];
5573       PetscInt        o, of, cf;
5574 
5575       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5576 #if 1
5577       if (cone[0] >= fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position 0 for cell %D", cone[0], fMax, c);
5578       if (cone[1] >= fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position 1 for cell %D", cone[1], fMax, c);
5579       if (cone[2] <  fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected face %D (fMax %D) in cone position 2 for cell %D", cone[2], fMax, c);
5580       if (cone[3] <  fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected face %D (fMax %D) in cone position 3 for cell %D", cone[3], fMax, c);
5581       if (cone[4] <  fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected face %D (fMax %D) in cone position 4 for cell %D", cone[4], fMax, c);
5582 #endif
5583       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5584       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
5585       o    = ornt[0] < 0 ? -1 : 1;
5586       /* A hex */
5587       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 0);                            /* B */
5588       orntNew[0] = ornt[0] < 0 ? -1 :  1;
5589       coneNew[1] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 0);                            /* T */
5590       orntNew[1] = ornt[1] < 0 ?  1 : -1;
5591       cf         = GetTriEdge_Static(ornt[0], 2);
5592       of         = fornt[cf] < 0 ? -1 : 1;
5593       coneNew[2] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 0 : 1); /* F */
5594       orntNew[2] = o*of < 0 ? 0 : -1;
5595       coneNew[3] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;         /* K */
5596       orntNew[3] = -1;
5597       coneNew[4] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;         /* R */
5598       orntNew[4] = 0;
5599       cf         = GetTriEdge_Static(ornt[0], 0);
5600       of         = fornt[cf] < 0 ? -1 : 1;
5601       coneNew[5] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 1 : 0); /* L */
5602       orntNew[5] = o*of < 0 ? 1 : -4;
5603       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5604       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5605 #if 1
5606       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
5607       for (p = 0; p < 6; ++p) {
5608         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
5609       }
5610 #endif
5611       /* B hex */
5612       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 1);                            /* B */
5613       orntNew[0] = ornt[0] < 0 ? -2 :  0;
5614       coneNew[1] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 1);                            /* T */
5615       orntNew[1] = ornt[1] < 0 ?  2 : -4;
5616       coneNew[2] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;         /* F */
5617       orntNew[2] = 0;
5618       cf         = GetTriEdge_Static(ornt[0], 1);
5619       of         = fornt[cf] < 0 ? -1 : 1;
5620       coneNew[3] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 1 : 0); /* K */
5621       orntNew[3] = o*of < 0 ? 0 : -1;
5622       coneNew[4] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;         /* R */
5623       orntNew[4] = -1;
5624       cf         = GetTriEdge_Static(ornt[0], 0);
5625       of         = fornt[cf] < 0 ? -1 : 1;
5626       coneNew[5] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 0 : 1); /* L */
5627       orntNew[5] = o*of < 0 ? 1 : -4;
5628       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5629       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5630 #if 1
5631       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
5632       for (p = 0; p < 6; ++p) {
5633         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
5634       }
5635 #endif
5636       /* C hex */
5637       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 2);                            /* B */
5638       orntNew[0] = ornt[0] < 0 ? -4 : 2;
5639       coneNew[1] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 2);                            /* T */
5640       orntNew[1] = ornt[1] < 0 ? 0 : -2;
5641       cf         = GetTriEdge_Static(ornt[0], 2);
5642       of         = fornt[cf] < 0 ? -1 : 1;
5643       coneNew[2] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 1 : 0); /* F */
5644       orntNew[2] = o*of < 0 ? 0 : -1;
5645       coneNew[3] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;         /* K */
5646       orntNew[3] = 0;
5647       cf         = GetTriEdge_Static(ornt[0], 1);
5648       of         = fornt[cf] < 0 ? -1 : 1;
5649       coneNew[4] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 0 : 1); /* R */
5650       orntNew[4] = o*of < 0 ? 0 : -1;
5651       coneNew[5] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;         /* L */
5652       orntNew[5] = -4;
5653       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5654       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5655 #if 1
5656       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
5657       for (p = 0; p < 6; ++p) {
5658         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
5659       }
5660 #endif
5661     }
5662 
5663     /* Split faces have 4 edges and the same cells as the parent */
5664     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5665     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
5666     for (f = fStart; f < fMax; ++f) {
5667       const PetscInt  newp = fStartNew + (f - fStart)*3;
5668       const PetscInt *cone, *ornt, *support;
5669       PetscInt        coneNew[4], orntNew[4], coneSize, supportSize, s;
5670 
5671       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5672 #if 1
5673       for (p = 0; p < 3; ++p) {
5674         if (cone[p] >= eMax) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid edge %D (eMax %D) in cone position %D for face %D", cone[p], p, eMax, f);
5675       }
5676 #endif
5677       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
5678       /* A quad */
5679       coneNew[0] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
5680       orntNew[0] = ornt[2];
5681       coneNew[1] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
5682       orntNew[1] = ornt[0];
5683       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
5684       orntNew[2] = 0;
5685       coneNew[3] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
5686       orntNew[3] = -2;
5687       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5688       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5689 #if 1
5690       if ((newp+0 < fStartNew) || (newp+0 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+0, fStartNew, fEndNew);
5691       for (p = 0; p < 4; ++p) {
5692         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5693       }
5694 #endif
5695       /* B quad */
5696       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
5697       orntNew[0] = ornt[0];
5698       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
5699       orntNew[1] = ornt[1];
5700       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
5701       orntNew[2] = 0;
5702       coneNew[3] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
5703       orntNew[3] = -2;
5704       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5705       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5706 #if 1
5707       if ((newp+1 < fStartNew) || (newp+1 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+1, fStartNew, fEndNew);
5708       for (p = 0; p < 4; ++p) {
5709         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5710       }
5711 #endif
5712       /* C quad */
5713       coneNew[0] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
5714       orntNew[0] = ornt[1];
5715       coneNew[1] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
5716       orntNew[1] = ornt[2];
5717       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
5718       orntNew[2] = 0;
5719       coneNew[3] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
5720       orntNew[3] = -2;
5721       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5722       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5723 #if 1
5724       if ((newp+2 < fStartNew) || (newp+2 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+2, fStartNew, fEndNew);
5725       for (p = 0; p < 4; ++p) {
5726         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5727       }
5728 #endif
5729       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5730       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5731       for (r = 0; r < 3; ++r) {
5732         for (s = 0; s < supportSize; ++s) {
5733           PetscInt subf;
5734 
5735           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5736           if (coneSize != 5 && support[s] >= cMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
5737           if (coneSize != 4 && support[s] <  cMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
5738           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5739           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5740           for (c = 0; c < coneSize; ++c) {
5741             if (cone[c] == f) break;
5742           }
5743           subf = GetTriSubfaceInverse_Static(ornt[c], r);
5744           if (coneSize == 4) {
5745             supportRef[s] = cStartNew + (support[s] - cStart)*4 + faces[c*3+subf];
5746           } else if (coneSize == 5) {
5747             if (c != 0 && c != 1) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected position %D in cone %D of cell %D (cMax %D) for face %D", c, support[s], cMax, f);
5748             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*3 + subf;
5749           } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
5750         }
5751         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
5752 #if 1
5753         if ((newp+r < fStartNew) || (newp+r >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+r, fStartNew, fEndNew);
5754         for (p = 0; p < supportSize; ++p) {
5755           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
5756         }
5757 #endif
5758       }
5759     }
5760     /* Interior faces have 4 edges and 2 cells */
5761     for (c = cStart; c < cMax; ++c) {
5762       PetscInt        newp = fStartNew + (fMax - fStart)*3 + (c - cStart)*6;
5763       const PetscInt *cone, *ornt;
5764       PetscInt        coneNew[4], orntNew[4];
5765       PetscInt        supportNew[2];
5766 
5767       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5768 #if 1
5769       for (p = 0; p < 4; ++p) {
5770         if (cone[p] >= fMax) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position %D for face %D", cone[p], p, fMax, f);
5771       }
5772 #endif
5773       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5774       /* Face {a, g, m, h} */
5775       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],0);
5776       orntNew[0] = 0;
5777       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 0;
5778       orntNew[1] = 0;
5779       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 1;
5780       orntNew[2] = -2;
5781       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],2);
5782       orntNew[3] = -2;
5783       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5784       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5785 #if 1
5786       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5787       for (p = 0; p < 4; ++p) {
5788         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5789       }
5790 #endif
5791       supportNew[0] = cStartNew + (c - cStart)*4 + 0;
5792       supportNew[1] = cStartNew + (c - cStart)*4 + 1;
5793       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5794 #if 1
5795       for (p = 0; p < 2; ++p) {
5796         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
5797       }
5798 #endif
5799       ++newp;
5800       /* Face {g, b, l , m} */
5801       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],1);
5802       orntNew[0] = -2;
5803       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],0);
5804       orntNew[1] = 0;
5805       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 3;
5806       orntNew[2] = 0;
5807       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 0;
5808       orntNew[3] = -2;
5809       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5810       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5811 #if 1
5812       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5813       for (p = 0; p < 4; ++p) {
5814         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5815       }
5816 #endif
5817       supportNew[0] = cStartNew + (c - cStart)*4 + 1;
5818       supportNew[1] = cStartNew + (c - cStart)*4 + 2;
5819       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5820 #if 1
5821       for (p = 0; p < 2; ++p) {
5822         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
5823       }
5824 #endif
5825       ++newp;
5826       /* Face {c, g, m, i} */
5827       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],2);
5828       orntNew[0] = 0;
5829       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 0;
5830       orntNew[1] = 0;
5831       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 2;
5832       orntNew[2] = -2;
5833       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],0);
5834       orntNew[3] = -2;
5835       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5836       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5837 #if 1
5838       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5839       for (p = 0; p < 4; ++p) {
5840         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5841       }
5842 #endif
5843       supportNew[0] = cStartNew + (c - cStart)*4 + 0;
5844       supportNew[1] = cStartNew + (c - cStart)*4 + 2;
5845       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5846 #if 1
5847       for (p = 0; p < 2; ++p) {
5848         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
5849       }
5850 #endif
5851       ++newp;
5852       /* Face {d, h, m, i} */
5853       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],0);
5854       orntNew[0] = 0;
5855       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 1;
5856       orntNew[1] = 0;
5857       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 2;
5858       orntNew[2] = -2;
5859       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],2);
5860       orntNew[3] = -2;
5861       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5862       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5863 #if 1
5864       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5865       for (p = 0; p < 4; ++p) {
5866         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5867       }
5868 #endif
5869       supportNew[0] = cStartNew + (c - cStart)*4 + 0;
5870       supportNew[1] = cStartNew + (c - cStart)*4 + 3;
5871       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5872 #if 1
5873       for (p = 0; p < 2; ++p) {
5874         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
5875       }
5876 #endif
5877       ++newp;
5878       /* Face {h, m, l, e} */
5879       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 1;
5880       orntNew[0] = 0;
5881       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 3;
5882       orntNew[1] = -2;
5883       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],1);
5884       orntNew[2] = -2;
5885       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],1);
5886       orntNew[3] = 0;
5887       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5888       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5889 #if 1
5890       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5891       for (p = 0; p < 4; ++p) {
5892         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5893       }
5894 #endif
5895       supportNew[0] = cStartNew + (c - cStart)*4 + 1;
5896       supportNew[1] = cStartNew + (c - cStart)*4 + 3;
5897       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5898 #if 1
5899       for (p = 0; p < 2; ++p) {
5900         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
5901       }
5902 #endif
5903       ++newp;
5904       /* Face {i, m, l, f} */
5905       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 2;
5906       orntNew[0] = 0;
5907       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 3;
5908       orntNew[1] = -2;
5909       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],2);
5910       orntNew[2] = -2;
5911       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],1);
5912       orntNew[3] = 0;
5913       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5914       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5915 #if 1
5916       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5917       for (p = 0; p < 4; ++p) {
5918         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5919       }
5920 #endif
5921       supportNew[0] = cStartNew + (c - cStart)*4 + 2;
5922       supportNew[1] = cStartNew + (c - cStart)*4 + 3;
5923       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5924 #if 1
5925       for (p = 0; p < 2; ++p) {
5926         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
5927       }
5928 #endif
5929       ++newp;
5930     }
5931     /* Hybrid split faces have 4 edges and same cells */
5932     for (f = fMax; f < fEnd; ++f) {
5933       const PetscInt *cone, *ornt, *support;
5934       PetscInt        coneNew[4], orntNew[4];
5935       PetscInt        size, s;
5936       const PetscInt  newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (f - fMax)*2;
5937 
5938       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5939 #if 1
5940       if (cone[0] >= eMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid edge %D (eMax %D) in cone position 0 for face %D", cone[0], eMax, f);
5941       if (cone[1] >= eMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid edge %D (eMax %D) in cone position 1 for face %D", cone[1], eMax, f);
5942       if (cone[2] <  eMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected edge %D (eMax %D) in cone position 2 for face %D", cone[2], eMax, f);
5943       if (cone[3] <  eMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected edge %D (eMax %D) in cone position 3 for face %D", cone[3], eMax, f);
5944 #endif
5945       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
5946       /* A face */
5947       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
5948       orntNew[0] = ornt[0];
5949       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (f - fMax);
5950       orntNew[1] = 0;
5951       coneNew[2] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
5952       orntNew[2] = ornt[1] < 0 ? 0 : -2;
5953       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (cone[2] - eMax);
5954       orntNew[3] = ornt[2] < 0 ? 0 : -2;
5955       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5956       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5957 #if 1
5958       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5959       for (p = 0; p < 4; ++p) {
5960         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5961       }
5962 #endif
5963 
5964       /* B face */
5965       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
5966       orntNew[0] = ornt[0];
5967       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (cone[3] - eMax);
5968       orntNew[1] = ornt[3];
5969       coneNew[2] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
5970       orntNew[2] = ornt[1] < 0 ? 0 : -2;
5971       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (f - fMax);
5972       orntNew[3] = -2;
5973       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5974       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5975 #if 1
5976       if ((newp+1 < fStartNew) || (newp+1 >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+1, fStartNew, fEndNew);
5977       for (p = 0; p < 4; ++p) {
5978         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5979       }
5980 #endif
5981 
5982       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5983       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5984       for (r = 0; r < 2; ++r) {
5985         for (s = 0; s < size; ++s) {
5986           const PetscInt *coneCell, *orntCell, *fornt;
5987           PetscInt        coneSize, o, of, c;
5988 
5989           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5990           if (coneSize != 5 || support[s] < cMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
5991           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
5992           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
5993           o = orntCell[0] < 0 ? -1 : 1;
5994           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
5995           if (c == 0 || c == 1) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected position in cone %D of cell %D (cMax %D) for face %D", c, support[s], cMax, f);
5996           if (c == coneSize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
5997           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
5998           of = fornt[c-2] < 0 ? -1 : 1;
5999           supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*3 + (GetTriEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%3;
6000         }
6001         ierr = DMPlexSetSupport(rdm, newp + r, supportRef);CHKERRQ(ierr);
6002 #if 1
6003         for (p = 0; p < size; ++p) {
6004           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
6005         }
6006 #endif
6007       }
6008     }
6009     /* Interior hybrid faces have 4 edges and 2 cells */
6010     for (c = cMax; c < cEnd; ++c) {
6011       PetscInt        newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3;
6012       const PetscInt *cone, *ornt;
6013       PetscInt        coneNew[4], orntNew[4];
6014       PetscInt        supportNew[2];
6015 
6016       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6017 #if 1
6018       if (cone[0] >= fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position 0 for cell %D", cone[0], fMax, c);
6019       if (cone[1] >= fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position 1 for cell %D", cone[1], fMax, c);
6020       if (cone[2] <  fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected face %D (fMax %D) in cone position 2 for cell %D", cone[2], fMax, c);
6021       if (cone[3] <  fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected face %D (fMax %D) in cone position 3 for cell %D", cone[3], fMax, c);
6022       if (cone[4] <  fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected face %D (fMax %D) in cone position 3 for cell %D", cone[3], fMax, c);
6023 #endif
6024       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6025       /* Face {a, g, h, d} */
6026       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],0);
6027       orntNew[0] = 0;
6028       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + c - cMax;
6029       orntNew[1] = 0;
6030       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],0);
6031       orntNew[2] = -2;
6032       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (cone[2] - fMax);
6033       orntNew[3] = -2;
6034       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6035       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6036 #if 1
6037       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6038       for (p = 0; p < 4; ++p) {
6039         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
6040       }
6041 #endif
6042       supportNew[0] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 0;
6043       supportNew[1] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 1;
6044       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6045 #if 1
6046       for (p = 0; p < 2; ++p) {
6047         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
6048       }
6049 #endif
6050       ++newp;
6051       /* Face {b, g, h, l} */
6052       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],1);
6053       orntNew[0] = 0;
6054       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + c - cMax;
6055       orntNew[1] = 0;
6056       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],1);
6057       orntNew[2] = -2;
6058       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (cone[3] - fMax);
6059       orntNew[3] = -2;
6060       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6061       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6062 #if 1
6063       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6064       for (p = 0; p < 4; ++p) {
6065         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
6066       }
6067 #endif
6068       supportNew[0] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 1;
6069       supportNew[1] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 2;
6070       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6071 #if 1
6072       for (p = 0; p < 2; ++p) {
6073         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
6074       }
6075 #endif
6076       ++newp;
6077       /* Face {c, g, h, f} */
6078       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],2);
6079       orntNew[0] = 0;
6080       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + c - cMax;
6081       orntNew[1] = 0;
6082       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],2);
6083       orntNew[2] = -2;
6084       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (cone[4] - fMax);
6085       orntNew[3] = -2;
6086       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6087       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6088 #if 1
6089       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6090       for (p = 0; p < 4; ++p) {
6091         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
6092       }
6093 #endif
6094       supportNew[0] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 2;
6095       supportNew[1] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 0;
6096       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6097 #if 1
6098       for (p = 0; p < 2; ++p) {
6099         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
6100       }
6101 #endif
6102     }
6103     /* Face edges have 2 vertices and 2 + cell faces supports */
6104     for (f = fStart; f < fMax; ++f) {
6105       const PetscInt *cone, *ornt, *support;
6106       PetscInt        coneSize, supportSize, s;
6107 
6108       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6109       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6110       for (r = 0; r < 3; ++r) {
6111         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
6112         PetscInt        coneNew[2];
6113         PetscInt        fint[4][3] = { {0, 1, 2},
6114                                        {3, 4, 0},
6115                                        {2, 5, 3},
6116                                        {1, 4, 5} };
6117 
6118         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6119         if (cone[r] >= eMax) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected cone point %D in position %D for face %D (eMax %D)", cone[r], r, f, eMax);
6120         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
6121         coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + f - fStart;
6122         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6123 #if 1
6124         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
6125         for (p = 0; p < 2; ++p) {
6126           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6127         }
6128 #endif
6129         supportRef[0] = fStartNew + (f - fStart)*3 + (r+0)%3;
6130         supportRef[1] = fStartNew + (f - fStart)*3 + (r+1)%3;
6131         for (s = 0; s < supportSize; ++s) {
6132           PetscInt er;
6133 
6134           supportRef[2+s] = -1;
6135           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6136           if (coneSize != 5 && support[s] >= cMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
6137           if (coneSize != 4 && support[s] <  cMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
6138           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6139           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
6140           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
6141           er = GetTriInteriorEdgeInverse_Static(ornt[c], r);
6142           if (coneSize == 4) {
6143             supportRef[2+s] = fStartNew + (fMax - fStart)*3 + (support[s] - cStart)*6 + fint[c][er];
6144           } else if (coneSize == 5) {
6145             if (c != 0 && c != 1) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected position %D in cone %D of cell %D (cMax %D) for face %D", c, support[s], cMax, f);
6146             supportRef[2+s] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + er;
6147           }
6148         }
6149         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6150 #if 1
6151         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
6152         for (p = 0; p < supportSize + 2; ++p) {
6153           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6154         }
6155 #endif
6156       }
6157     }
6158     /* Interior cell edges have 2 vertices and 3 faces */
6159     for (c = cStart; c < cMax; ++c) {
6160       const PetscInt *cone;
6161       PetscInt       fint[4][3] = { {0,1,2},
6162                                     {0,3,4},
6163                                     {2,3,5},
6164                                     {1,4,5} } ;
6165 
6166       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6167       for (r = 0; r < 4; r++) {
6168         PetscInt       coneNew[2], supportNew[3];
6169         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + r;
6170 
6171         if (cone[r] >= fMax) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position %D for cell %D", cone[r], r, fMax, c);
6172         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
6173         coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax     -fStart) + c - cStart;
6174         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6175 #if 1
6176         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
6177         for (p = 0; p < 2; ++p) {
6178           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6179         }
6180 #endif
6181         supportNew[0] = fStartNew + (fMax - fStart)*3 + (c - cStart)*6 + fint[r][0];
6182         supportNew[1] = fStartNew + (fMax - fStart)*3 + (c - cStart)*6 + fint[r][1];
6183         supportNew[2] = fStartNew + (fMax - fStart)*3 + (c - cStart)*6 + fint[r][2];
6184         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6185 #if 1
6186         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
6187         for (p = 0; p < 3; ++p) {
6188           if ((supportNew[p] < fStartNew) || (supportNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportNew[p], fStartNew, fEndNew);
6189         }
6190 #endif
6191       }
6192     }
6193     /* Hybrid edges have two vertices and the same faces */
6194     for (e = eMax; e < eEnd; ++e) {
6195       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (e - eMax);
6196       const PetscInt *cone, *support, *fcone;
6197       PetscInt        coneNew[2], size, fsize, s;
6198 
6199       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6200       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
6201       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
6202       coneNew[0] = vStartNew + (cone[0] - vStart);
6203       coneNew[1] = vStartNew + (cone[1] - vStart);
6204       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6205 #if 1
6206       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is a edge [%d, %d)", newp, eStartNew, eEndNew);
6207       for (p = 0; p < 2; ++p) {
6208         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6209       }
6210 #endif
6211       for (s = 0; s < size; ++s) {
6212         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
6213         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
6214         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
6215         if ((c < 2) || (c > 3)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
6216         supportRef[s] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (support[s] - fMax)*2 + c-2;
6217       }
6218       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6219 #if 1
6220       for (p = 0; p < size; ++p) {
6221         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6222       }
6223 #endif
6224     }
6225     /* Hybrid face edges have 2 vertices and 2 + cell faces supports */
6226     for (f = fMax; f < fEnd; ++f) {
6227       const PetscInt *cone, *ornt, *support;
6228       PetscInt        coneSize, supportSize;
6229       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + f - fMax;
6230       PetscInt        coneNew[2], s;
6231 
6232       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6233 #if 1
6234       if (cone[0] >= eMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected cone point %D in position 0 for face %D (eMax %D)", cone[0], f, eMax);
6235       if (cone[1] >= eMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected cone point %D in position 1 for face %D (eMax %D)", cone[1], f, eMax);
6236 #endif
6237       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
6238       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
6239       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6240 #if 1
6241       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
6242       for (p = 0; p < 2; ++p) {
6243         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6244       }
6245 #endif
6246       supportRef[0] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (f- fMax)*2 + 0;
6247       supportRef[1] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (f- fMax)*2 + 1;
6248       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6249       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6250       for (s = 0; s < supportSize; ++s) {
6251         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6252         if (coneSize != 5 || support[s] < cMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
6253         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6254         ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
6255         for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
6256         if (c == 0 || c == 1) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected position in cone %D of cell %D (cMax %D) for face %D", c, support[s], cMax, f);
6257         supportRef[2+s] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + c - 2;
6258       }
6259       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6260 #if 1
6261       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
6262       for (p = 0; p < supportSize + 2; ++p) {
6263         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6264       }
6265 #endif
6266     }
6267     /* Hybrid cell edges have 2 vertices and 3 faces */
6268     for (c = cMax; c < cEnd; ++c) {
6269       PetscInt       coneNew[2], supportNew[3];
6270       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + c - cMax;
6271       const PetscInt *cone;
6272 
6273       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6274 #if 1
6275       if (cone[0] >= fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position 0 for cell %D", cone[0], fMax, c);
6276       if (cone[1] >= fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected hybrid face %D (fMax %D) in cone position 1 for cell %D", cone[1], fMax, c);
6277 #endif
6278       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
6279       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
6280       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6281 #if 1
6282       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
6283       for (p = 0; p < 2; ++p) {
6284         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6285       }
6286 #endif
6287       supportNew[0] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
6288       supportNew[1] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
6289       supportNew[2] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
6290       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6291 #if 1
6292       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
6293       for (p = 0; p < 3; ++p) {
6294         if ((supportNew[p] < fStartNew) || (supportNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportNew[p], fStartNew, fEndNew);
6295       }
6296 #endif
6297     }
6298     /* Old vertices have identical supports */
6299     for (v = vStart; v < vEnd; ++v) {
6300       const PetscInt  newp = vStartNew + (v - vStart);
6301       const PetscInt *support, *cone;
6302       PetscInt        size, s;
6303 
6304       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6305       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6306       for (s = 0; s < size; ++s) {
6307         const PetscInt e = support[s];
6308 
6309         supportRef[s] = -1;
6310         if (eStart <= e) {
6311           if (e < eMax) {
6312             ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6313             supportRef[s] = eStartNew + (e - eStart)*2 + (cone[1] == v ? 1 : 0);
6314           } else if (e < eEnd) {
6315             supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + e - eMax;
6316           } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", e, eStart, eEnd);
6317         } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", e, eStart, eEnd);
6318       }
6319       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6320 #if 1
6321       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6322       for (p = 0; p < size; ++p) {
6323         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
6324       }
6325 #endif
6326     }
6327     /* Interior edge vertices have 2 + faces supports */
6328     for (e = eStart; e < eMax; ++e) {
6329       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
6330       const PetscInt *cone, *support;
6331       PetscInt        size, s;
6332 
6333       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
6334       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
6335       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
6336       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
6337       for (s = 0; s < size; ++s) {
6338         PetscInt r, coneSize;
6339 
6340         supportRef[2+s] = -1;
6341         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6342         if (coneSize != 4 && support[s] >= fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for face %D (fMax %D)", coneSize, support[s], fMax);
6343         if (coneSize != 3 && support[s] <  fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for face %D (fMax %D)", coneSize, support[s], fMax);
6344         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6345         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
6346         if (coneSize == 3) supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + r;
6347         else if (coneSize == 4) {
6348           if (r != 0 && r != 1) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected position in cone %D of face %D (fMax %D) for edge %D", r, support[s], fMax, e);
6349           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + support[s] - fMax;
6350         } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for face %D (fMax %D)", coneSize, support[s], fMax);
6351       }
6352       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6353 #if 1
6354       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6355       for (p = 0; p < 2+size; ++p) {
6356         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
6357       }
6358 #endif
6359     }
6360     /* Split Edges have 2 vertices and the same faces as the parent */
6361     for (e = eStart; e < eMax; ++e) {
6362       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
6363 
6364       for (r = 0; r < 2; ++r) {
6365         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
6366         const PetscInt *cone, *ornt, *support;
6367         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6368 
6369         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6370         coneNew[0]       = vStartNew + (cone[0] - vStart);
6371         coneNew[1]       = vStartNew + (cone[1] - vStart);
6372         coneNew[(r+1)%2] = newv;
6373         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6374 #if 1
6375         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
6376         for (p = 0; p < 2; ++p) {
6377           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6378         }
6379 #endif
6380         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
6381         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
6382         for (s = 0; s < supportSize; ++s) {
6383           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6384           if (coneSize != 4 && support[s] >= fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for face %D (fMax %D)", coneSize, support[s], fMax);
6385           if (coneSize != 3 && support[s] <  fMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for face %D (fMax %D)", coneSize, support[s], fMax);
6386           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6387           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
6388           for (c = 0; c < coneSize; ++c) {
6389             if (cone[c] == e) break;
6390           }
6391           if (coneSize == 3) supportRef[s] = fStartNew + (support[s] - fStart)*3 + (c + (ornt[c] < 0 ? 1-r : r))%3;
6392           else if (coneSize == 4) {
6393             if (c != 0 && c != 1) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected position in cone %D of face %D (fMax %D) for edge %D", c, support[s], fMax, e);
6394             supportRef[s] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
6395           } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for face %D (fMax %D)", coneSize, support[s], fMax);
6396         }
6397         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6398 #if 1
6399         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
6400         for (p = 0; p < supportSize; ++p) {
6401           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6402         }
6403 #endif
6404       }
6405     }
6406     /* Face vertices have 3 + cells supports */
6407     for (f = fStart; f < fMax; ++f) {
6408       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
6409       const PetscInt *cone, *support;
6410       PetscInt        size, s;
6411 
6412       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6413       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6414       supportRef[0] = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + 0;
6415       supportRef[1] = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + 1;
6416       supportRef[2] = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + 2;
6417       for (s = 0; s < size; ++s) {
6418         PetscInt r, coneSize;
6419 
6420         supportRef[3+s] = -1;
6421         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6422         if (coneSize != 5 && support[s] >= cMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
6423         if (coneSize != 4 && support[s] <  cMax) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
6424         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6425         for (r = 0; r < coneSize; ++r) {if (cone[r] == f) break;}
6426         if (coneSize == 4) supportRef[3+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (support[s] - cStart)*4 + r;
6427         else if (coneSize == 5) {
6428           if (r != 0 && r != 1) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected position in cone %D of cell %D (cMax %D) for face %D", r, support[s], cMax, f);
6429           supportRef[3+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + support[s] - cMax;
6430         }
6431       }
6432       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6433 #if 1
6434       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6435       for (p = 0; p < 3+size; ++p) {
6436         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
6437       }
6438 #endif
6439     }
6440     /* Interior cell vertices have 4 supports */
6441     for (c = cStart; c < cMax; ++c) {
6442       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + c - cStart;
6443 
6444       supportRef[0] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 0;
6445       supportRef[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 1;
6446       supportRef[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 2;
6447       supportRef[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 3;
6448       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6449 #if 1
6450       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6451       for (p = 0; p < 4; ++p) {
6452         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
6453       }
6454 #endif
6455     }
6456     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6457     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
6458     break;
6459   case REFINER_HEX_3D:
6460     /*
6461      Bottom (viewed from top)    Top
6462      1---------2---------2       7---------2---------6
6463      |         |         |       |         |         |
6464      |    B    2    C    |       |    H    2    G    |
6465      |         |         |       |         |         |
6466      3----3----0----1----1       3----3----0----1----1
6467      |         |         |       |         |         |
6468      |    A    0    D    |       |    E    0    F    |
6469      |         |         |       |         |         |
6470      0---------0---------3       4---------0---------5
6471      */
6472     /* All cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
6473     for (c = cStart; c < cEnd; ++c) {
6474       const PetscInt  newp = (c - cStart)*8;
6475       const PetscInt *cone, *ornt;
6476       PetscInt        coneNew[6], orntNew[6];
6477 
6478       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6479       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6480       /* A hex */
6481       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
6482       orntNew[0] = ornt[0];
6483       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
6484       orntNew[1] = 0;
6485       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
6486       orntNew[2] = ornt[2];
6487       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
6488       orntNew[3] = 0;
6489       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
6490       orntNew[4] = 0;
6491       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
6492       orntNew[5] = ornt[5];
6493       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6494       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6495 #if 1
6496       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
6497       for (p = 0; p < 6; ++p) {
6498         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6499       }
6500 #endif
6501       /* B hex */
6502       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
6503       orntNew[0] = ornt[0];
6504       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
6505       orntNew[1] = 0;
6506       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
6507       orntNew[2] = -1;
6508       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
6509       orntNew[3] = ornt[3];
6510       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
6511       orntNew[4] = 0;
6512       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
6513       orntNew[5] = ornt[5];
6514       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6515       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6516 #if 1
6517       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
6518       for (p = 0; p < 6; ++p) {
6519         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6520       }
6521 #endif
6522       /* C hex */
6523       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
6524       orntNew[0] = ornt[0];
6525       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
6526       orntNew[1] = 0;
6527       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
6528       orntNew[2] = -1;
6529       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
6530       orntNew[3] = ornt[3];
6531       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
6532       orntNew[4] = ornt[4];
6533       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
6534       orntNew[5] = -4;
6535       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6536       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6537 #if 1
6538       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
6539       for (p = 0; p < 6; ++p) {
6540         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6541       }
6542 #endif
6543       /* D hex */
6544       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
6545       orntNew[0] = ornt[0];
6546       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
6547       orntNew[1] = 0;
6548       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
6549       orntNew[2] = ornt[2];
6550       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
6551       orntNew[3] = 0;
6552       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
6553       orntNew[4] = ornt[4];
6554       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
6555       orntNew[5] = -4;
6556       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6557       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6558 #if 1
6559       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
6560       for (p = 0; p < 6; ++p) {
6561         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6562       }
6563 #endif
6564       /* E hex */
6565       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
6566       orntNew[0] = -4;
6567       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
6568       orntNew[1] = ornt[1];
6569       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
6570       orntNew[2] = ornt[2];
6571       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
6572       orntNew[3] = 0;
6573       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
6574       orntNew[4] = -1;
6575       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
6576       orntNew[5] = ornt[5];
6577       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
6578       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
6579 #if 1
6580       if ((newp+4 < cStartNew) || (newp+4 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+4, cStartNew, cEndNew);
6581       for (p = 0; p < 6; ++p) {
6582         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6583       }
6584 #endif
6585       /* F hex */
6586       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
6587       orntNew[0] = -4;
6588       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
6589       orntNew[1] = ornt[1];
6590       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
6591       orntNew[2] = ornt[2];
6592       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
6593       orntNew[3] = -1;
6594       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
6595       orntNew[4] = ornt[4];
6596       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
6597       orntNew[5] = 1;
6598       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
6599       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
6600 #if 1
6601       if ((newp+5 < cStartNew) || (newp+5 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+5, cStartNew, cEndNew);
6602       for (p = 0; p < 6; ++p) {
6603         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6604       }
6605 #endif
6606       /* G hex */
6607       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
6608       orntNew[0] = -4;
6609       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
6610       orntNew[1] = ornt[1];
6611       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
6612       orntNew[2] = 0;
6613       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
6614       orntNew[3] = ornt[3];
6615       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
6616       orntNew[4] = ornt[4];
6617       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
6618       orntNew[5] = -3;
6619       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
6620       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
6621 #if 1
6622       if ((newp+6 < cStartNew) || (newp+6 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+6, cStartNew, cEndNew);
6623       for (p = 0; p < 6; ++p) {
6624         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6625       }
6626 #endif
6627       /* H hex */
6628       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
6629       orntNew[0] = -4;
6630       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
6631       orntNew[1] = ornt[1];
6632       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
6633       orntNew[2] = -1;
6634       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
6635       orntNew[3] = ornt[3];
6636       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
6637       orntNew[4] = 3;
6638       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
6639       orntNew[5] = ornt[5];
6640       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
6641       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
6642 #if 1
6643       if ((newp+7 < cStartNew) || (newp+7 >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+7, cStartNew, cEndNew);
6644       for (p = 0; p < 6; ++p) {
6645         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6646       }
6647 #endif
6648     }
6649     /* Split faces have 4 edges and the same cells as the parent */
6650     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6651     ierr = PetscMalloc1(4 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
6652     for (f = fStart; f < fEnd; ++f) {
6653       for (r = 0; r < 4; ++r) {
6654         /* TODO: This can come from GetFaces_Internal() */
6655         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};
6656         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
6657         const PetscInt *cone, *ornt, *support;
6658         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
6659 
6660         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6661         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
6662         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
6663         orntNew[(r+3)%4] = ornt[(r+3)%4];
6664         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
6665         orntNew[(r+0)%4] = ornt[r];
6666         coneNew[(r+1)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
6667         orntNew[(r+1)%4] = 0;
6668         coneNew[(r+2)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + (r+3)%4;
6669         orntNew[(r+2)%4] = -2;
6670         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6671         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6672 #if 1
6673         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6674         for (p = 0; p < 4; ++p) {
6675           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
6676         }
6677 #endif
6678         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6679         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6680         for (s = 0; s < supportSize; ++s) {
6681           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6682           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6683           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
6684           for (c = 0; c < coneSize; ++c) {
6685             if (cone[c] == f) break;
6686           }
6687           supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+GetQuadSubfaceInverse_Static(ornt[c], r)];
6688         }
6689         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6690 #if 1
6691         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6692         for (p = 0; p < supportSize; ++p) {
6693           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
6694         }
6695 #endif
6696       }
6697     }
6698     /* Interior faces have 4 edges and 2 cells */
6699     for (c = cStart; c < cEnd; ++c) {
6700       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};
6701       const PetscInt *cone, *ornt;
6702       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
6703 
6704       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6705       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6706       /* A-D face */
6707       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 0;
6708       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
6709       orntNew[0] = 0;
6710       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
6711       orntNew[1] = 0;
6712       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
6713       orntNew[2] = -2;
6714       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
6715       orntNew[3] = -2;
6716       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6717       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6718 #if 1
6719       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6720       for (p = 0; p < 4; ++p) {
6721         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
6722       }
6723 #endif
6724       /* C-D face */
6725       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 1;
6726       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
6727       orntNew[0] = 0;
6728       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
6729       orntNew[1] = 0;
6730       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
6731       orntNew[2] = -2;
6732       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
6733       orntNew[3] = -2;
6734       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6735       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6736 #if 1
6737       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6738       for (p = 0; p < 4; ++p) {
6739         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
6740       }
6741 #endif
6742       /* B-C face */
6743       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 2;
6744       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
6745       orntNew[0] = -2;
6746       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
6747       orntNew[1] = 0;
6748       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
6749       orntNew[2] = 0;
6750       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
6751       orntNew[3] = -2;
6752       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6753       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6754 #if 1
6755       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6756       for (p = 0; p < 4; ++p) {
6757         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
6758       }
6759 #endif
6760       /* A-B face */
6761       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 3;
6762       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
6763       orntNew[0] = -2;
6764       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
6765       orntNew[1] = 0;
6766       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
6767       orntNew[2] = 0;
6768       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
6769       orntNew[3] = -2;
6770       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6771       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6772 #if 1
6773       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6774       for (p = 0; p < 4; ++p) {
6775         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
6776       }
6777 #endif
6778       /* E-F face */
6779       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 4;
6780       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
6781       orntNew[0] = -2;
6782       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
6783       orntNew[1] = -2;
6784       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
6785       orntNew[2] = 0;
6786       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
6787       orntNew[3] = 0;
6788       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6789       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6790 #if 1
6791       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6792       for (p = 0; p < 4; ++p) {
6793         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
6794       }
6795 #endif
6796       /* F-G face */
6797       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 5;
6798       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
6799       orntNew[0] = -2;
6800       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
6801       orntNew[1] = -2;
6802       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
6803       orntNew[2] = 0;
6804       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
6805       orntNew[3] = 0;
6806       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6807       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6808 #if 1
6809       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6810       for (p = 0; p < 4; ++p) {
6811         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
6812       }
6813 #endif
6814       /* G-H face */
6815       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 6;
6816       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
6817       orntNew[0] = -2;
6818       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
6819       orntNew[1] = 0;
6820       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
6821       orntNew[2] = 0;
6822       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
6823       orntNew[3] = -2;
6824       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6825       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6826 #if 1
6827       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6828       for (p = 0; p < 4; ++p) {
6829         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
6830       }
6831 #endif
6832       /* E-H face */
6833       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 7;
6834       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
6835       orntNew[0] = -2;
6836       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
6837       orntNew[1] = -2;
6838       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
6839       orntNew[2] = 0;
6840       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
6841       orntNew[3] = 0;
6842       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6843       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6844 #if 1
6845       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6846       for (p = 0; p < 4; ++p) {
6847         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
6848       }
6849 #endif
6850       /* A-E face */
6851       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 8;
6852       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
6853       orntNew[0] = 0;
6854       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
6855       orntNew[1] = 0;
6856       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
6857       orntNew[2] = -2;
6858       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
6859       orntNew[3] = -2;
6860       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6861       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6862 #if 1
6863       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6864       for (p = 0; p < 4; ++p) {
6865         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
6866       }
6867 #endif
6868       /* D-F face */
6869       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 9;
6870       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
6871       orntNew[0] = -2;
6872       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
6873       orntNew[1] = 0;
6874       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
6875       orntNew[2] = 0;
6876       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
6877       orntNew[3] = -2;
6878       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6879       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6880 #if 1
6881       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6882       for (p = 0; p < 4; ++p) {
6883         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
6884       }
6885 #endif
6886       /* C-G face */
6887       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 10;
6888       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
6889       orntNew[0] = -2;
6890       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
6891       orntNew[1] = -2;
6892       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
6893       orntNew[2] = 0;
6894       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
6895       orntNew[3] = 0;
6896       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6897       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6898 #if 1
6899       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6900       for (p = 0; p < 4; ++p) {
6901         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
6902       }
6903 #endif
6904       /* B-H face */
6905       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 11;
6906       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
6907       orntNew[0] = 0;
6908       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
6909       orntNew[1] = -2;
6910       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
6911       orntNew[2] = -2;
6912       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
6913       orntNew[3] = 0;
6914       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6915       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6916 #if 1
6917       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6918       for (p = 0; p < 4; ++p) {
6919         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
6920       }
6921 #endif
6922       for (r = 0; r < 12; ++r) {
6923         newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
6924         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
6925         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
6926         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6927 #if 1
6928         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6929         for (p = 0; p < 2; ++p) {
6930           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
6931         }
6932 #endif
6933       }
6934     }
6935     /* Split edges have 2 vertices and the same faces as the parent */
6936     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6937     for (e = eStart; e < eEnd; ++e) {
6938       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
6939 
6940       for (r = 0; r < 2; ++r) {
6941         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
6942         const PetscInt *cone, *ornt, *support;
6943         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6944 
6945         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6946         coneNew[0]       = vStartNew + (cone[0] - vStart);
6947         coneNew[1]       = vStartNew + (cone[1] - vStart);
6948         coneNew[(r+1)%2] = newv;
6949         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6950 #if 1
6951         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
6952         for (p = 0; p < 2; ++p) {
6953           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6954         }
6955 #endif
6956         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
6957         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
6958         for (s = 0; s < supportSize; ++s) {
6959           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6960           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6961           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
6962           for (c = 0; c < coneSize; ++c) {
6963             if (cone[c] == e) break;
6964           }
6965           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
6966         }
6967         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6968 #if 1
6969         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
6970         for (p = 0; p < supportSize; ++p) {
6971           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6972         }
6973 #endif
6974       }
6975     }
6976     /* Face edges have 2 vertices and 2+cells faces */
6977     for (f = fStart; f < fEnd; ++f) {
6978       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};
6979       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
6980       const PetscInt *cone, *coneCell, *orntCell, *support;
6981       PetscInt        coneNew[2], coneSize, c, supportSize, s;
6982 
6983       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6984       for (r = 0; r < 4; ++r) {
6985         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
6986 
6987         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
6988         coneNew[1] = newv;
6989         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6990 #if 1
6991         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
6992         for (p = 0; p < 2; ++p) {
6993           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6994         }
6995 #endif
6996         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6997         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6998         supportRef[0] = fStartNew + (f - fStart)*4 + r;
6999         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
7000         for (s = 0; s < supportSize; ++s) {
7001           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
7002           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
7003           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
7004           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
7005           supportRef[2+s] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
7006         }
7007         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7008 #if 1
7009         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
7010         for (p = 0; p < 2+supportSize; ++p) {
7011           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
7012         }
7013 #endif
7014       }
7015     }
7016     /* Cell edges have 2 vertices and 4 faces */
7017     for (c = cStart; c < cEnd; ++c) {
7018       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};
7019       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
7020       const PetscInt *cone;
7021       PetscInt        coneNew[2], supportNew[4];
7022 
7023       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7024       for (r = 0; r < 6; ++r) {
7025         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
7026 
7027         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
7028         coneNew[1] = newv;
7029         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7030 #if 1
7031         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
7032         for (p = 0; p < 2; ++p) {
7033           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
7034         }
7035 #endif
7036         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
7037         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
7038 #if 1
7039         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
7040         for (p = 0; p < 4; ++p) {
7041           if ((supportNew[p] < fStartNew) || (supportNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportNew[p], fStartNew, fEndNew);
7042         }
7043 #endif
7044       }
7045     }
7046     /* Old vertices have identical supports */
7047     for (v = vStart; v < vEnd; ++v) {
7048       const PetscInt  newp = vStartNew + (v - vStart);
7049       const PetscInt *support, *cone;
7050       PetscInt        size, s;
7051 
7052       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
7053       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
7054       for (s = 0; s < size; ++s) {
7055         PetscInt r = 0;
7056 
7057         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7058         if (cone[1] == v) r = 1;
7059         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
7060       }
7061       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7062 #if 1
7063       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
7064       for (p = 0; p < size; ++p) {
7065         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
7066       }
7067 #endif
7068     }
7069     /* Edge vertices have 2 + faces supports */
7070     for (e = eStart; e < eEnd; ++e) {
7071       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
7072       const PetscInt *cone, *support;
7073       PetscInt        size, s;
7074 
7075       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
7076       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
7077       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
7078       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
7079       for (s = 0; s < size; ++s) {
7080         PetscInt r;
7081 
7082         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7083         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
7084         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*4 + r;
7085       }
7086       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7087 #if 1
7088       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
7089       for (p = 0; p < 2+size; ++p) {
7090         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
7091       }
7092 #endif
7093     }
7094     /* Face vertices have 4 + cells supports */
7095     for (f = fStart; f < fEnd; ++f) {
7096       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
7097       const PetscInt *cone, *support;
7098       PetscInt        size, s;
7099 
7100       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
7101       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
7102       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eEnd - eStart)*2 +  (f - fStart)*4 + r;
7103       for (s = 0; s < size; ++s) {
7104         PetscInt r;
7105 
7106         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7107         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
7108         supportRef[4+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (support[s] - cStart)*6 + r;
7109       }
7110       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7111 #if 1
7112       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
7113       for (p = 0; p < 4+size; ++p) {
7114         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
7115       }
7116 #endif
7117     }
7118     /* Cell vertices have 6 supports */
7119     for (c = cStart; c < cEnd; ++c) {
7120       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
7121       PetscInt       supportNew[6];
7122 
7123       for (r = 0; r < 6; ++r) {
7124         supportNew[r] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
7125       }
7126       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
7127     }
7128     ierr = PetscFree(supportRef);CHKERRQ(ierr);
7129     break;
7130   case REFINER_HYBRID_HEX_3D:
7131     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
7132     /*
7133      Bottom (viewed from top)    Top
7134      1---------2---------2       7---------2---------6
7135      |         |         |       |         |         |
7136      |    B    2    C    |       |    H    2    G    |
7137      |         |         |       |         |         |
7138      3----3----0----1----1       3----3----0----1----1
7139      |         |         |       |         |         |
7140      |    A    0    D    |       |    E    0    F    |
7141      |         |         |       |         |         |
7142      0---------0---------3       4---------0---------5
7143      */
7144     /* Interior cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
7145     for (c = cStart; c < cMax; ++c) {
7146       const PetscInt  newp = (c - cStart)*8;
7147       const PetscInt *cone, *ornt;
7148       PetscInt        coneNew[6], orntNew[6];
7149 
7150       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7151       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
7152       /* A hex */
7153       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
7154       orntNew[0] = ornt[0];
7155       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
7156       orntNew[1] = 0;
7157       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
7158       orntNew[2] = ornt[2];
7159       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
7160       orntNew[3] = 0;
7161       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
7162       orntNew[4] = 0;
7163       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
7164       orntNew[5] = ornt[5];
7165       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
7166       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
7167 #if 1
7168       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cMaxNew);
7169       for (p = 0; p < 6; ++p) {
7170         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
7171       }
7172 #endif
7173       /* B hex */
7174       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
7175       orntNew[0] = ornt[0];
7176       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
7177       orntNew[1] = 0;
7178       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
7179       orntNew[2] = -1;
7180       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
7181       orntNew[3] = ornt[3];
7182       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
7183       orntNew[4] = 0;
7184       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
7185       orntNew[5] = ornt[5];
7186       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
7187       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
7188 #if 1
7189       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cMaxNew);
7190       for (p = 0; p < 6; ++p) {
7191         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
7192       }
7193 #endif
7194       /* C hex */
7195       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
7196       orntNew[0] = ornt[0];
7197       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
7198       orntNew[1] = 0;
7199       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
7200       orntNew[2] = -1;
7201       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
7202       orntNew[3] = ornt[3];
7203       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
7204       orntNew[4] = ornt[4];
7205       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
7206       orntNew[5] = -4;
7207       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
7208       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
7209 #if 1
7210       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cMaxNew);
7211       for (p = 0; p < 6; ++p) {
7212         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
7213       }
7214 #endif
7215       /* D hex */
7216       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
7217       orntNew[0] = ornt[0];
7218       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
7219       orntNew[1] = 0;
7220       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
7221       orntNew[2] = ornt[2];
7222       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
7223       orntNew[3] = 0;
7224       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
7225       orntNew[4] = ornt[4];
7226       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
7227       orntNew[5] = -4;
7228       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
7229       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
7230 #if 1
7231       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cMaxNew);
7232       for (p = 0; p < 6; ++p) {
7233         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
7234       }
7235 #endif
7236       /* E hex */
7237       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
7238       orntNew[0] = -4;
7239       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
7240       orntNew[1] = ornt[1];
7241       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
7242       orntNew[2] = ornt[2];
7243       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
7244       orntNew[3] = 0;
7245       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
7246       orntNew[4] = -1;
7247       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
7248       orntNew[5] = ornt[5];
7249       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
7250       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
7251 #if 1
7252       if ((newp+4 < cStartNew) || (newp+4 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+4, cStartNew, cMaxNew);
7253       for (p = 0; p < 6; ++p) {
7254         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
7255       }
7256 #endif
7257       /* F hex */
7258       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
7259       orntNew[0] = -4;
7260       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
7261       orntNew[1] = ornt[1];
7262       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
7263       orntNew[2] = ornt[2];
7264       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
7265       orntNew[3] = -1;
7266       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
7267       orntNew[4] = ornt[4];
7268       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
7269       orntNew[5] = 1;
7270       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
7271       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
7272 #if 1
7273       if ((newp+5 < cStartNew) || (newp+5 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+5, cStartNew, cMaxNew);
7274       for (p = 0; p < 6; ++p) {
7275         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
7276       }
7277 #endif
7278       /* G hex */
7279       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
7280       orntNew[0] = -4;
7281       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
7282       orntNew[1] = ornt[1];
7283       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
7284       orntNew[2] = 0;
7285       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
7286       orntNew[3] = ornt[3];
7287       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
7288       orntNew[4] = ornt[4];
7289       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
7290       orntNew[5] = -3;
7291       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
7292       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
7293 #if 1
7294       if ((newp+6 < cStartNew) || (newp+6 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+6, cStartNew, cMaxNew);
7295       for (p = 0; p < 6; ++p) {
7296         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
7297       }
7298 #endif
7299       /* H hex */
7300       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
7301       orntNew[0] = -4;
7302       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
7303       orntNew[1] = ornt[1];
7304       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
7305       orntNew[2] = -1;
7306       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
7307       orntNew[3] = ornt[3];
7308       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
7309       orntNew[4] = 3;
7310       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
7311       orntNew[5] = ornt[5];
7312       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
7313       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
7314 #if 1
7315       if ((newp+7 < cStartNew) || (newp+7 >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+7, cStartNew, cMaxNew);
7316       for (p = 0; p < 6; ++p) {
7317         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
7318       }
7319 #endif
7320     }
7321     /* Hybrid cells have 6 faces: Front, Back, Sides */
7322     /*
7323      3---------2---------2
7324      |         |         |
7325      |    D    2    C    |
7326      |         |         |
7327      3----3----0----1----1
7328      |         |         |
7329      |    A    0    B    |
7330      |         |         |
7331      0---------0---------1
7332      */
7333     for (c = cMax; c < cEnd; ++c) {
7334       const PetscInt  newp = (cMax - cStart)*8 + (c - cMax)*4;
7335       const PetscInt *cone, *ornt, *fornt;
7336       PetscInt        coneNew[6], orntNew[6], o, of, i;
7337 
7338       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7339       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
7340       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
7341       o = ornt[0] < 0 ? -1 : 1;
7342       for (r = 0; r < 4; ++r) {
7343         PetscInt subfA = GetQuadSubface_Static(ornt[0], r);
7344         PetscInt edgeA = GetQuadEdge_Static(ornt[0], r);
7345         PetscInt edgeB = GetQuadEdge_Static(ornt[0], (r+3)%4);
7346         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]);
7347         coneNew[0]         = fStartNew + (cone[0] - fStart)*4 + subfA;
7348         orntNew[0]         = ornt[0];
7349         coneNew[1]         = fStartNew + (cone[1] - fStart)*4 + subfA;
7350         orntNew[1]         = ornt[0];
7351         of = fornt[edgeA] < 0 ? -1 : 1;
7352         i  = GetQuadEdgeInverse_Static(ornt[0], r) + 2;
7353         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeA] - fMax)*2 + (o*of < 0 ? 1 : 0);
7354         orntNew[i] = ornt[edgeA];
7355         i  = GetQuadEdgeInverse_Static(ornt[0], (r+1)%4) + 2;
7356         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeA;
7357         orntNew[i] = 0;
7358         i  = GetQuadEdgeInverse_Static(ornt[0], (r+2)%4) + 2;
7359         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeB;
7360         orntNew[i] = -2;
7361         of = fornt[edgeB] < 0 ? -1 : 1;
7362         i  = GetQuadEdgeInverse_Static(ornt[0], (r+3)%4) + 2;
7363         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeB] - fMax)*2 + (o*of < 0 ? 0 : 1);
7364         orntNew[i] = ornt[edgeB];
7365         ierr       = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
7366         ierr       = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
7367 #if 1
7368         if ((newp+r < cMaxNew) || (newp+r >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", newp+r, cMaxNew, cEndNew);
7369         for (p = 0; p < 2; ++p) {
7370           if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
7371         }
7372         for (p = 2; p < 6; ++p) {
7373           if ((coneNew[p] < fMaxNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", coneNew[p], fMaxNew, fEndNew);
7374         }
7375 #endif
7376       }
7377     }
7378     /* Interior split faces have 4 edges and the same cells as the parent */
7379     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
7380     ierr = PetscMalloc1(4 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
7381     for (f = fStart; f < fMax; ++f) {
7382       for (r = 0; r < 4; ++r) {
7383         /* TODO: This can come from GetFaces_Internal() */
7384         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};
7385         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
7386         const PetscInt *cone, *ornt, *support;
7387         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
7388 
7389         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
7390         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
7391         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
7392         orntNew[(r+3)%4] = ornt[(r+3)%4];
7393         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
7394         orntNew[(r+0)%4] = ornt[r];
7395         coneNew[(r+1)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
7396         orntNew[(r+1)%4] = 0;
7397         coneNew[(r+2)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + (r+3)%4;
7398         orntNew[(r+2)%4] = -2;
7399         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7400         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7401 #if 1
7402         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
7403         for (p = 0; p < 4; ++p) {
7404           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
7405         }
7406 #endif
7407         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
7408         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
7409         for (s = 0; s < supportSize; ++s) {
7410           PetscInt subf;
7411           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
7412           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7413           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
7414           for (c = 0; c < coneSize; ++c) {
7415             if (cone[c] == f) break;
7416           }
7417           subf = GetQuadSubfaceInverse_Static(ornt[c], r);
7418           if (support[s] < cMax) {
7419             supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+subf];
7420           } else {
7421             supportRef[s] = cStartNew + (cMax       - cStart)*8 + (support[s] - cMax)*4 + subf;
7422           }
7423         }
7424         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7425 #if 1
7426         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
7427         for (p = 0; p < supportSize; ++p) {
7428           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
7429         }
7430 #endif
7431       }
7432     }
7433     /* Interior cell faces have 4 edges and 2 cells */
7434     for (c = cStart; c < cMax; ++c) {
7435       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};
7436       const PetscInt *cone, *ornt;
7437       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
7438 
7439       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7440       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
7441       /* A-D face */
7442       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 0;
7443       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
7444       orntNew[0] = 0;
7445       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
7446       orntNew[1] = 0;
7447       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
7448       orntNew[2] = -2;
7449       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
7450       orntNew[3] = -2;
7451       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7452       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7453 #if 1
7454       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
7455       for (p = 0; p < 4; ++p) {
7456         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
7457       }
7458 #endif
7459       /* C-D face */
7460       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 1;
7461       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
7462       orntNew[0] = 0;
7463       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
7464       orntNew[1] = 0;
7465       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
7466       orntNew[2] = -2;
7467       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
7468       orntNew[3] = -2;
7469       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7470       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7471 #if 1
7472       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
7473       for (p = 0; p < 4; ++p) {
7474         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
7475       }
7476 #endif
7477       /* B-C face */
7478       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 2;
7479       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
7480       orntNew[0] = -2;
7481       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
7482       orntNew[1] = 0;
7483       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
7484       orntNew[2] = 0;
7485       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
7486       orntNew[3] = -2;
7487       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7488       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7489 #if 1
7490       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
7491       for (p = 0; p < 4; ++p) {
7492         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
7493       }
7494 #endif
7495       /* A-B face */
7496       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 3;
7497       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
7498       orntNew[0] = -2;
7499       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
7500       orntNew[1] = 0;
7501       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
7502       orntNew[2] = 0;
7503       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
7504       orntNew[3] = -2;
7505       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7506       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7507 #if 1
7508       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
7509       for (p = 0; p < 4; ++p) {
7510         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
7511       }
7512 #endif
7513       /* E-F face */
7514       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 4;
7515       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
7516       orntNew[0] = -2;
7517       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
7518       orntNew[1] = -2;
7519       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
7520       orntNew[2] = 0;
7521       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
7522       orntNew[3] = 0;
7523       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7524       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7525 #if 1
7526       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
7527       for (p = 0; p < 4; ++p) {
7528         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
7529       }
7530 #endif
7531       /* F-G face */
7532       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 5;
7533       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
7534       orntNew[0] = -2;
7535       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
7536       orntNew[1] = -2;
7537       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
7538       orntNew[2] = 0;
7539       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
7540       orntNew[3] = 0;
7541       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7542       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7543 #if 1
7544       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
7545       for (p = 0; p < 4; ++p) {
7546         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
7547       }
7548 #endif
7549       /* G-H face */
7550       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 6;
7551       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
7552       orntNew[0] = -2;
7553       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
7554       orntNew[1] = 0;
7555       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
7556       orntNew[2] = 0;
7557       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
7558       orntNew[3] = -2;
7559       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7560       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7561 #if 1
7562       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
7563       for (p = 0; p < 4; ++p) {
7564         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
7565       }
7566 #endif
7567       /* E-H face */
7568       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 7;
7569       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
7570       orntNew[0] = -2;
7571       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
7572       orntNew[1] = -2;
7573       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
7574       orntNew[2] = 0;
7575       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
7576       orntNew[3] = 0;
7577       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7578       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7579 #if 1
7580       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
7581       for (p = 0; p < 4; ++p) {
7582         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
7583       }
7584 #endif
7585       /* A-E face */
7586       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 8;
7587       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
7588       orntNew[0] = 0;
7589       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
7590       orntNew[1] = 0;
7591       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
7592       orntNew[2] = -2;
7593       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
7594       orntNew[3] = -2;
7595       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7596       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7597 #if 1
7598       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
7599       for (p = 0; p < 4; ++p) {
7600         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
7601       }
7602 #endif
7603       /* D-F face */
7604       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 9;
7605       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
7606       orntNew[0] = -2;
7607       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
7608       orntNew[1] = 0;
7609       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
7610       orntNew[2] = 0;
7611       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
7612       orntNew[3] = -2;
7613       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7614       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7615 #if 1
7616       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
7617       for (p = 0; p < 4; ++p) {
7618         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
7619       }
7620 #endif
7621       /* C-G face */
7622       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 10;
7623       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
7624       orntNew[0] = -2;
7625       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
7626       orntNew[1] = -2;
7627       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
7628       orntNew[2] = 0;
7629       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
7630       orntNew[3] = 0;
7631       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7632       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7633 #if 1
7634       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
7635       for (p = 0; p < 4; ++p) {
7636         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
7637       }
7638 #endif
7639       /* B-H face */
7640       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 11;
7641       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
7642       orntNew[0] = 0;
7643       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
7644       orntNew[1] = -2;
7645       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
7646       orntNew[2] = -2;
7647       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
7648       orntNew[3] = 0;
7649       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7650       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7651 #if 1
7652       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
7653       for (p = 0; p < 4; ++p) {
7654         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
7655       }
7656 #endif
7657       for (r = 0; r < 12; ++r) {
7658         newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
7659         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
7660         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
7661         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
7662 #if 1
7663         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
7664         for (p = 0; p < 2; ++p) {
7665           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
7666         }
7667 #endif
7668       }
7669     }
7670     /* Hybrid split faces have 4 edges and same cells */
7671     for (f = fMax; f < fEnd; ++f) {
7672       const PetscInt *cone, *ornt, *support;
7673       PetscInt        coneNew[4], orntNew[4];
7674       PetscInt        supportNew[2], size, s, c;
7675 
7676       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
7677       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
7678       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
7679       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
7680       for (r = 0; r < 2; ++r) {
7681         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
7682 
7683         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
7684         orntNew[0]   = ornt[0];
7685         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
7686         orntNew[1]   = ornt[1];
7687         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (cone[2+r] - eMax);
7688         orntNew[2+r] = 0;
7689         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd      - eMax) + (f - fMax);
7690         orntNew[3-r] = 0;
7691         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7692         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7693 #if 1
7694         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
7695         for (p = 0; p < 2; ++p) {
7696           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
7697         }
7698         for (p = 2; p < 4; ++p) {
7699           if ((coneNew[p] < eMaxNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", coneNew[p], eMaxNew, eEndNew);
7700         }
7701 #endif
7702         for (s = 0; s < size; ++s) {
7703           const PetscInt *coneCell, *orntCell, *fornt;
7704           PetscInt        o, of;
7705 
7706           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
7707           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
7708           o = orntCell[0] < 0 ? -1 : 1;
7709           for (c = 2; c < 6; ++c) if (coneCell[c] == f) break;
7710           if (c >= 6) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
7711           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
7712           of = fornt[c-2] < 0 ? -1 : 1;
7713           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetQuadEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%4;
7714         }
7715         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
7716 #if 1
7717         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
7718         for (p = 0; p < size; ++p) {
7719           if ((supportNew[p] < cMaxNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", supportNew[p], cMaxNew, cEndNew);
7720         }
7721 #endif
7722       }
7723     }
7724     /* Hybrid cell faces have 4 edges and 2 cells */
7725     for (c = cMax; c < cEnd; ++c) {
7726       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4;
7727       const PetscInt *cone, *ornt;
7728       PetscInt        coneNew[4], orntNew[4];
7729       PetscInt        supportNew[2];
7730 
7731       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7732       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
7733       for (r = 0; r < 4; ++r) {
7734 #if 0
7735         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], r);
7736         orntNew[0] = 0;
7737         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], r);
7738         orntNew[1] = 0;
7739         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+GetQuadEdge_Static(ornt[0], r)] - fMax);
7740         orntNew[2] = 0;
7741         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd                                   - fMax) + (c - cMax);
7742         orntNew[3] = 0;
7743 #else
7744         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + r;
7745         orntNew[0] = 0;
7746         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + r;
7747         orntNew[1] = 0;
7748         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+r] - fMax);
7749         orntNew[2] = 0;
7750         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd      - fMax) + (c - cMax);
7751         orntNew[3] = 0;
7752 #endif
7753         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
7754         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
7755 #if 1
7756         if ((newp+r < fMaxNew) || (newp+r >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp+r, fMaxNew, fEndNew);
7757         for (p = 0; p < 2; ++p) {
7758           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
7759         }
7760         for (p = 2; p < 4; ++p) {
7761           if ((coneNew[p] < eMaxNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", coneNew[p], eMaxNew, eEndNew);
7762         }
7763 #endif
7764         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], r);
7765         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], (r+1)%4);
7766         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
7767 #if 1
7768         if ((newp+r < fMaxNew) || (newp+r >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp+r, fMaxNew, fEndNew);
7769         for (p = 0; p < 2; ++p) {
7770           if ((supportNew[p] < cMaxNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", supportNew[p], cMaxNew, cEndNew);
7771         }
7772 #endif
7773       }
7774     }
7775     /* Interior split edges have 2 vertices and the same faces as the parent */
7776     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
7777     for (e = eStart; e < eMax; ++e) {
7778       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
7779 
7780       for (r = 0; r < 2; ++r) {
7781         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
7782         const PetscInt *cone, *ornt, *support;
7783         PetscInt        coneNew[2], coneSize, c, supportSize, s;
7784 
7785         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
7786         coneNew[0]       = vStartNew + (cone[0] - vStart);
7787         coneNew[1]       = vStartNew + (cone[1] - vStart);
7788         coneNew[(r+1)%2] = newv;
7789         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7790 #if 1
7791         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
7792         for (p = 0; p < 2; ++p) {
7793           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
7794         }
7795 #endif
7796         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
7797         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
7798         for (s = 0; s < supportSize; ++s) {
7799           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
7800           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7801           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
7802           for (c = 0; c < coneSize; ++c) {
7803             if (cone[c] == e) break;
7804           }
7805           if (support[s] < fMax) {
7806             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%4;
7807           } else {
7808             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
7809           }
7810         }
7811         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7812 #if 1
7813         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
7814         for (p = 0; p < supportSize; ++p) {
7815           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
7816         }
7817 #endif
7818       }
7819     }
7820     /* Interior face edges have 2 vertices and 2+cells faces */
7821     for (f = fStart; f < fMax; ++f) {
7822       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};
7823       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
7824       const PetscInt *cone, *coneCell, *orntCell, *support;
7825       PetscInt        coneNew[2], coneSize, c, supportSize, s;
7826 
7827       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
7828       for (r = 0; r < 4; ++r) {
7829         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
7830 
7831         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
7832         coneNew[1] = newv;
7833         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7834 #if 1
7835         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
7836         for (p = 0; p < 2; ++p) {
7837           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
7838         }
7839 #endif
7840         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
7841         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
7842         supportRef[0] = fStartNew + (f - fStart)*4 + r;
7843         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
7844         for (s = 0; s < supportSize; ++s) {
7845           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
7846           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
7847           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
7848           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
7849           if (support[s] < cMax) {
7850             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
7851           } else {
7852             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + r;
7853           }
7854         }
7855         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7856 #if 1
7857         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
7858         for (p = 0; p < 2+supportSize; ++p) {
7859           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
7860         }
7861 #endif
7862       }
7863     }
7864     /* Interior cell edges have 2 vertices and 4 faces */
7865     for (c = cStart; c < cMax; ++c) {
7866       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};
7867       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
7868       const PetscInt *cone;
7869       PetscInt        coneNew[2], supportNew[4];
7870 
7871       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7872       for (r = 0; r < 6; ++r) {
7873         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
7874 
7875         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
7876         coneNew[1] = newv;
7877         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7878 #if 1
7879         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
7880         for (p = 0; p < 2; ++p) {
7881           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
7882         }
7883 #endif
7884         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
7885         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
7886 #if 1
7887         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
7888         for (p = 0; p < 4; ++p) {
7889           if ((supportNew[p] < fStartNew) || (supportNew[p] >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportNew[p], fStartNew, fMaxNew);
7890         }
7891 #endif
7892       }
7893     }
7894     /* Hybrid edges have two vertices and the same faces */
7895     for (e = eMax; e < eEnd; ++e) {
7896       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
7897       const PetscInt *cone, *support, *fcone;
7898       PetscInt        coneNew[2], size, fsize, s;
7899 
7900       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
7901       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
7902       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
7903       coneNew[0] = vStartNew + (cone[0] - vStart);
7904       coneNew[1] = vStartNew + (cone[1] - vStart);
7905       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7906 #if 1
7907       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
7908       for (p = 0; p < 2; ++p) {
7909         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
7910       }
7911 #endif
7912       for (s = 0; s < size; ++s) {
7913         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
7914         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
7915         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
7916         if ((c < 2) || (c > 3)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
7917         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + c-2;
7918       }
7919       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7920 #if 1
7921       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
7922       for (p = 0; p < size; ++p) {
7923         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", supportRef[p], fMaxNew, fEndNew);
7924       }
7925 #endif
7926     }
7927     /* Hybrid face edges have 2 vertices and 2+cells faces */
7928     for (f = fMax; f < fEnd; ++f) {
7929       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
7930       const PetscInt *cone, *support, *ccone, *cornt;
7931       PetscInt        coneNew[2], size, csize, s;
7932 
7933       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
7934       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
7935       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
7936       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
7937       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
7938       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7939 #if 1
7940       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
7941       for (p = 0; p < 2; ++p) {
7942         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
7943       }
7944 #endif
7945       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 0;
7946       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 1;
7947       for (s = 0; s < size; ++s) {
7948         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
7949         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
7950         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
7951         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
7952         if ((c < 2) || (c >= csize)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Hybrid face %d is not in cone of hybrid cell %d", f, support[s]);
7953         supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + c-2;
7954       }
7955       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7956 #if 1
7957       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
7958       for (p = 0; p < 2+size; ++p) {
7959         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", supportRef[p], fMaxNew, fEndNew);
7960       }
7961 #endif
7962     }
7963     /* Hybrid cell edges have 2 vertices and 4 faces */
7964     for (c = cMax; c < cEnd; ++c) {
7965       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
7966       const PetscInt *cone, *support;
7967       PetscInt        coneNew[2], size;
7968 
7969       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7970       ierr = DMPlexGetSupportSize(dm, c, &size);CHKERRQ(ierr);
7971       ierr = DMPlexGetSupport(dm, c, &support);CHKERRQ(ierr);
7972       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
7973       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
7974       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7975 #if 1
7976       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
7977       for (p = 0; p < 2; ++p) {
7978         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
7979       }
7980 #endif
7981       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 0;
7982       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 1;
7983       supportRef[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 2;
7984       supportRef[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 3;
7985       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7986 #if 1
7987       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
7988       for (p = 0; p < 4; ++p) {
7989         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", supportRef[p], fMaxNew, fEndNew);
7990       }
7991 #endif
7992     }
7993     /* Interior vertices have identical supports */
7994     for (v = vStart; v < vEnd; ++v) {
7995       const PetscInt  newp = vStartNew + (v - vStart);
7996       const PetscInt *support, *cone;
7997       PetscInt        size, s;
7998 
7999       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
8000       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
8001       for (s = 0; s < size; ++s) {
8002         PetscInt r = 0;
8003 
8004         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
8005         if (cone[1] == v) r = 1;
8006         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
8007         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (support[s] - eMax);
8008       }
8009       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
8010 #if 1
8011       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
8012       for (p = 0; p < size; ++p) {
8013         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
8014       }
8015 #endif
8016     }
8017     /* Interior edge vertices have 2 + faces supports */
8018     for (e = eStart; e < eMax; ++e) {
8019       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
8020       const PetscInt *cone, *support;
8021       PetscInt        size, s;
8022 
8023       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
8024       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
8025       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
8026       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
8027       for (s = 0; s < size; ++s) {
8028         PetscInt r;
8029 
8030         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
8031         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
8032         if (support[s] < fMax) {
8033           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*4 + r;
8034         } else {
8035           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (support[s] - fMax);
8036         }
8037       }
8038       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
8039 #if 1
8040       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
8041       for (p = 0; p < 2+size; ++p) {
8042         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
8043       }
8044 #endif
8045     }
8046     /* Interior face vertices have 4 + cells supports */
8047     for (f = fStart; f < fMax; ++f) {
8048       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
8049       const PetscInt *cone, *support;
8050       PetscInt        size, s;
8051 
8052       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
8053       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
8054       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eMax - eStart)*2 +  (f - fStart)*4 + r;
8055       for (s = 0; s < size; ++s) {
8056         PetscInt r;
8057 
8058         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
8059         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
8060         if (support[s] < cMax) {
8061           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (support[s] - cStart)*6 + r;
8062         } else {
8063           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax       - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (support[s] - cMax);
8064         }
8065       }
8066       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
8067 #if 1
8068       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
8069       for (p = 0; p < 4+size; ++p) {
8070         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
8071       }
8072 #endif
8073     }
8074     /* Cell vertices have 6 supports */
8075     for (c = cStart; c < cMax; ++c) {
8076       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
8077       PetscInt       supportNew[6];
8078 
8079       for (r = 0; r < 6; ++r) {
8080         supportNew[r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
8081       }
8082       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
8083     }
8084     ierr = PetscFree(supportRef);CHKERRQ(ierr);
8085     break;
8086   default:
8087     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
8088   }
8089   PetscFunctionReturn(0);
8090 }
8091 
8092 static PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
8093 {
8094   PetscSection          coordSection, coordSectionNew;
8095   Vec                   coordinates, coordinatesNew;
8096   PetscScalar          *coords, *coordsNew;
8097   const PetscInt        numVertices = depthSize ? depthSize[0] : 0;
8098   PetscInt              dim, spaceDim, depth, bs, coordSizeNew, cStart, cEnd, cMax;
8099   PetscInt              c, vStart, vStartNew, vEnd, v, eStart, eEnd, eMax, e, fStart, fEnd, fMax, f;
8100   PetscInt              cStartNew, cEndNew, vEndNew, *parentId = NULL;
8101   VecType               vtype;
8102   PetscBool             isperiodic, localize = PETSC_FALSE, needcoords = PETSC_FALSE;
8103   const PetscReal      *maxCell, *L;
8104   const DMBoundaryType *bd;
8105   PetscErrorCode        ierr;
8106 
8107   PetscFunctionBegin;
8108   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
8109   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
8110   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8111   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
8112   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8113   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
8114   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, NULL);CHKERRQ(ierr);
8115   if (cMax < 0) cMax = cEnd;
8116   if (fMax < 0) fMax = fEnd;
8117   if (eMax < 0) eMax = eEnd;
8118   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, NULL, NULL, &vStartNew);CHKERRQ(ierr);
8119   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, NULL, NULL, &vEndNew);CHKERRQ(ierr);
8120   ierr = DMGetPeriodicity(dm, &isperiodic, &maxCell, &L, &bd);CHKERRQ(ierr);
8121   /* Determine if we need to localize coordinates when generating them */
8122   if (isperiodic && !maxCell) {
8123     ierr = DMGetCoordinatesLocalized(dm, &localize);CHKERRQ(ierr);
8124     if (!localize) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Cannot refine if coordinates have not been localized");
8125   }
8126   if (isperiodic) {
8127     ierr = PetscOptionsBegin(PetscObjectComm((PetscObject)dm),((PetscObject)dm)->prefix,"DMPlex coords refinement options","DM");CHKERRQ(ierr);
8128     ierr = PetscOptionsBool("-dm_plex_refine_localize","Automatically localize from parent cells",NULL,localize,&localize,NULL);CHKERRQ(ierr);
8129     ierr = PetscOptionsEnd();CHKERRQ(ierr);
8130     if (localize) {
8131       ierr = DMLocalizeCoordinates(dm);CHKERRQ(ierr);
8132     }
8133   }
8134   ierr = DMSetPeriodicity(rdm, isperiodic,  maxCell,  L,  bd);CHKERRQ(ierr);
8135 
8136   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8137   ierr = PetscSectionGetFieldComponents(coordSection, 0, &spaceDim);CHKERRQ(ierr);
8138   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
8139   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
8140   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, spaceDim);CHKERRQ(ierr);
8141 
8142   if (localize) {
8143     PetscInt p, r, newp, *pi;
8144 
8145     /* New coordinates will be already localized on the cell */
8146     ierr = PetscSectionSetChart(coordSectionNew, 0, vStartNew+numVertices);CHKERRQ(ierr);
8147 
8148     /* We need the parentId to properly localize coordinates */
8149     ierr = PetscMalloc1(cEndNew-cStartNew,&pi);CHKERRQ(ierr);
8150     switch (refiner) {
8151     case REFINER_NOOP:
8152       break;
8153     case REFINER_SIMPLEX_1D:
8154       for (p = cStart; p < cEnd; ++p) {
8155         for (r = 0; r < 2; ++r) {
8156           newp     = (p - cStart)*2 + r;
8157           pi[newp] = p;
8158         }
8159       }
8160       break;
8161     case REFINER_SIMPLEX_2D:
8162       for (p = cStart; p < cEnd; ++p) {
8163         for (r = 0; r < 4; ++r) {
8164           newp     = (p - cStart)*4 + r;
8165           pi[newp] = p;
8166         }
8167       }
8168       break;
8169     case REFINER_HEX_2D:
8170       for (p = cStart; p < cEnd; ++p) {
8171         for (r = 0; r < 4; ++r) {
8172           newp     = (p - cStart)*4 + r;
8173           pi[newp] = p;
8174         }
8175       }
8176       break;
8177     case REFINER_SIMPLEX_TO_HEX_2D:
8178       for (p = cStart; p < cEnd; ++p) {
8179         for (r = 0; r < 3; ++r) {
8180           newp     = (p - cStart)*3 + r;
8181           pi[newp] = p;
8182         }
8183       }
8184       break;
8185     case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
8186       for (p = cStart; p < cMax; ++p) {
8187         for (r = 0; r < 3; ++r) {
8188           newp     = (p - cStart)*3 + r;
8189           pi[newp] = p;
8190         }
8191       }
8192       for (p = cMax; p < cEnd; ++p) {
8193         for (r = 0; r < 4; ++r) {
8194           newp     = (cMax - cStart)*3 + (p - cMax)*4 + r;
8195           pi[newp] = p;
8196         }
8197       }
8198       /* The refiner needs midpoint vertices on hybrid edges and hybrid cells */
8199       cMax = cEnd;
8200       eMax = eEnd;
8201       break;
8202     case REFINER_HYBRID_SIMPLEX_2D:
8203       for (p = cStart; p < cMax; ++p) {
8204         for (r = 0; r < 4; ++r) {
8205           newp     = (p - cStart)*4 + r;
8206           pi[newp] = p;
8207         }
8208       }
8209       for (p = cMax; p < cEnd; ++p) {
8210         for (r = 0; r < 2; ++r) {
8211           newp     = (cMax - cStart)*4 + (p - cMax)*2 + r;
8212           pi[newp] = p;
8213         }
8214       }
8215       break;
8216     case REFINER_HYBRID_HEX_2D:
8217       for (p = cStart; p < cMax; ++p) {
8218         for (r = 0; r < 4; ++r) {
8219           newp     = (p - cStart)*4 + r;
8220           pi[newp] = p;
8221         }
8222       }
8223       for (p = cMax; p < cEnd; ++p) {
8224         for (r = 0; r < 2; ++r) {
8225           newp     = (cMax - cStart)*4 + (p - cMax)*2 + r;
8226           pi[newp] = p;
8227         }
8228       }
8229       break;
8230     case REFINER_SIMPLEX_3D:
8231       for (p = cStart; p < cEnd; ++p) {
8232         for (r = 0; r < 8; ++r) {
8233           newp     = (p - cStart)*8 + r;
8234           pi[newp] = p;
8235         }
8236       }
8237       break;
8238     case REFINER_HYBRID_SIMPLEX_3D:
8239       for (p = cStart; p < cMax; ++p) {
8240         for (r = 0; r < 8; ++r) {
8241           newp     = (p - cStart)*8 + r;
8242           pi[newp] = p;
8243         }
8244       }
8245       for (p = cMax; p < cEnd; ++p) {
8246         for (r = 0; r < 4; ++r) {
8247           newp     = (cMax - cStart)*8 + (p - cMax)*4 + r;
8248           pi[newp] = p;
8249         }
8250       }
8251       break;
8252     case REFINER_SIMPLEX_TO_HEX_3D:
8253       for (p = cStart; p < cEnd; ++p) {
8254         for (r = 0; r < 4; ++r) {
8255           newp     = (p - cStart)*4 + r;
8256           pi[newp] = p;
8257         }
8258       }
8259       break;
8260     case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
8261       for (p = cStart; p < cMax; ++p) {
8262         for (r = 0; r < 4; ++r) {
8263           newp     = (p - cStart)*4 + r;
8264           pi[newp] = p;
8265         }
8266       }
8267       for (p = cMax; p < cEnd; ++p) {
8268         for (r = 0; r < 3; ++r) {
8269           newp     = (cMax - cStart)*4 + (p - cMax)*3 + r;
8270           pi[newp] = p;
8271         }
8272       }
8273       break;
8274     case REFINER_HEX_3D:
8275       for (p = cStart; p < cEnd; ++p) {
8276         for (r = 0; r < 8; ++r) {
8277           newp = (p - cStart)*8 + r;
8278           pi[newp] = p;
8279         }
8280       }
8281       break;
8282     case REFINER_HYBRID_HEX_3D:
8283       for (p = cStart; p < cMax; ++p) {
8284         for (r = 0; r < 8; ++r) {
8285           newp = (p - cStart)*8 + r;
8286           pi[newp] = p;
8287         }
8288       }
8289       for (p = cMax; p < cEnd; ++p) {
8290         for (r = 0; r < 4; ++r) {
8291           newp = (cMax - cStart)*8 + (p - cMax)*4 + r;
8292           pi[newp] = p;
8293         }
8294       }
8295       break;
8296     default:
8297       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
8298     }
8299     parentId = pi;
8300   } else {
8301     /* The refiner needs midpoint vertices on hybrid edges and hybrid cells */
8302     if (REFINER_HYBRID_SIMPLEX_TO_HEX_2D == refiner) { cMax = cEnd; eMax = eEnd; }
8303     ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+numVertices);CHKERRQ(ierr);
8304   }
8305 
8306   /* All vertices have the spaceDim coordinates */
8307   if (localize) {
8308     PetscInt c;
8309 
8310     for (c = cStartNew; c < cEndNew; ++c) {
8311       PetscInt *cone = NULL;
8312       PetscInt  closureSize, coneSize = 0, p, pdof;
8313 
8314       ierr = PetscSectionGetDof(coordSection, parentId[c], &pdof); CHKERRQ(ierr);
8315       if (pdof) { /* localize on all cells that are refinement of a localized parent cell */
8316         ierr = DMPlexGetTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8317         for (p = 0; p < closureSize*2; p += 2) {
8318           const PetscInt point = cone[p];
8319           if ((point >= vStartNew) && (point < vEndNew)) coneSize++;
8320         }
8321         ierr = DMPlexRestoreTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8322         ierr = PetscSectionSetDof(coordSectionNew, c, coneSize*spaceDim);CHKERRQ(ierr);
8323         ierr = PetscSectionSetFieldDof(coordSectionNew, c, 0, coneSize*spaceDim);CHKERRQ(ierr);
8324       }
8325     }
8326   }
8327   for (v = vStartNew; v < vStartNew+numVertices; ++v) {
8328     ierr = PetscSectionSetDof(coordSectionNew, v, spaceDim);CHKERRQ(ierr);
8329     ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, spaceDim);CHKERRQ(ierr);
8330   }
8331   ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
8332   ierr = DMSetCoordinateSection(rdm, PETSC_DETERMINE, coordSectionNew);CHKERRQ(ierr);
8333   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8334   ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
8335   ierr = VecCreate(PETSC_COMM_SELF, &coordinatesNew);CHKERRQ(ierr);
8336   ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
8337   ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
8338   ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr);
8339   ierr = VecSetBlockSize(coordinatesNew, bs);CHKERRQ(ierr);
8340   ierr = VecGetType(coordinates, &vtype);CHKERRQ(ierr);
8341   ierr = VecSetType(coordinatesNew, vtype);CHKERRQ(ierr);
8342   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
8343   ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
8344 
8345   switch (refiner) {
8346   case REFINER_NOOP: break;
8347   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
8348   case REFINER_SIMPLEX_TO_HEX_3D:
8349   case REFINER_HEX_3D:
8350   case REFINER_HYBRID_HEX_3D:
8351     /* Face vertices have the average of corner coordinates */
8352     for (f = fStart; f < fMax; ++f) {
8353       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
8354       PetscInt      *cone = NULL;
8355       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
8356 
8357       ierr = DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8358       for (p = 0; p < closureSize*2; p += 2) {
8359         const PetscInt point = cone[p];
8360         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
8361       }
8362       if (localize) {
8363         const PetscInt *support = NULL;
8364         PetscInt       *rStar = NULL;
8365         PetscInt        supportSize, rStarSize, coff, s, ccoff[8];
8366         PetscBool       cellfound = PETSC_FALSE;
8367 
8368         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8369         ierr = DMPlexGetSupportSize(dm,f,&supportSize);CHKERRQ(ierr);
8370         ierr = DMPlexGetSupport(dm,f,&support);CHKERRQ(ierr);
8371         /* Compute average of coordinates for each cell sharing the face */
8372         for (s = 0; s < supportSize; ++s) {
8373           PetscScalar     coordsNewAux[3] = { 0.0, 0.0, 0.0 };
8374           PetscInt       *cellCone = NULL;
8375           PetscInt        cellClosureSize, cellConeSize = 0, cdof;
8376           const PetscInt  cell = support[s];
8377           PetscBool       copyoff = PETSC_FALSE;
8378 
8379           ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
8380           for (p = 0; p < cellClosureSize*2; p += 2) {
8381             const PetscInt point = cellCone[p];
8382             if ((point >= vStart) && (point < vEnd)) cellCone[cellConeSize++] = point;
8383           }
8384           ierr = PetscSectionGetDof(coordSection, cell, &cdof);CHKERRQ(ierr);
8385           if (!cdof) { /* the parent cell does not have localized coordinates */
8386             cellfound = PETSC_TRUE;
8387             for (v = 0; v < coneSize; ++v) {
8388               ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
8389               for (d = 0; d < spaceDim; ++d) coordsNewAux[d] += coords[off[v]+d];
8390             }
8391             for (d = 0; d < spaceDim; ++d) coordsNewAux[d] /= coneSize;
8392           } else {
8393             ierr = PetscSectionGetOffset(coordSection, cell, &coff);CHKERRQ(ierr);
8394             for (p = 0; p < coneSize; ++p) {
8395               const PetscInt tv = cone[p];
8396               PetscInt       cv, voff;
8397               PetscBool      locv = PETSC_TRUE;
8398 
8399               for (cv = 0; cv < cellConeSize; ++cv) {
8400                 if (cellCone[cv] == tv) {
8401                   ccoff[p] = spaceDim*cv + coff;
8402                   break;
8403                 }
8404               }
8405               if (cv == cellConeSize) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map vertex %D\n",tv);
8406 
8407               ierr = PetscSectionGetOffset(coordSection, cone[p], &voff);CHKERRQ(ierr);
8408               for (d = 0; d < spaceDim; ++d) {
8409                 coordsNewAux[d] += coords[ccoff[p]+d];
8410                 if (!cellfound && coords[voff+d] != coords[ccoff[p]+d]) locv = PETSC_FALSE;
8411               }
8412               if (locv && !cellfound) {
8413                 cellfound = PETSC_TRUE;
8414                 copyoff   = PETSC_TRUE;
8415               }
8416             }
8417             for (d = 0; d < spaceDim; ++d) coordsNewAux[d] /= coneSize;
8418 
8419             /* Found a valid face for the "vertex" part of the Section (physical space)
8420                i.e., a face that has at least one corner in the physical space */
8421             if (copyoff) for (p = 0; p < coneSize; ++p) off[p] = ccoff[p];
8422           }
8423 
8424           /* Localize new coordinates on each refined cell */
8425           for (v = 0; v < rStarSize*2; v += 2) {
8426             if ((rStar[v] >= cStartNew) && (rStar[v] < cEndNew) && parentId[rStar[v]-cStartNew] == cell) {
8427               PetscInt       *rcone = NULL, rclosureSize, lid, rcdof, rcoff;
8428               const PetscInt  rcell = rStar[v];
8429 
8430               ierr = PetscSectionGetDof(coordSectionNew, rcell, &rcdof);CHKERRQ(ierr);
8431               if (!rcdof) continue;
8432               ierr = PetscSectionGetOffset(coordSectionNew, rcell, &rcoff);CHKERRQ(ierr);
8433               ierr = DMPlexGetTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
8434               for (p = 0, lid = 0; p < rclosureSize*2; p += 2) {
8435                 if (rcone[p] == newv) {
8436                   for (d = 0; d < spaceDim; d++) coordsNew[rcoff + lid*spaceDim + d] = coordsNewAux[d];
8437                   break;
8438                 }
8439                 if (rcone[p] >= vStartNew && rcone[p] < vEndNew) lid++;
8440               }
8441               ierr = DMPlexRestoreTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
8442               if (p == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
8443             }
8444           }
8445           ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
8446         }
8447         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8448         if (!cellfound) {
8449           /* Could not find a valid face for the vertex part, we will get this vertex later (final reduction) */
8450           needcoords = PETSC_TRUE;
8451           coneSize   = 0;
8452         }
8453       } else {
8454         for (v = 0; v < coneSize; ++v) {
8455           ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
8456         }
8457       }
8458       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
8459       if (coneSize) {
8460         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
8461         for (v = 0; v < coneSize; ++v) {ierr = DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);CHKERRQ(ierr);}
8462         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
8463       } else {
8464         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = PETSC_MIN_REAL;
8465       }
8466       ierr = DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8467     }
8468   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
8469   case REFINER_SIMPLEX_TO_HEX_2D:
8470   case REFINER_HEX_2D:
8471   case REFINER_HYBRID_HEX_2D:
8472   case REFINER_SIMPLEX_1D:
8473     /* Cell vertices have the average of corner coordinates */
8474     for (c = cStart; c < cMax; ++c) {
8475       const PetscInt newv = vStartNew + (vEnd - vStart) + (dim > 1 ? (eMax - eStart) : 0) + (c - cStart) + (dim > 2 ? (fMax - fStart) : 0);
8476       PetscInt      *cone = NULL;
8477       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d, cdof = 0;
8478 
8479       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8480       for (p = 0; p < closureSize*2; p += 2) {
8481         const PetscInt point = cone[p];
8482         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
8483       }
8484       if (localize) {
8485         ierr = PetscSectionGetDof(coordSection, c, &cdof);CHKERRQ(ierr);
8486       }
8487       if (cdof) {
8488         PetscInt coff;
8489 
8490         ierr = PetscSectionGetOffset(coordSection, c, &coff);CHKERRQ(ierr);
8491         for (v = 0; v < coneSize; ++v) off[v] = spaceDim*v + coff;
8492       } else {
8493         for (v = 0; v < coneSize; ++v) {
8494           ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
8495         }
8496       }
8497       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
8498       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
8499       for (v = 0; v < coneSize; ++v) {ierr = DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);CHKERRQ(ierr);}
8500       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
8501       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8502 
8503       /* Localize new coordinates on each refined cell */
8504       if (cdof) {
8505         PetscInt *rStar = NULL, rStarSize;
8506 
8507         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8508         for (v = 0; v < rStarSize*2; v += 2) {
8509           if ((rStar[v] >= cStartNew) && (rStar[v] < cEndNew)) {
8510             PetscInt *cone = NULL, closureSize, lid, coff, rc, rcdof;
8511 
8512             rc   = rStar[v];
8513             ierr = PetscSectionGetDof(coordSectionNew, rc, &rcdof);CHKERRQ(ierr);
8514             if (!rcdof) continue;
8515             ierr = PetscSectionGetOffset(coordSectionNew, rc, &coff);CHKERRQ(ierr);
8516             ierr = DMPlexGetTransitiveClosure(rdm, rc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8517             for (p = 0, lid = 0; p < closureSize*2; p += 2) {
8518               if (cone[p] == newv) {
8519                 for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = coordsNew[offnew + d];
8520                 break;
8521               }
8522               if (cone[p] >= vStartNew && cone[p] < vEndNew) lid++;
8523             }
8524             if (p == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
8525             ierr = DMPlexRestoreTransitiveClosure(rdm, rc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8526           }
8527         }
8528         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8529       }
8530     }
8531   case REFINER_SIMPLEX_2D:
8532   case REFINER_HYBRID_SIMPLEX_2D:
8533   case REFINER_SIMPLEX_3D:
8534   case REFINER_HYBRID_SIMPLEX_3D:
8535     /* Edge vertices have the average of endpoint coordinates */
8536     for (e = eStart; e < eMax; ++e) {
8537       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
8538       const PetscInt *cone;
8539       PetscInt        coneSize, offA, offB, offnew, d;
8540 
8541       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
8542       if (coneSize != 2) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
8543       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
8544       if (localize) {
8545         PetscInt   coff, toffA = -1, toffB = -1, voffA, voffB;
8546         PetscInt  *eStar = NULL, eStarSize;
8547         PetscInt  *rStar = NULL, rStarSize;
8548         PetscBool  cellfound = PETSC_FALSE;
8549 
8550         offA = offB = -1;
8551         ierr = PetscSectionGetOffset(coordSection, cone[0], &voffA);CHKERRQ(ierr);
8552         ierr = PetscSectionGetOffset(coordSection, cone[1], &voffB);CHKERRQ(ierr);
8553         ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &eStarSize, &eStar);CHKERRQ(ierr);
8554         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8555         for (v = 0; v < eStarSize*2; v += 2) {
8556           if ((eStar[v] >= cStart) && (eStar[v] < cEnd)) {
8557             PetscScalar     coordsNewAux[3];
8558             PetscInt       *cellCone = NULL;
8559             PetscInt        cellClosureSize, s, cv, cdof;
8560             PetscBool       locvA = PETSC_TRUE, locvB = PETSC_TRUE;
8561             const PetscInt  cell = eStar[v];
8562 
8563             ierr = PetscSectionGetDof(coordSection, cell, &cdof);CHKERRQ(ierr);
8564             if (!cdof) {
8565               /* Found a valid edge for the "vertex" part of the Section */
8566               offA = voffA;
8567               offB = voffB;
8568               cellfound = PETSC_TRUE;
8569             } else {
8570               ierr = PetscSectionGetOffset(coordSection, cell, &coff);CHKERRQ(ierr);
8571               ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
8572               for (s = 0, cv = 0; s < cellClosureSize*2; s += 2) {
8573                 const PetscInt point = cellCone[s];
8574                 if ((point >= vStart) && (point < vEnd)) {
8575                   if (point == cone[0]) toffA = spaceDim*cv + coff;
8576                   else if (point == cone[1]) toffB = spaceDim*cv + coff;
8577                   cv++;
8578                 }
8579               }
8580               ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
8581               for (d = 0; d < spaceDim; ++d) {
8582                 coordsNewAux[d] = 0.5*(coords[toffA+d] + coords[toffB+d]);
8583                 if (coords[toffA+d] != coords[voffA+d]) locvA = PETSC_FALSE;
8584                 if (coords[toffB+d] != coords[voffB+d]) locvB = PETSC_FALSE;
8585               }
8586               /* Found a valid edge for the "vertex" part of the Section */
8587               if (!cellfound && (locvA || locvB)) {
8588                 cellfound = PETSC_TRUE;
8589                 offA = toffA;
8590                 offB = toffB;
8591               }
8592             }
8593 
8594             /* Localize new coordinates on each refined cell */
8595             for (s = 0; s < rStarSize*2; s += 2) {
8596               if ((rStar[s] >= cStartNew) && (rStar[s] < cEndNew) && parentId[rStar[s]-cStartNew] == cell) {
8597                 PetscInt       *rcone = NULL, rclosureSize, lid, p, rcdof;
8598                 const PetscInt  rcell = rStar[s];
8599 
8600                 ierr = PetscSectionGetDof(coordSectionNew, rcell, &rcdof);CHKERRQ(ierr);
8601                 if (!rcdof) continue;
8602                 ierr = PetscSectionGetOffset(coordSectionNew, rcell, &coff);CHKERRQ(ierr);
8603                 ierr = DMPlexGetTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
8604                 for (p = 0, lid = 0; p < rclosureSize*2; p += 2) {
8605                   if (rcone[p] == newv) {
8606                     for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = coordsNewAux[d];
8607                     break;
8608                   }
8609                   if (rcone[p] >= vStartNew && rcone[p] < vEndNew) lid++;
8610                 }
8611                 ierr = DMPlexRestoreTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
8612                 if (p == rclosureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
8613               }
8614             }
8615           }
8616         }
8617         ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &eStarSize, &eStar);CHKERRQ(ierr);
8618         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8619         if (!cellfound) {
8620           /* Could not find a valid edge for the vertex part, we will get this vertex later (final reduction) */
8621           needcoords = PETSC_TRUE;
8622         }
8623       } else {
8624         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
8625         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
8626       }
8627       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
8628       if (offA != -1 && offB != -1) {
8629         ierr = DMLocalizeCoordinate_Internal(dm, spaceDim, &coords[offA], &coords[offB], &coordsNew[offnew]);CHKERRQ(ierr);
8630         for (d = 0; d < spaceDim; ++d) {
8631           coordsNew[offnew+d] = 0.5*(coords[offA+d] + coordsNew[offnew+d]);
8632         }
8633       } else {
8634         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = PETSC_MIN_REAL;
8635       }
8636     }
8637     /* Old vertices have the same coordinates */
8638     for (v = vStart; v < vEnd; ++v) {
8639       const PetscInt newv = vStartNew + (v - vStart);
8640       PetscInt       off, offnew, d;
8641 
8642       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
8643       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
8644       for (d = 0; d < spaceDim; ++d) {
8645         coordsNew[offnew+d] = coords[off+d];
8646       }
8647 
8648       /* Localize new coordinates on each refined cell */
8649       if (localize) {
8650         PetscInt  p;
8651         PetscInt *rStar = NULL, rStarSize;
8652 
8653         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8654         for (p = 0; p < rStarSize*2; p += 2) {
8655           if ((rStar[p] >= cStartNew) && (rStar[p] < cEndNew)) {
8656             PetscScalar  ocoords[3];
8657             PetscInt    *cone = NULL, closureSize, lid, coff, s, oc, cdof;
8658 
8659             c    = rStar[p];
8660             oc   = parentId[c-cStartNew];
8661             ierr = PetscSectionGetDof(coordSectionNew, c, &cdof);CHKERRQ(ierr);
8662             if (!cdof) continue;
8663             ierr = PetscSectionGetDof(coordSection, oc, &cdof);CHKERRQ(ierr);
8664             if (!cdof) continue;
8665             ierr = PetscSectionGetOffset(coordSection, oc, &coff);CHKERRQ(ierr);
8666             ierr = DMPlexGetTransitiveClosure(dm, oc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8667             for (s = 0, lid = 0; s < closureSize*2; s += 2) {
8668               if (cone[s] == v) {
8669                 for (d = 0; d < spaceDim; d++) ocoords[d] = coords[coff + lid*spaceDim + d];
8670                 break;
8671               }
8672               if (cone[s] >= vStart && cone[s] < vEnd) lid++;
8673             }
8674             if (s == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map old vertex %D\n",v);
8675             ierr = DMPlexRestoreTransitiveClosure(dm, oc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8676 
8677             ierr = PetscSectionGetOffset(coordSectionNew, c, &coff);CHKERRQ(ierr);
8678             ierr = DMPlexGetTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8679             for (s = 0, lid = 0; s < closureSize*2; s += 2) {
8680               if (cone[s] == newv) {
8681                 for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = ocoords[d];
8682                 break;
8683               }
8684               if (cone[s] >= vStartNew && cone[s] < vEndNew) lid++;
8685             }
8686             if (s == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
8687             ierr = DMPlexRestoreTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8688           }
8689         }
8690         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8691       }
8692     }
8693     break;
8694   default:
8695     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
8696   }
8697   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
8698   ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
8699   ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
8700 
8701   /* Final reduction (if needed) if we are localizing */
8702   if (localize) {
8703     PetscBool gred;
8704 
8705     ierr = MPIU_Allreduce(&needcoords, &gred, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)rdm));CHKERRQ(ierr);
8706     if (gred) {
8707       DM                 cdm;
8708       Vec                aux;
8709       PetscSF            sf;
8710       const PetscScalar *lArray;
8711       PetscScalar       *gArray;
8712 
8713       ierr = DMGetCoordinateDM(rdm, &cdm);CHKERRQ(ierr);
8714       ierr = DMCreateGlobalVector(cdm, &aux);CHKERRQ(ierr);
8715       ierr = DMGetDefaultSF(cdm, &sf);CHKERRQ(ierr);
8716       ierr = VecGetArrayRead(coordinatesNew, &lArray);CHKERRQ(ierr);
8717       ierr = VecSet(aux, PETSC_MIN_REAL);CHKERRQ(ierr);
8718       ierr = VecGetArray(aux, &gArray);CHKERRQ(ierr);
8719       ierr = PetscSFReduceBegin(sf, MPIU_SCALAR, lArray, gArray, MPIU_MAX);CHKERRQ(ierr);
8720       ierr = PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_MAX);CHKERRQ(ierr);
8721       ierr = VecRestoreArrayRead(coordinatesNew, &lArray);CHKERRQ(ierr);
8722       ierr = VecRestoreArray(aux, &gArray);CHKERRQ(ierr);
8723       ierr = DMGlobalToLocalBegin(cdm, aux, INSERT_VALUES, coordinatesNew);CHKERRQ(ierr);
8724       ierr = DMGlobalToLocalEnd(cdm, aux, INSERT_VALUES, coordinatesNew);CHKERRQ(ierr);
8725       ierr = VecDestroy(&aux);CHKERRQ(ierr);
8726     }
8727   }
8728   ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
8729   ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
8730   ierr = PetscFree(parentId);CHKERRQ(ierr);
8731   PetscFunctionReturn(0);
8732 }
8733 
8734 /*@
8735   DMPlexCreateProcessSF - Create an SF which just has process connectivity
8736 
8737   Collective on DM
8738 
8739   Input Parameters:
8740 + dm      - The DM
8741 - sfPoint - The PetscSF which encodes point connectivity
8742 
8743   Output Parameters:
8744 + processRanks - A list of process neighbors, or NULL
8745 - sfProcess    - An SF encoding the process connectivity, or NULL
8746 
8747   Level: developer
8748 
8749 .seealso: PetscSFCreate(), DMPlexCreateTwoSidedProcessSF()
8750 @*/
8751 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
8752 {
8753   PetscInt           numRoots, numLeaves, l;
8754   const PetscInt    *localPoints;
8755   const PetscSFNode *remotePoints;
8756   PetscInt          *localPointsNew;
8757   PetscSFNode       *remotePointsNew;
8758   PetscInt          *ranks, *ranksNew;
8759   PetscMPIInt        size;
8760   PetscErrorCode     ierr;
8761 
8762   PetscFunctionBegin;
8763   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8764   PetscValidHeaderSpecific(sfPoint, PETSCSF_CLASSID, 2);
8765   if (processRanks) {PetscValidPointer(processRanks, 3);}
8766   if (sfProcess)    {PetscValidPointer(sfProcess, 4);}
8767   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) dm), &size);CHKERRQ(ierr);
8768   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
8769   ierr = PetscMalloc1(numLeaves, &ranks);CHKERRQ(ierr);
8770   for (l = 0; l < numLeaves; ++l) {
8771     ranks[l] = remotePoints[l].rank;
8772   }
8773   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
8774   ierr = PetscMalloc1(numLeaves, &ranksNew);CHKERRQ(ierr);
8775   ierr = PetscMalloc1(numLeaves, &localPointsNew);CHKERRQ(ierr);
8776   ierr = PetscMalloc1(numLeaves, &remotePointsNew);CHKERRQ(ierr);
8777   for (l = 0; l < numLeaves; ++l) {
8778     ranksNew[l]              = ranks[l];
8779     localPointsNew[l]        = l;
8780     remotePointsNew[l].index = 0;
8781     remotePointsNew[l].rank  = ranksNew[l];
8782   }
8783   ierr = PetscFree(ranks);CHKERRQ(ierr);
8784   if (processRanks) {ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);}
8785   else              {ierr = PetscFree(ranksNew);CHKERRQ(ierr);}
8786   if (sfProcess) {
8787     ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
8788     ierr = PetscObjectSetName((PetscObject) *sfProcess, "Process SF");CHKERRQ(ierr);
8789     ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
8790     ierr = PetscSFSetGraph(*sfProcess, size, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
8791   }
8792   PetscFunctionReturn(0);
8793 }
8794 
8795 static PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
8796 {
8797   PetscSF            sf, sfNew, sfProcess;
8798   IS                 processRanks;
8799   MPI_Datatype       depthType;
8800   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
8801   const PetscInt    *localPoints, *neighbors;
8802   const PetscSFNode *remotePoints;
8803   PetscInt          *localPointsNew;
8804   PetscSFNode       *remotePointsNew;
8805   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
8806   PetscInt           ldepth, depth, numNeighbors, pStartNew, pEndNew, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r, n;
8807   PetscInt           cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
8808   PetscErrorCode     ierr;
8809 
8810   PetscFunctionBegin;
8811   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
8812   ierr = DMPlexGetDepth(dm, &ldepth);CHKERRQ(ierr);
8813   ierr = MPIU_Allreduce(&ldepth, &depth, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
8814   if ((ldepth >= 0) && (depth != ldepth)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent Plex depth %d != %d", ldepth, depth);
8815   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8816   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
8817   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8818   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
8819   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
8820   cMax = cMax < 0 ? cEnd : cMax;
8821   fMax = fMax < 0 ? fEnd : fMax;
8822   eMax = eMax < 0 ? eEnd : eMax;
8823   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
8824   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
8825   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
8826   /* Calculate size of new SF */
8827   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
8828   if (numRoots < 0) PetscFunctionReturn(0);
8829   for (l = 0; l < numLeaves; ++l) {
8830     const PetscInt p = localPoints[l];
8831 
8832     switch (refiner) {
8833     case REFINER_SIMPLEX_1D:
8834       if ((p >= vStart) && (p < vEnd)) {
8835         /* Interior vertices stay the same */
8836         ++numLeavesNew;
8837       } else if ((p >= cStart && p < cMax)) {
8838         /* Interior cells add new cells and interior vertices */
8839         numLeavesNew += 2 + 1;
8840       }
8841       break;
8842     case REFINER_SIMPLEX_2D:
8843     case REFINER_HYBRID_SIMPLEX_2D:
8844       if ((p >= vStart) && (p < vEnd)) {
8845         /* Interior vertices stay the same */
8846         ++numLeavesNew;
8847       } else if ((p >= fStart) && (p < fMax)) {
8848         /* Interior faces add new faces and vertex */
8849         numLeavesNew += 2 + 1;
8850       } else if ((p >= fMax) && (p < fEnd)) {
8851         /* Hybrid faces stay the same */
8852         ++numLeavesNew;
8853       } else if ((p >= cStart) && (p < cMax)) {
8854         /* Interior cells add new cells and interior faces */
8855         numLeavesNew += 4 + 3;
8856       } else if ((p >= cMax) && (p < cEnd)) {
8857         /* Hybrid cells add new cells and hybrid face */
8858         numLeavesNew += 2 + 1;
8859       }
8860       break;
8861     case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
8862     case REFINER_SIMPLEX_TO_HEX_2D:
8863       if ((p >= vStart) && (p < vEnd)) {
8864         /* Interior vertices stay the same */
8865         ++numLeavesNew;
8866       } else if ((p >= fStart) && (p < fEnd)) {
8867         /* Interior faces add new faces and vertex */
8868         numLeavesNew += 2 + 1;
8869       } else if ((p >= cStart) && (p < cMax)) {
8870         /* Interior cells add new cells, interior faces, and vertex */
8871         numLeavesNew += 3 + 3 + 1;
8872       } else if ((p >= cMax) && (p < cEnd)) {
8873         /* Hybrid cells add new cells, interior faces, and vertex */
8874         numLeavesNew += 4 + 4 + 1;
8875       }
8876       break;
8877     case REFINER_HEX_2D:
8878     case REFINER_HYBRID_HEX_2D:
8879       if ((p >= vStart) && (p < vEnd)) {
8880         /* Interior vertices stay the same */
8881         ++numLeavesNew;
8882       } else if ((p >= fStart) && (p < fMax)) {
8883         /* Interior faces add new faces and vertex */
8884         numLeavesNew += 2 + 1;
8885       } else if ((p >= fMax) && (p < fEnd)) {
8886         /* Hybrid faces stay the same */
8887         ++numLeavesNew;
8888       } else if ((p >= cStart) && (p < cMax)) {
8889         /* Interior cells add new cells, interior faces, and vertex */
8890         numLeavesNew += 4 + 4 + 1;
8891       } else if ((p >= cMax) && (p < cEnd)) {
8892         /* Hybrid cells add new cells and hybrid face */
8893         numLeavesNew += 2 + 1;
8894       }
8895       break;
8896     case REFINER_SIMPLEX_3D:
8897     case REFINER_HYBRID_SIMPLEX_3D:
8898       if ((p >= vStart) && (p < vEnd)) {
8899         /* Interior vertices stay the same */
8900         ++numLeavesNew;
8901       } else if ((p >= eStart) && (p < eMax)) {
8902         /* Interior edges add new edges and vertex */
8903         numLeavesNew += 2 + 1;
8904       } else if ((p >= eMax) && (p < eEnd)) {
8905         /* Hybrid edges stay the same */
8906         ++numLeavesNew;
8907       } else if ((p >= fStart) && (p < fMax)) {
8908         /* Interior faces add new faces and edges */
8909         numLeavesNew += 4 + 3;
8910       } else if ((p >= fMax) && (p < fEnd)) {
8911         /* Hybrid faces add new faces and edges */
8912         numLeavesNew += 2 + 1;
8913       } else if ((p >= cStart) && (p < cMax)) {
8914         /* Interior cells add new cells, faces, and edges */
8915         numLeavesNew += 8 + 8 + 1;
8916       } else if ((p >= cMax) && (p < cEnd)) {
8917         /* Hybrid cells add new cells and faces */
8918         numLeavesNew += 4 + 3;
8919       }
8920       break;
8921     case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
8922     case REFINER_SIMPLEX_TO_HEX_3D:
8923       if ((p >= vStart) && (p < vEnd)) {
8924         /* Interior vertices stay the same */
8925         ++numLeavesNew;
8926       } else if ((p >= eStart) && (p < eMax)) {
8927         /* Interior edges add new edges and vertex */
8928         numLeavesNew += 2 + 1;
8929       } else if ((p >= eMax) && (p < eEnd)) {
8930         /* Hybrid edges stay the same */
8931         ++numLeavesNew;
8932       } else if ((p >= fStart) && (p < fMax)) {
8933         /* Interior faces add new faces, edges and a vertex */
8934         numLeavesNew += 3 + 3 + 1;
8935       } else if ((p >= fMax) && (p < fEnd)) {
8936         /* Hybrid faces add new faces and an edge */
8937         numLeavesNew += 2 + 1;
8938       } else if ((p >= cStart) && (p < cMax)) {
8939         /* Interior cells add new cells, faces, edges and a vertex */
8940         numLeavesNew += 4 + 6 + 4 + 1;
8941       } else if ((p >= cMax) && (p < cEnd)) {
8942         /* Hybrid cells add new cells, faces and an edge */
8943         numLeavesNew += 3 + 3 + 1;
8944       }
8945       break;
8946     case REFINER_HEX_3D:
8947     case REFINER_HYBRID_HEX_3D:
8948       if ((p >= vStart) && (p < vEnd)) {
8949         /* Old vertices stay the same */
8950         ++numLeavesNew;
8951       } else if ((p >= eStart) && (p < eMax)) {
8952         /* Interior edges add new edges, and vertex */
8953         numLeavesNew += 2 + 1;
8954       } else if ((p >= eMax) && (p < eEnd)) {
8955         /* Hybrid edges stay the same */
8956         ++numLeavesNew;
8957       } else if ((p >= fStart) && (p < fMax)) {
8958         /* Interior faces add new faces, edges, and vertex */
8959         numLeavesNew += 4 + 4 + 1;
8960       } else if ((p >= fMax) && (p < fEnd)) {
8961         /* Hybrid faces add new faces and edges */
8962         numLeavesNew += 2 + 1;
8963       } else if ((p >= cStart) && (p < cMax)) {
8964         /* Interior cells add new cells, faces, edges, and vertex */
8965         numLeavesNew += 8 + 12 + 6 + 1;
8966       } else if ((p >= cStart) && (p < cEnd)) {
8967         /* Hybrid cells add new cells, faces, and edges */
8968         numLeavesNew += 4 + 4 + 1;
8969       }
8970       break;
8971     default:
8972       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
8973     }
8974   }
8975   /* Communicate depthSizes for each remote rank */
8976   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
8977   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
8978   ierr = PetscMalloc5((depth+1)*numNeighbors,&rdepthSize,numNeighbors,&rvStartNew,numNeighbors,&reStartNew,numNeighbors,&rfStartNew,numNeighbors,&rcStartNew);CHKERRQ(ierr);
8979   ierr = PetscMalloc7(depth+1,&depthSizeOld,(depth+1)*numNeighbors,&rdepthSizeOld,(depth+1)*numNeighbors,&rdepthMaxOld,numNeighbors,&rvStart,numNeighbors,&reStart,numNeighbors,&rfStart,numNeighbors,&rcStart);CHKERRQ(ierr);
8980   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
8981   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
8982   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
8983   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
8984   for (n = 0; n < numNeighbors; ++n) {
8985     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
8986   }
8987   depthSizeOld[depth]   = cMax;
8988   depthSizeOld[0]       = vMax;
8989   depthSizeOld[depth-1] = fMax;
8990   depthSizeOld[1]       = eMax;
8991 
8992   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
8993   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
8994 
8995   depthSizeOld[depth]   = cEnd - cStart;
8996   depthSizeOld[0]       = vEnd - vStart;
8997   depthSizeOld[depth-1] = fEnd - fStart;
8998   depthSizeOld[1]       = eEnd - eStart;
8999 
9000   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
9001   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
9002   for (n = 0; n < numNeighbors; ++n) {
9003     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
9004     rdepthMaxOld[n*(depth+1)+depth]   = rdepthMaxOld[n*(depth+1)+depth]   < 0 ? rdepthSizeOld[n*(depth+1)+depth]  +rcStart[n]: rdepthMaxOld[n*(depth+1)+depth];
9005     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];
9006     rdepthMaxOld[n*(depth+1)+1]       = rdepthMaxOld[n*(depth+1)+1]       < 0 ? rdepthSizeOld[n*(depth+1)+1]      +reStart[n]: rdepthMaxOld[n*(depth+1)+1];
9007   }
9008   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
9009   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
9010   /* Calculate new point SF */
9011   ierr = PetscMalloc1(numLeavesNew, &localPointsNew);CHKERRQ(ierr);
9012   ierr = PetscMalloc1(numLeavesNew, &remotePointsNew);CHKERRQ(ierr);
9013   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
9014   for (l = 0, m = 0; l < numLeaves; ++l) {
9015     PetscInt    p     = localPoints[l];
9016     PetscInt    rp    = remotePoints[l].index, n;
9017     PetscMPIInt rrank = remotePoints[l].rank;
9018 
9019     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
9020     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
9021     switch (refiner) {
9022     case REFINER_SIMPLEX_1D:
9023       if ((p >= vStart) && (p < vEnd)) {
9024         /* Old vertices stay the same */
9025         localPointsNew[m]        = vStartNew     + (p  - vStart);
9026         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9027         remotePointsNew[m].rank  = rrank;
9028         ++m;
9029       } else if ((p >= cStart) && (p < cMax)) {
9030         /* Old interior cells add new cells and vertex */
9031         for (r = 0; r < 2; ++r, ++m) {
9032           localPointsNew[m]        = cStartNew     + (p  - cStart)*2     + r;
9033           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*2 + r;
9034           remotePointsNew[m].rank  = rrank;
9035         }
9036         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - cStart);
9037         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rcStart[n]);
9038         remotePointsNew[m].rank  = rrank;
9039         ++m;
9040       }
9041       break;
9042     case REFINER_SIMPLEX_2D:
9043     case REFINER_HYBRID_SIMPLEX_2D:
9044       if ((p >= vStart) && (p < vEnd)) {
9045         /* Old vertices stay the same */
9046         localPointsNew[m]        = vStartNew     + (p  - vStart);
9047         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9048         remotePointsNew[m].rank  = rrank;
9049         ++m;
9050       } else if ((p >= fStart) && (p < fMax)) {
9051         /* Old interior faces add new faces and vertex */
9052         for (r = 0; r < 2; ++r, ++m) {
9053           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
9054           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
9055           remotePointsNew[m].rank  = rrank;
9056         }
9057         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
9058         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
9059         remotePointsNew[m].rank  = rrank;
9060         ++m;
9061       } else if ((p >= fMax) && (p < fEnd)) {
9062         /* Old hybrid faces stay the same */
9063         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
9064         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
9065         remotePointsNew[m].rank  = rrank;
9066         ++m;
9067       } else if ((p >= cStart) && (p < cMax)) {
9068         /* Old interior cells add new cells and interior faces */
9069         for (r = 0; r < 4; ++r, ++m) {
9070           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
9071           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
9072           remotePointsNew[m].rank  = rrank;
9073         }
9074         for (r = 0; r < 3; ++r, ++m) {
9075           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
9076           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
9077           remotePointsNew[m].rank  = rrank;
9078         }
9079       } else if ((p >= cMax) && (p < cEnd)) {
9080         /* Old hybrid cells add new cells and hybrid face */
9081         for (r = 0; r < 2; ++r, ++m) {
9082           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
9083           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
9084           remotePointsNew[m].rank  = rrank;
9085         }
9086         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
9087         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]);
9088         remotePointsNew[m].rank  = rrank;
9089         ++m;
9090       }
9091       break;
9092     case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
9093     case REFINER_SIMPLEX_TO_HEX_2D:
9094       if ((p >= vStart) && (p < vEnd)) {
9095         /* Old vertices stay the same */
9096         localPointsNew[m]        = vStartNew     + (p  - vStart);
9097         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9098         remotePointsNew[m].rank  = rrank;
9099         ++m;
9100       } else if ((p >= fStart) && (p < fEnd)) {
9101         /* Old interior faces add new faces and vertex */
9102         for (r = 0; r < 2; ++r, ++m) {
9103           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
9104           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
9105           remotePointsNew[m].rank  = rrank;
9106         }
9107         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
9108         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
9109         remotePointsNew[m].rank  = rrank;
9110         ++m;
9111       } else if ((p >= cStart) && (p < cMax)) {
9112         /* Old interior cells add new cells, interior faces, and a vertex */
9113         for (r = 0; r < 3; ++r, ++m) {
9114           localPointsNew[m]        = cStartNew     + (p  - cStart)*3     + r;
9115           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*3 + r;
9116           remotePointsNew[m].rank  = rrank;
9117         }
9118         for (r = 0; r < 3; ++r, ++m) {
9119           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
9120           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
9121           remotePointsNew[m].rank  = rrank;
9122         }
9123         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (fEnd - fStart)                    + (p  - cStart);
9124         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
9125         remotePointsNew[m].rank  = rrank;
9126         ++m;
9127       } else if ((p >= cMax) && (p < cEnd)) {
9128         /* Old interior hybrid cells add new cells, interior faces, and a vertex */
9129         for (r = 0; r < 4; ++r, ++m) {
9130           localPointsNew[m]        = cStartNew     + (cMax  - cStart)*3                               + (p  - cMax)*4 + r;
9131           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*3 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
9132           remotePointsNew[m].rank  = rrank;
9133         }
9134         for (r = 0; r < 4; ++r, ++m) {
9135           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (cMax  - cStart)*3                               + (p - cMax)*4 + r;
9136           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*3 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
9137           remotePointsNew[m].rank  = rrank;
9138         }
9139         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (fEnd - fStart)                    + (p  - cStart);
9140         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
9141         remotePointsNew[m].rank  = rrank;
9142         ++m;
9143       }
9144       break;
9145     case REFINER_HEX_2D:
9146     case REFINER_HYBRID_HEX_2D:
9147       if ((p >= vStart) && (p < vEnd)) {
9148         /* Old vertices stay the same */
9149         localPointsNew[m]        = vStartNew     + (p  - vStart);
9150         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9151         remotePointsNew[m].rank  = rrank;
9152         ++m;
9153       } else if ((p >= fStart) && (p < fMax)) {
9154         /* Old interior faces add new faces and vertex */
9155         for (r = 0; r < 2; ++r, ++m) {
9156           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
9157           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
9158           remotePointsNew[m].rank  = rrank;
9159         }
9160         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
9161         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
9162         remotePointsNew[m].rank  = rrank;
9163         ++m;
9164       } else if ((p >= fMax) && (p < fEnd)) {
9165         /* Old hybrid faces stay the same */
9166         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
9167         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
9168         remotePointsNew[m].rank  = rrank;
9169         ++m;
9170       } else if ((p >= cStart) && (p < cMax)) {
9171         /* Old interior cells add new cells, interior faces, and vertex */
9172         for (r = 0; r < 4; ++r, ++m) {
9173           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
9174           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
9175           remotePointsNew[m].rank  = rrank;
9176         }
9177         for (r = 0; r < 4; ++r, ++m) {
9178           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*4     + r;
9179           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*4 + r;
9180           remotePointsNew[m].rank  = rrank;
9181         }
9182         localPointsNew[m]        = vStartNew     + (vEnd - vStart)               + (fMax                              - fStart)     + (p  - cStart);
9183         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0]  + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]);
9184         remotePointsNew[m].rank  = rrank;
9185         ++m;
9186       } else if ((p >= cStart) && (p < cMax)) {
9187         /* Old hybrid cells add new cells and hybrid face */
9188         for (r = 0; r < 2; ++r, ++m) {
9189           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r; /* TODO: is this a bug? */
9190           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r; /* TODO: is this a bug? */
9191           remotePointsNew[m].rank  = rrank;
9192         }
9193         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*4     + (p  - cMax);
9194         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]);
9195         remotePointsNew[m].rank  = rrank;
9196         ++m;
9197       }
9198       break;
9199     case REFINER_SIMPLEX_3D:
9200     case REFINER_HYBRID_SIMPLEX_3D:
9201       if ((p >= vStart) && (p < vEnd)) {
9202         /* Interior vertices stay the same */
9203         localPointsNew[m]        = vStartNew     + (p  - vStart);
9204         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9205         remotePointsNew[m].rank  = rrank;
9206         ++m;
9207       } else if ((p >= eStart) && (p < eMax)) {
9208         /* Interior edges add new edges and vertex */
9209         for (r = 0; r < 2; ++r, ++m) {
9210           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
9211           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
9212           remotePointsNew[m].rank  = rrank;
9213         }
9214         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
9215         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
9216         remotePointsNew[m].rank  = rrank;
9217         ++m;
9218       } else if ((p >= eMax) && (p < eEnd)) {
9219         /* Hybrid edges stay the same */
9220         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - eMax);
9221         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]);
9222         remotePointsNew[m].rank  = rrank;
9223         ++m;
9224       } else if ((p >= fStart) && (p < fMax)) {
9225         /* Interior faces add new faces and edges */
9226         for (r = 0; r < 4; ++r, ++m) {
9227           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
9228           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
9229           remotePointsNew[m].rank  = rrank;
9230         }
9231         for (r = 0; r < 3; ++r, ++m) {
9232           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*3     + r;
9233           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
9234           remotePointsNew[m].rank  = rrank;
9235         }
9236       } else if ((p >= fMax) && (p < fEnd)) {
9237         /* Hybrid faces add new faces and edges */
9238         for (r = 0; r < 2; ++r, ++m) {
9239           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fMax)*2                              + r;
9240           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;
9241           remotePointsNew[m].rank  = rrank;
9242         }
9243         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (eEnd                                    - eMax)                        + (p  - fMax);
9244         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]);
9245         remotePointsNew[m].rank  = rrank;
9246         ++m;
9247       } else if ((p >= cStart) && (p < cMax)) {
9248         /* Interior cells add new cells, faces, and edges */
9249         for (r = 0; r < 8; ++r, ++m) {
9250           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
9251           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
9252           remotePointsNew[m].rank  = rrank;
9253         }
9254         for (r = 0; r < 8; ++r, ++m) {
9255           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*8     + r;
9256           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*8 + r;
9257           remotePointsNew[m].rank  = rrank;
9258         }
9259         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (p  - cStart)*1     + 0;
9260         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;
9261         remotePointsNew[m].rank  = rrank;
9262         ++m;
9263       } else if ((p >= cMax) && (p < cEnd)) {
9264         /* Hybrid cells add new cells and faces */
9265         for (r = 0; r < 4; ++r, ++m) {
9266           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
9267           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
9268           remotePointsNew[m].rank  = rrank;
9269         }
9270         for (r = 0; r < 3; ++r, ++m) {
9271           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*2                              + (p  - cMax)*3                            + r;
9272           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;
9273           remotePointsNew[m].rank  = rrank;
9274         }
9275       }
9276       break;
9277     case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
9278     case REFINER_SIMPLEX_TO_HEX_3D:
9279       if ((p >= vStart) && (p < vEnd)) {
9280         /* Interior vertices stay the same */
9281         localPointsNew[m]        = vStartNew     + (p  - vStart);
9282         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9283         remotePointsNew[m].rank  = rrank;
9284         ++m;
9285       } else if ((p >= eStart) && (p < eMax)) {
9286         /* Interior edges add new edges and vertex */
9287         for (r = 0; r < 2; ++r, ++m) {
9288           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
9289           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
9290           remotePointsNew[m].rank  = rrank;
9291         }
9292         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
9293         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
9294         remotePointsNew[m].rank  = rrank;
9295         ++m;
9296       } else if ((p >= eMax) && (p < eEnd)) {
9297         /* Hybrid edges stay the same */
9298         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)*4     + (p  - eMax);
9299         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])*4 + (rp - rdepthMaxOld[n*(depth+1)+1]);
9300         remotePointsNew[m].rank  = rrank;
9301         ++m;
9302       } else if ((p >= fStart) && (p < fMax)) {
9303         /* Interior faces add new faces, edges and a vertex */
9304         for (r = 0; r < 3; ++r, ++m) {
9305           localPointsNew[m]        = fStartNew     + (p  - fStart)*3     + r;
9306           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*3 + r;
9307           remotePointsNew[m].rank  = rrank;
9308         }
9309         for (r = 0; r < 3; ++r, ++m) {
9310           localPointsNew[m]        = eStartNew     + (eMax - eStart)*2                            + (p  - fStart)*3     + r;
9311           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
9312           remotePointsNew[m].rank  = rrank;
9313         }
9314         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax - eStart)                            + (p - fStart);
9315         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
9316         remotePointsNew[m].rank  = rrank;
9317         ++m;
9318       } else if ((p >= fMax) && (p < fEnd)) {
9319         /* Interior hybrid faces add new faces and an edge */
9320         for (r = 0; r < 2; ++r, ++m) {
9321           localPointsNew[m]        = fStartNew     + (fMax - fStart)*3                                 + (cMax - cStart)*6                                + (p  - fMax)*2 + r;
9322           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1]- rfStart[n])*3 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*6 + (rp - rdepthMaxOld[n*(depth+1)+depth-1])*2 + r;
9323           remotePointsNew[m].rank  = rrank;
9324         }
9325         localPointsNew[m]        = eStartNew     + (eMax - eStart)*2                            + (fMax - fStart)*3                                 + (cMax - cStart)*4                                + (eEnd - eMax)                                                           + (p  - fMax);
9326         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])*4 + (rdepthSizeOld[n*(depth+1)+1]+reStart[n] - rdepthMaxOld[n*(depth+1)+1]) + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
9327         remotePointsNew[m].rank  = rrank;
9328         ++m;
9329       } else if ((p >= cStart) && (p < cMax)) {
9330         /* Interior cells add new cells, faces, edges, and a vertex */
9331         for (r = 0; r < 4; ++r, ++m) {
9332           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
9333           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
9334           remotePointsNew[m].rank  = rrank;
9335         }
9336         for (r = 0; r < 6; ++r, ++m) {
9337           localPointsNew[m]        = fStartNew     + (fMax - fStart)*3                                 + (p  - cStart)*6     + r;
9338           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1]- rfStart[n])*3 + (rp - rcStart[n])*6 + r;
9339           remotePointsNew[m].rank  = rrank;
9340         }
9341         for (r = 0; r < 4; ++r, ++m) {
9342           localPointsNew[m]        = eStartNew     + (eMax - eStart)*2                           + (fMax - fStart)*3                                 + (p  - cStart)*4 + r;
9343           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])*4 + r;
9344           remotePointsNew[m].rank  = rrank;
9345         }
9346         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax - eStart)                           + (fMax - fStart)                                 + (p  - cStart);
9347         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1]- reStart[n]) + (rdepthMaxOld[n*(depth+1)+depth-1]- rfStart[n]) + (rp - rcStart[n]);
9348         remotePointsNew[m].rank  = rrank;
9349         ++m;
9350       } else if ((p >= cMax) && (p < cEnd)) {
9351         /* Interior hybrid cells add new cells, faces and an edge */
9352         for (r = 0; r < 3; ++r, ++m) {
9353           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*4     + (p  - cMax)*3                            + r;
9354           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*4 + (rp - rdepthMaxOld[n*(depth+1)+depth])*3 + r;
9355           remotePointsNew[m].rank  = rrank;
9356         }
9357         for (r = 0; r < 3; ++r, ++m) {
9358           localPointsNew[m]        = fStartNew     + (fMax - fStart)*3                                 + (cMax - cStart)*6                                + (fEnd  - fMax)*2                                                                      + (p  - cMax)*3 + r;
9359           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1]- rfStart[n])*3 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*6 + (rdepthSizeOld[n*(depth+1)+depth-1]+rfStart[n] - rdepthMaxOld[n*(depth+1)+depth-1])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth])*3 + r;
9360           remotePointsNew[m].rank  = rrank;
9361         }
9362         localPointsNew[m]        = eStartNew     + (eMax - eStart)*2                           + (fMax - fStart)*3                                 + (cMax - cStart)*4                                + (eEnd  - eMax)                                                          + (fEnd  - fMax)                                                                      + (p  - cMax);
9363         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])*4 + (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]);
9364         remotePointsNew[m].rank  = rrank;
9365         ++m;
9366       }
9367       break;
9368     case REFINER_HEX_3D:
9369     case REFINER_HYBRID_HEX_3D:
9370       if ((p >= vStart) && (p < vEnd)) {
9371         /* Interior vertices stay the same */
9372         localPointsNew[m]        = vStartNew     + (p  - vStart);
9373         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9374         remotePointsNew[m].rank  = rrank;
9375         ++m;
9376       } else if ((p >= eStart) && (p < eMax)) {
9377         /* Interior edges add new edges and vertex */
9378         for (r = 0; r < 2; ++r, ++m) {
9379           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
9380           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
9381           remotePointsNew[m].rank  = rrank;
9382         }
9383         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
9384         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
9385         remotePointsNew[m].rank  = rrank;
9386         ++m;
9387       } else if ((p >= eMax) && (p < eEnd)) {
9388         /* Hybrid edges stay the same */
9389         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (p  - eMax);
9390         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]);
9391         remotePointsNew[m].rank  = rrank;
9392         ++m;
9393       } else if ((p >= fStart) && (p < fMax)) {
9394         /* Interior faces add new faces, edges, and vertex */
9395         for (r = 0; r < 4; ++r, ++m) {
9396           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
9397           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
9398           remotePointsNew[m].rank  = rrank;
9399         }
9400         for (r = 0; r < 4; ++r, ++m) {
9401           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*4     + r;
9402           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*4 + r;
9403           remotePointsNew[m].rank  = rrank;
9404         }
9405         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax                        - eStart)     + (p  - fStart);
9406         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
9407         remotePointsNew[m].rank  = rrank;
9408         ++m;
9409       } else if ((p >= fMax) && (p < fEnd)) {
9410         /* Hybrid faces add new faces and edges */
9411         for (r = 0; r < 2; ++r, ++m) {
9412           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (p  - fMax)*2                              + r;
9413           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;
9414           remotePointsNew[m].rank  = rrank;
9415         }
9416         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (p  - fMax);
9417         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]);
9418         remotePointsNew[m].rank  = rrank;
9419         ++m;
9420       } else if ((p >= cStart) && (p < cMax)) {
9421         /* Interior cells add new cells, faces, edges, and vertex */
9422         for (r = 0; r < 8; ++r, ++m) {
9423           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
9424           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
9425           remotePointsNew[m].rank  = rrank;
9426         }
9427         for (r = 0; r < 12; ++r, ++m) {
9428           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*12     + r;
9429           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*12 + r;
9430           remotePointsNew[m].rank  = rrank;
9431         }
9432         for (r = 0; r < 6; ++r, ++m) {
9433           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (p  - cStart)*6     + r;
9434           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;
9435           remotePointsNew[m].rank  = rrank;
9436         }
9437         for (r = 0; r < 1; ++r, ++m) {
9438           localPointsNew[m]        = vStartNew     + (eMax                        - eStart)     + (fMax                              - fStart)     + (p  - cStart)     + r;
9439           remotePointsNew[m].index = rvStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]) + r;
9440           remotePointsNew[m].rank  = rrank;
9441         }
9442       } else if ((p >= cMax) && (p < cEnd)) {
9443         /* Hybrid cells add new cells, faces, and edges */
9444         for (r = 0; r < 4; ++r, ++m) {
9445           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
9446           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
9447           remotePointsNew[m].rank  = rrank;
9448         }
9449         for (r = 0; r < 4; ++r, ++m) {
9450           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (fEnd                                          - fMax)*2                              + (p  - cMax)*4                            + r;
9451           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;
9452           remotePointsNew[m].rank  = rrank;
9453         }
9454         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (fEnd                                          - fMax)                              + (p  - cMax);
9455         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]);
9456         remotePointsNew[m].rank  = rrank;
9457         ++m;
9458       }
9459       break;
9460     default:
9461       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
9462     }
9463   }
9464   if (m != numLeavesNew) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of leaf point %d should be %d", m, numLeavesNew);
9465   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
9466   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
9467   {
9468     PetscSFNode *rp, *rtmp;
9469     PetscInt    *lp, *idx, *ltmp, i;
9470 
9471     /* SF needs sorted leaves to correct calculate Gather */
9472     ierr = PetscMalloc1(numLeavesNew,&idx);CHKERRQ(ierr);
9473     ierr = PetscMalloc1(numLeavesNew, &lp);CHKERRQ(ierr);
9474     ierr = PetscMalloc1(numLeavesNew, &rp);CHKERRQ(ierr);
9475     for (i = 0; i < numLeavesNew; ++i) {
9476       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);
9477       idx[i] = i;
9478     }
9479     ierr = PetscSortIntWithPermutation(numLeavesNew, localPointsNew, idx);CHKERRQ(ierr);
9480     for (i = 0; i < numLeavesNew; ++i) {
9481       lp[i] = localPointsNew[idx[i]];
9482       rp[i] = remotePointsNew[idx[i]];
9483     }
9484     ltmp            = localPointsNew;
9485     localPointsNew  = lp;
9486     rtmp            = remotePointsNew;
9487     remotePointsNew = rp;
9488     ierr = PetscFree(idx);CHKERRQ(ierr);
9489     ierr = PetscFree(ltmp);CHKERRQ(ierr);
9490     ierr = PetscFree(rtmp);CHKERRQ(ierr);
9491   }
9492   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
9493   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
9494   ierr = PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
9495   PetscFunctionReturn(0);
9496 }
9497 
9498 static PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
9499 {
9500   PetscInt       numLabels, l;
9501   PetscInt       depth, newp, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r;
9502   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
9503   PetscErrorCode ierr;
9504 
9505   PetscFunctionBegin;
9506   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9507   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
9508   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9509   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
9510   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
9511   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
9512   ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
9513   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
9514   switch (refiner) {
9515   case REFINER_NOOP:
9516   case REFINER_SIMPLEX_1D:
9517   case REFINER_SIMPLEX_2D:
9518   case REFINER_SIMPLEX_TO_HEX_2D:
9519   case REFINER_HEX_2D:
9520   case REFINER_SIMPLEX_3D:
9521   case REFINER_HEX_3D:
9522   case REFINER_SIMPLEX_TO_HEX_3D:
9523     break;
9524   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
9525   case REFINER_HYBRID_SIMPLEX_3D:
9526   case REFINER_HYBRID_HEX_3D:
9527     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
9528   case REFINER_HYBRID_SIMPLEX_2D:
9529   case REFINER_HYBRID_HEX_2D:
9530     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
9531   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
9532     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
9533     break;
9534   default:
9535     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
9536   }
9537   cMax = cMax < 0 ? cEnd : cMax;
9538   fMax = fMax < 0 ? fEnd : fMax;
9539   eMax = eMax < 0 ? eEnd : eMax;
9540   for (l = 0; l < numLabels; ++l) {
9541     DMLabel         label, labelNew;
9542     const char     *lname;
9543     PetscBool       isDepth;
9544     IS              valueIS;
9545     const PetscInt *values;
9546     PetscInt        defVal;
9547     PetscInt        numValues, val;
9548 
9549     ierr = DMGetLabelName(dm, l, &lname);CHKERRQ(ierr);
9550     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
9551     if (isDepth) continue;
9552     ierr = DMCreateLabel(rdm, lname);CHKERRQ(ierr);
9553     ierr = DMGetLabel(dm, lname, &label);CHKERRQ(ierr);
9554     ierr = DMGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
9555     ierr = DMLabelGetDefaultValue(label,&defVal);CHKERRQ(ierr);
9556     ierr = DMLabelSetDefaultValue(labelNew,defVal);CHKERRQ(ierr);
9557     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
9558     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
9559     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
9560     for (val = 0; val < numValues; ++val) {
9561       IS              pointIS;
9562       const PetscInt *points;
9563       PetscInt        numPoints, n;
9564 
9565       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
9566       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
9567       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
9568       /* Ensure refined label is created with same number of strata as
9569        * original (even if no entries here). */
9570       ierr = DMLabelAddStratum(labelNew, values[val]);CHKERRQ(ierr);
9571       for (n = 0; n < numPoints; ++n) {
9572         const PetscInt p = points[n];
9573         switch (refiner) {
9574         case REFINER_SIMPLEX_1D:
9575           if ((p >= vStart) && (p < vEnd)) {
9576             /* Old vertices stay the same */
9577             newp = vStartNew + (p - vStart);
9578             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9579           } else if ((p >= cStart) && (p < cEnd)) {
9580             /* Old cells add new cells and vertex */
9581             newp = vStartNew + (vEnd - vStart) + (p - cStart);
9582             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9583             for (r = 0; r < 2; ++r) {
9584               newp = cStartNew + (p - cStart)*2 + r;
9585               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9586             }
9587           }
9588           break;
9589         case REFINER_SIMPLEX_2D:
9590           if ((p >= vStart) && (p < vEnd)) {
9591             /* Old vertices stay the same */
9592             newp = vStartNew + (p - vStart);
9593             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9594           } else if ((p >= fStart) && (p < fEnd)) {
9595             /* Old faces add new faces and vertex */
9596             newp = vStartNew + (vEnd - vStart) + (p - fStart);
9597             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9598             for (r = 0; r < 2; ++r) {
9599               newp = fStartNew + (p - fStart)*2 + r;
9600               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9601             }
9602           } else if ((p >= cStart) && (p < cEnd)) {
9603             /* Old cells add new cells and interior faces */
9604             for (r = 0; r < 4; ++r) {
9605               newp = cStartNew + (p - cStart)*4 + r;
9606               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9607             }
9608             for (r = 0; r < 3; ++r) {
9609               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
9610               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9611             }
9612           }
9613           break;
9614         case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
9615         case REFINER_SIMPLEX_TO_HEX_2D:
9616           if ((p >= vStart) && (p < vEnd)) {
9617             /* Old vertices stay the same */
9618             newp = vStartNew + (p - vStart);
9619             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9620           } else if ((p >= fStart) && (p < fEnd)) {
9621             /* Old faces add new faces and vertex */
9622             newp = vStartNew + (vEnd - vStart) + (p - fStart);
9623             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9624             for (r = 0; r < 2; ++r) {
9625               newp = fStartNew + (p - fStart)*2 + r;
9626               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9627             }
9628           } else if ((p >= cStart) && (p < cMax)) {
9629             /* Old cells add new cells, interior faces, and a vertex */
9630             for (r = 0; r < 3; ++r) {
9631               newp = cStartNew + (p - cStart)*3 + r;
9632               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9633             }
9634             for (r = 0; r < 3; ++r) {
9635               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
9636               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9637             }
9638             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + p;
9639             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9640           } else if ((p >= cMax) && (p < cEnd)) {
9641             /* Old hybrid cells add new cells, interior faces, and a vertex */
9642             for (r = 0; r < 4; ++r) {
9643               newp = cStartNew + (cMax - cStart)*3 + (p - cMax)*4 + r;
9644               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9645             }
9646             for (r = 0; r < 4; ++r) {
9647               newp = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (p - cMax)*4 + r;
9648               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9649             }
9650             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + p;
9651             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9652           }
9653           break;
9654         case REFINER_HEX_2D:
9655           if ((p >= vStart) && (p < vEnd)) {
9656             /* Old vertices stay the same */
9657             newp = vStartNew + (p - vStart);
9658             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9659           } else if ((p >= fStart) && (p < fEnd)) {
9660             /* Old faces add new faces and vertex */
9661             newp = vStartNew + (vEnd - vStart) + (p - fStart);
9662             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9663             for (r = 0; r < 2; ++r) {
9664               newp = fStartNew + (p - fStart)*2 + r;
9665               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9666             }
9667           } else if ((p >= cStart) && (p < cEnd)) {
9668             /* Old cells add new cells and interior faces and vertex */
9669             for (r = 0; r < 4; ++r) {
9670               newp = cStartNew + (p - cStart)*4 + r;
9671               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9672             }
9673             for (r = 0; r < 4; ++r) {
9674               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
9675               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9676             }
9677             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
9678             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9679           }
9680           break;
9681         case REFINER_HYBRID_SIMPLEX_2D:
9682           if ((p >= vStart) && (p < vEnd)) {
9683             /* Old vertices stay the same */
9684             newp = vStartNew + (p - vStart);
9685             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9686           } else if ((p >= fStart) && (p < fMax)) {
9687             /* Old interior faces add new faces and vertex */
9688             newp = vStartNew + (vEnd - vStart) + (p - fStart);
9689             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9690             for (r = 0; r < 2; ++r) {
9691               newp = fStartNew + (p - fStart)*2 + r;
9692               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9693             }
9694           } else if ((p >= fMax) && (p < fEnd)) {
9695             /* Old hybrid faces stay the same */
9696             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
9697             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9698           } else if ((p >= cStart) && (p < cMax)) {
9699             /* Old interior cells add new cells and interior faces */
9700             for (r = 0; r < 4; ++r) {
9701               newp = cStartNew + (p - cStart)*4 + r;
9702               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9703             }
9704             for (r = 0; r < 3; ++r) {
9705               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
9706               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9707             }
9708           } else if ((p >= cMax) && (p < cEnd)) {
9709             /* Old hybrid cells add new cells and hybrid face */
9710             for (r = 0; r < 2; ++r) {
9711               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
9712               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9713             }
9714             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
9715             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9716           }
9717           break;
9718         case REFINER_HYBRID_HEX_2D:
9719           if ((p >= vStart) && (p < vEnd)) {
9720             /* Old vertices stay the same */
9721             newp = vStartNew + (p - vStart);
9722             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9723           } else if ((p >= fStart) && (p < fMax)) {
9724             /* Old interior faces add new faces and vertex */
9725             newp = vStartNew + (vEnd - vStart) + (p - fStart);
9726             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9727             for (r = 0; r < 2; ++r) {
9728               newp = fStartNew + (p - fStart)*2 + r;
9729               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9730             }
9731           } else if ((p >= fMax) && (p < fEnd)) {
9732             /* Old hybrid faces stay the same */
9733             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
9734             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9735           } else if ((p >= cStart) && (p < cMax)) {
9736             /* Old interior cells add new cells, interior faces, and vertex */
9737             for (r = 0; r < 4; ++r) {
9738               newp = cStartNew + (p - cStart)*4 + r;
9739               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9740             }
9741             for (r = 0; r < 4; ++r) {
9742               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
9743               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9744             }
9745             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
9746             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9747           } else if ((p >= cMax) && (p < cEnd)) {
9748             /* Old hybrid cells add new cells and hybrid face */
9749             for (r = 0; r < 2; ++r) {
9750               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
9751               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9752             }
9753             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (p - cMax);
9754             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9755           }
9756           break;
9757         case REFINER_SIMPLEX_3D:
9758           if ((p >= vStart) && (p < vEnd)) {
9759             /* Old vertices stay the same */
9760             newp = vStartNew + (p - vStart);
9761             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9762           } else if ((p >= eStart) && (p < eEnd)) {
9763             /* Old edges add new edges and vertex */
9764             for (r = 0; r < 2; ++r) {
9765               newp = eStartNew + (p - eStart)*2 + r;
9766               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9767             }
9768             newp = vStartNew + (vEnd - vStart) + (p - eStart);
9769             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9770           } else if ((p >= fStart) && (p < fEnd)) {
9771             /* Old faces add new faces and edges */
9772             for (r = 0; r < 4; ++r) {
9773               newp = fStartNew + (p - fStart)*4 + r;
9774               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9775             }
9776             for (r = 0; r < 3; ++r) {
9777               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
9778               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9779             }
9780           } else if ((p >= cStart) && (p < cEnd)) {
9781             /* Old cells add new cells and interior faces and edges */
9782             for (r = 0; r < 8; ++r) {
9783               newp = cStartNew + (p - cStart)*8 + r;
9784               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9785             }
9786             for (r = 0; r < 8; ++r) {
9787               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*8 + r;
9788               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9789             }
9790             for (r = 0; r < 1; ++r) {
9791               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*1 + r;
9792               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9793             }
9794           }
9795           break;
9796         case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
9797         case REFINER_SIMPLEX_TO_HEX_3D:
9798           if ((p >= vStart) && (p < vEnd)) {
9799             /* Old vertices stay the same */
9800             newp = vStartNew + (p - vStart);
9801             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9802           } else if ((p >= eStart) && (p < eMax)) {
9803             /* Interior edges add new edges and vertex */
9804             for (r = 0; r < 2; ++r) {
9805               newp = eStartNew + (p - eStart)*2 + r;
9806               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9807             }
9808             newp = vStartNew + (vEnd - vStart) + (p - eStart);
9809             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9810           } else if ((p >= eMax) && (p < eEnd)) {
9811             /* Hybrid edges stay the same */
9812             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + p - eMax;
9813             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9814           } else if ((p >= fStart) && (p < fMax)) {
9815             /* Old faces add new faces, edges and a vertex */
9816             for (r = 0; r < 3; ++r) {
9817               newp = fStartNew + (p - fStart)*3 + r;
9818               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9819             }
9820             for (r = 0; r < 3; ++r) {
9821               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
9822               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9823             }
9824           } else if ((p >= fMax) && (p < fEnd)) {
9825             /* Old hybrid faces add new faces and an edge */
9826             for (r = 0; r < 2; ++r) {
9827               newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (p - fMax)*2 + r;
9828               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9829             }
9830             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (p - fMax);
9831             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9832           } else if ((p >= cStart) && (p < cMax)) {
9833             /* Old cells add new cells and interior faces and edges and a vertex */
9834             for (r = 0; r < 4; ++r) {
9835               newp = cStartNew + (p - cStart)*4 + r;
9836               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9837             }
9838             for (r = 0; r < 6; ++r) {
9839               newp = fStartNew + (fMax - fStart)*3 + (p - cStart)*6 + r;
9840               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9841             }
9842             for (r = 0; r < 4; ++r) {
9843               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart)*4 + r;
9844               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9845             }
9846             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + p - cStart;
9847             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9848           } else if ((p >= cMax) && (p < cEnd)) {
9849             /* Old hybrid cells add new cells and interior faces and an edge */
9850             for (r = 0; r < 3; ++r) {
9851               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*3 + r;
9852               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9853             }
9854             for (r = 0; r < 3; ++r) {
9855               newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
9856               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9857             }
9858             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + p - cMax;
9859             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9860           }
9861           break;
9862         case REFINER_HYBRID_SIMPLEX_3D:
9863           if ((p >= vStart) && (p < vEnd)) {
9864             /* Interior vertices stay the same */
9865             newp = vStartNew + (p - vStart);
9866             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9867           } else if ((p >= eStart) && (p < eMax)) {
9868             /* Interior edges add new edges and vertex */
9869             for (r = 0; r < 2; ++r) {
9870               newp = eStartNew + (p - eStart)*2 + r;
9871               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9872             }
9873             newp = vStartNew + (vEnd - vStart) + (p - eStart);
9874             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9875           } else if ((p >= eMax) && (p < eEnd)) {
9876             /* Hybrid edges stay the same */
9877             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - eMax);
9878             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9879           } else if ((p >= fStart) && (p < fMax)) {
9880             /* Interior faces add new faces and edges */
9881             for (r = 0; r < 4; ++r) {
9882               newp = fStartNew + (p - fStart)*4 + r;
9883               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9884             }
9885             for (r = 0; r < 3; ++r) {
9886               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
9887               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9888             }
9889           } else if ((p >= fMax) && (p < fEnd)) {
9890             /* Hybrid faces add new faces and edges */
9891             for (r = 0; r < 2; ++r) {
9892               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (p - fMax)*2 + r;
9893               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9894             }
9895             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - fMax);
9896             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9897           } else if ((p >= cStart) && (p < cMax)) {
9898             /* Interior cells add new cells, faces, and edges */
9899             for (r = 0; r < 8; ++r) {
9900               newp = cStartNew + (p - cStart)*8 + r;
9901               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9902             }
9903             for (r = 0; r < 8; ++r) {
9904               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*8 + r;
9905               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9906             }
9907             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart);
9908             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9909           } else if ((p >= cMax) && (p < cEnd)) {
9910             /* Hybrid cells add new cells and faces */
9911             for (r = 0; r < 4; ++r) {
9912               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
9913               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9914             }
9915             for (r = 0; r < 3; ++r) {
9916               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
9917               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9918             }
9919           }
9920           break;
9921         case REFINER_HEX_3D:
9922           if ((p >= vStart) && (p < vEnd)) {
9923             /* Old vertices stay the same */
9924             newp = vStartNew + (p - vStart);
9925             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9926           } else if ((p >= eStart) && (p < eEnd)) {
9927             /* Old edges add new edges and vertex */
9928             for (r = 0; r < 2; ++r) {
9929               newp = eStartNew + (p - eStart)*2 + r;
9930               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9931             }
9932             newp = vStartNew + (vEnd - vStart) + (p - eStart);
9933             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9934           } else if ((p >= fStart) && (p < fEnd)) {
9935             /* Old faces add new faces, edges, and vertex */
9936             for (r = 0; r < 4; ++r) {
9937               newp = fStartNew + (p - fStart)*4 + r;
9938               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9939             }
9940             for (r = 0; r < 4; ++r) {
9941               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*4 + r;
9942               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9943             }
9944             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (p - fStart);
9945             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9946           } else if ((p >= cStart) && (p < cEnd)) {
9947             /* Old cells add new cells, faces, edges, and vertex */
9948             for (r = 0; r < 8; ++r) {
9949               newp = cStartNew + (p - cStart)*8 + r;
9950               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9951             }
9952             for (r = 0; r < 12; ++r) {
9953               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*12 + r;
9954               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9955             }
9956             for (r = 0; r < 6; ++r) {
9957               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (p - cStart)*6 + r;
9958               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9959             }
9960             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (p - cStart);
9961             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9962           }
9963           break;
9964         case REFINER_HYBRID_HEX_3D:
9965           if ((p >= vStart) && (p < vEnd)) {
9966             /* Interior vertices stay the same */
9967             newp = vStartNew + (p - vStart);
9968             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9969           } else if ((p >= eStart) && (p < eMax)) {
9970             /* Interior edges add new edges and vertex */
9971             for (r = 0; r < 2; ++r) {
9972               newp = eStartNew + (p - eStart)*2 + r;
9973               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9974             }
9975             newp = vStartNew + (vEnd - vStart) + (p - eStart);
9976             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9977           } else if ((p >= eMax) && (p < eEnd)) {
9978             /* Hybrid edges stay the same */
9979             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - eMax);
9980             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9981           } else if ((p >= fStart) && (p < fMax)) {
9982             /* Interior faces add new faces, edges, and vertex */
9983             for (r = 0; r < 4; ++r) {
9984               newp = fStartNew + (p - fStart)*4 + r;
9985               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9986             }
9987             for (r = 0; r < 4; ++r) {
9988               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*4 + r;
9989               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9990             }
9991             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (p - fStart);
9992             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9993           } else if ((p >= fMax) && (p < fEnd)) {
9994             /* Hybrid faces add new faces and edges */
9995             for (r = 0; r < 2; ++r) {
9996               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (p - fMax)*2 + r;
9997               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9998             }
9999             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - fMax);
10000             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10001           } else if ((p >= cStart) && (p < cMax)) {
10002             /* Interior cells add new cells, faces, edges, and vertex */
10003             for (r = 0; r < 8; ++r) {
10004               newp = cStartNew + (p - cStart)*8 + r;
10005               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10006             }
10007             for (r = 0; r < 12; ++r) {
10008               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*12 + r;
10009               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10010             }
10011             for (r = 0; r < 6; ++r) {
10012               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (p - cStart)*6 + r;
10013               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10014             }
10015             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (p - cStart);
10016             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10017           } else if ((p >= cMax) && (p < cEnd)) {
10018             /* Hybrid cells add new cells, faces, and edges */
10019             for (r = 0; r < 4; ++r) {
10020               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
10021               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10022             }
10023             for (r = 0; r < 4; ++r) {
10024               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (p - cMax)*4 + r;
10025               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10026             }
10027             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (fEnd - fMax) + (p - cMax);
10028             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10029           }
10030           break;
10031         default:
10032           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
10033         }
10034       }
10035       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
10036       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
10037     }
10038     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
10039     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
10040     if (0) {
10041       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
10042     }
10043   }
10044   PetscFunctionReturn(0);
10045 }
10046 
10047 /* This will only work for interpolated meshes */
10048 PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
10049 {
10050   DM             rdm;
10051   PetscInt      *depthSize;
10052   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
10053   PetscErrorCode ierr;
10054 
10055   PetscFunctionBegin;
10056   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
10057   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
10058   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
10059   ierr = DMSetDimension(rdm, dim);CHKERRQ(ierr);
10060   /* Calculate number of new points of each depth */
10061   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
10062   if (depth >= 0 && dim != depth) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Mesh must be interpolated for regular refinement");
10063   ierr = PetscMalloc1(depth+1, &depthSize);CHKERRQ(ierr);
10064   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
10065   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
10066   /* Step 1: Set chart */
10067   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
10068   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
10069   /* Step 2: Set cone/support sizes (automatically stratifies) */
10070   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
10071   /* Step 3: Setup refined DM */
10072   ierr = DMSetUp(rdm);CHKERRQ(ierr);
10073   /* Step 4: Set cones and supports (automatically symmetrizes) */
10074   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
10075   /* Step 5: Create pointSF */
10076   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
10077   /* Step 6: Create labels */
10078   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
10079   /* Step 7: Set coordinates */
10080   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
10081   ierr = PetscFree(depthSize);CHKERRQ(ierr);
10082 
10083   *dmRefined = rdm;
10084   PetscFunctionReturn(0);
10085 }
10086 
10087 /*@
10088   DMPlexCreateCoarsePointIS - Creates an IS covering the coarse DM chart with the fine points as data
10089 
10090   Input Parameter:
10091 . dm - The coarse DM
10092 
10093   Output Parameter:
10094 . fpointIS - The IS of all the fine points which exist in the original coarse mesh
10095 
10096   Level: developer
10097 
10098 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexCreateSubpointIS()
10099 @*/
10100 PetscErrorCode DMPlexCreateCoarsePointIS(DM dm, IS *fpointIS)
10101 {
10102   CellRefiner    cellRefiner;
10103   PetscInt      *depthSize, *fpoints;
10104   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
10105   PetscInt       depth, pStart, pEnd, p, vStart, vEnd, v;
10106   PetscErrorCode ierr;
10107 
10108   PetscFunctionBegin;
10109   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
10110   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
10111   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10112   ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr);
10113   ierr = PetscMalloc1(depth+1, &depthSize);CHKERRQ(ierr);
10114   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
10115   if (cellRefiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
10116   ierr = PetscMalloc1(pEnd-pStart,&fpoints);CHKERRQ(ierr);
10117   for (p = 0; p < pEnd-pStart; ++p) fpoints[p] = -1;
10118   switch (cellRefiner) {
10119   case REFINER_SIMPLEX_1D:
10120   case REFINER_SIMPLEX_2D:
10121   case REFINER_HYBRID_SIMPLEX_2D:
10122   case REFINER_HEX_2D:
10123   case REFINER_HYBRID_HEX_2D:
10124   case REFINER_SIMPLEX_3D:
10125   case REFINER_HYBRID_SIMPLEX_3D:
10126   case REFINER_HEX_3D:
10127   case REFINER_HYBRID_HEX_3D:
10128     for (v = vStart; v < vEnd; ++v) fpoints[v-pStart] = vStartNew + (v - vStart);
10129     break;
10130   default:
10131     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", cellRefiner);
10132   }
10133   ierr = ISCreateGeneral(PETSC_COMM_SELF, pEnd-pStart, fpoints, PETSC_OWN_POINTER, fpointIS);CHKERRQ(ierr);
10134   ierr = PetscFree(depthSize);CHKERRQ(ierr);
10135   PetscFunctionReturn(0);
10136 }
10137 
10138 /*@
10139   DMPlexSetRefinementUniform - Set the flag for uniform refinement
10140 
10141   Input Parameters:
10142 + dm - The DM
10143 - refinementUniform - The flag for uniform refinement
10144 
10145   Level: developer
10146 
10147 .seealso: DMRefine(), DMPlexGetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
10148 @*/
10149 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
10150 {
10151   DM_Plex *mesh = (DM_Plex*) dm->data;
10152 
10153   PetscFunctionBegin;
10154   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10155   mesh->refinementUniform = refinementUniform;
10156   PetscFunctionReturn(0);
10157 }
10158 
10159 /*@
10160   DMPlexGetRefinementUniform - Retrieve the flag for uniform refinement
10161 
10162   Input Parameter:
10163 . dm - The DM
10164 
10165   Output Parameter:
10166 . refinementUniform - The flag for uniform refinement
10167 
10168   Level: developer
10169 
10170 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
10171 @*/
10172 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
10173 {
10174   DM_Plex *mesh = (DM_Plex*) dm->data;
10175 
10176   PetscFunctionBegin;
10177   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10178   PetscValidPointer(refinementUniform,  2);
10179   *refinementUniform = mesh->refinementUniform;
10180   PetscFunctionReturn(0);
10181 }
10182 
10183 /*@
10184   DMPlexSetRefinementLimit - Set the maximum cell volume for refinement
10185 
10186   Input Parameters:
10187 + dm - The DM
10188 - refinementLimit - The maximum cell volume in the refined mesh
10189 
10190   Level: developer
10191 
10192 .seealso: DMRefine(), DMPlexGetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
10193 @*/
10194 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
10195 {
10196   DM_Plex *mesh = (DM_Plex*) dm->data;
10197 
10198   PetscFunctionBegin;
10199   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10200   mesh->refinementLimit = refinementLimit;
10201   PetscFunctionReturn(0);
10202 }
10203 
10204 /*@
10205   DMPlexGetRefinementLimit - Retrieve the maximum cell volume for refinement
10206 
10207   Input Parameter:
10208 . dm - The DM
10209 
10210   Output Parameter:
10211 . refinementLimit - The maximum cell volume in the refined mesh
10212 
10213   Level: developer
10214 
10215 .seealso: DMRefine(), DMPlexSetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
10216 @*/
10217 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
10218 {
10219   DM_Plex *mesh = (DM_Plex*) dm->data;
10220 
10221   PetscFunctionBegin;
10222   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10223   PetscValidPointer(refinementLimit,  2);
10224   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
10225   *refinementLimit = mesh->refinementLimit;
10226   PetscFunctionReturn(0);
10227 }
10228 
10229 /*@
10230   DMPlexSetRefinementFunction - Set the function giving the maximum cell volume for refinement
10231 
10232   Input Parameters:
10233 + dm - The DM
10234 - refinementFunc - Function giving the maximum cell volume in the refined mesh
10235 
10236   Note: The calling sequence is refinementFunc(coords, limit)
10237 $ coords - Coordinates of the current point, usually a cell centroid
10238 $ limit  - The maximum cell volume for a cell containing this point
10239 
10240   Level: developer
10241 
10242 .seealso: DMRefine(), DMPlexGetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
10243 @*/
10244 PetscErrorCode DMPlexSetRefinementFunction(DM dm, PetscErrorCode (*refinementFunc)(const PetscReal [], PetscReal *))
10245 {
10246   DM_Plex *mesh = (DM_Plex*) dm->data;
10247 
10248   PetscFunctionBegin;
10249   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10250   mesh->refinementFunc = refinementFunc;
10251   PetscFunctionReturn(0);
10252 }
10253 
10254 /*@
10255   DMPlexGetRefinementFunction - Get the function giving the maximum cell volume for refinement
10256 
10257   Input Parameter:
10258 . dm - The DM
10259 
10260   Output Parameter:
10261 . refinementFunc - Function giving the maximum cell volume in the refined mesh
10262 
10263   Note: The calling sequence is refinementFunc(coords, limit)
10264 $ coords - Coordinates of the current point, usually a cell centroid
10265 $ limit  - The maximum cell volume for a cell containing this point
10266 
10267   Level: developer
10268 
10269 .seealso: DMRefine(), DMPlexSetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
10270 @*/
10271 PetscErrorCode DMPlexGetRefinementFunction(DM dm, PetscErrorCode (**refinementFunc)(const PetscReal [], PetscReal *))
10272 {
10273   DM_Plex *mesh = (DM_Plex*) dm->data;
10274 
10275   PetscFunctionBegin;
10276   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10277   PetscValidPointer(refinementFunc,  2);
10278   *refinementFunc = mesh->refinementFunc;
10279   PetscFunctionReturn(0);
10280 }
10281 
10282 PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
10283 {
10284   PetscInt       dim, cStart, cEnd, coneSize, cMax, fMax;
10285   PetscErrorCode ierr;
10286 
10287   PetscFunctionBegin;
10288   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
10289   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10290   if (cEnd <= cStart) {*cellRefiner = REFINER_NOOP; PetscFunctionReturn(0);}
10291   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
10292   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, NULL, NULL);CHKERRQ(ierr);
10293   switch (dim) {
10294   case 1:
10295     switch (coneSize) {
10296     case 2:
10297       *cellRefiner = REFINER_SIMPLEX_1D;
10298       break;
10299     default:
10300       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
10301     }
10302     break;
10303   case 2:
10304     switch (coneSize) {
10305     case 3:
10306       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_2D;
10307       else *cellRefiner = REFINER_SIMPLEX_2D;
10308       break;
10309     case 4:
10310       if (cMax >= 0 && fMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_2D;
10311       else *cellRefiner = REFINER_HEX_2D;
10312       break;
10313     default:
10314       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
10315     }
10316     break;
10317   case 3:
10318     switch (coneSize) {
10319     case 4:
10320       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_3D;
10321       else *cellRefiner = REFINER_SIMPLEX_3D;
10322       break;
10323     case 5:
10324       if (cMax == 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_3D;
10325       else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
10326       break;
10327     case 6:
10328       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_3D;
10329       else *cellRefiner = REFINER_HEX_3D;
10330       break;
10331     default:
10332       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
10333     }
10334     break;
10335   default:
10336     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
10337   }
10338   PetscFunctionReturn(0);
10339 }
10340 
10341 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
10342 {
10343   PetscBool      isUniform;
10344   PetscErrorCode ierr;
10345 
10346   PetscFunctionBegin;
10347   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
10348   if (isUniform) {
10349     CellRefiner cellRefiner;
10350     PetscBool   localized;
10351 
10352     ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
10353     ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr);
10354     ierr = DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
10355     ierr = DMCopyBoundary(dm, *dmRefined);CHKERRQ(ierr);
10356     if (localized) {ierr = DMLocalizeCoordinates(*dmRefined);CHKERRQ(ierr);}
10357   } else {
10358     ierr = DMPlexRefine_Internal(dm, NULL, dmRefined);CHKERRQ(ierr);
10359   }
10360   PetscFunctionReturn(0);
10361 }
10362 
10363 PetscErrorCode DMRefineHierarchy_Plex(DM dm, PetscInt nlevels, DM dmRefined[])
10364 {
10365   DM             cdm = dm;
10366   PetscInt       r;
10367   PetscBool      isUniform, localized;
10368   PetscErrorCode ierr;
10369 
10370   PetscFunctionBegin;
10371   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
10372   ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
10373   if (isUniform) {
10374     for (r = 0; r < nlevels; ++r) {
10375       CellRefiner cellRefiner;
10376 
10377       ierr = DMPlexGetCellRefiner_Internal(cdm, &cellRefiner);CHKERRQ(ierr);
10378       ierr = DMPlexRefineUniform_Internal(cdm, cellRefiner, &dmRefined[r]);CHKERRQ(ierr);
10379       ierr = DMCopyBoundary(cdm, dmRefined[r]);CHKERRQ(ierr);
10380       if (localized) {ierr = DMLocalizeCoordinates(dmRefined[r]);CHKERRQ(ierr);}
10381       ierr = DMSetCoarseDM(dmRefined[r], cdm);CHKERRQ(ierr);
10382       ierr = DMPlexSetRegularRefinement(dmRefined[r], PETSC_TRUE);CHKERRQ(ierr);
10383       cdm  = dmRefined[r];
10384     }
10385   } else {
10386     for (r = 0; r < nlevels; ++r) {
10387       ierr = DMRefine(cdm, PetscObjectComm((PetscObject) dm), &dmRefined[r]);CHKERRQ(ierr);
10388       ierr = DMCopyBoundary(cdm, dmRefined[r]);CHKERRQ(ierr);
10389       if (localized) {ierr = DMLocalizeCoordinates(dmRefined[r]);CHKERRQ(ierr);}
10390       ierr = DMSetCoarseDM(dmRefined[r], cdm);CHKERRQ(ierr);
10391       cdm  = dmRefined[r];
10392     }
10393   }
10394   PetscFunctionReturn(0);
10395 }
10396