xref: /petsc/src/dm/impls/plex/plexrefine.c (revision 55e7fe800d976e85ed2b5cd8bfdef564daa37bd9)
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 = PetscObjectStateGet((PetscObject) 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;
1616 #if defined(PETSC_USE_DEBUG)
1617   PetscInt        p;
1618 #endif
1619   PetscErrorCode  ierr;
1620 
1621   PetscFunctionBegin;
1622   if (!refiner) PetscFunctionReturn(0);
1623   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1624   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
1625   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
1626   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1627   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
1628   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
1629   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
1630   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
1631   switch (refiner) {
1632   case REFINER_SIMPLEX_1D:
1633     /* Max support size of refined mesh is 2 */
1634     ierr = PetscMalloc1(2, &supportRef);CHKERRQ(ierr);
1635     /* All cells have 2 vertices */
1636     for (c = cStart; c < cEnd; ++c) {
1637       const PetscInt  newv = vStartNew + (vEnd - vStart) + (c - cStart);
1638 
1639       for (r = 0; r < 2; ++r) {
1640         const PetscInt newp = cStartNew + (c - cStart)*2 + r;
1641         const PetscInt *cone;
1642         PetscInt        coneNew[2];
1643 
1644         ierr             = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1645         coneNew[0]       = vStartNew + (cone[0] - vStart);
1646         coneNew[1]       = vStartNew + (cone[1] - vStart);
1647         coneNew[(r+1)%2] = newv;
1648         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1649 #if defined(PETSC_USE_DEBUG)
1650         if ((newp < cStartNew) || (newp >= cEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a cell [%D, %D)", newp, cStartNew, cEndNew);
1651         for (p = 0; p < 2; ++p) {
1652           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);
1653         }
1654 #endif
1655       }
1656     }
1657     /* Old vertices have identical supports */
1658     for (v = vStart; v < vEnd; ++v) {
1659       const PetscInt  newp = vStartNew + (v - vStart);
1660       const PetscInt *support, *cone;
1661       PetscInt        size, s;
1662 
1663       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1664       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1665       for (s = 0; s < size; ++s) {
1666         PetscInt r = 0;
1667 
1668         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1669         if (cone[1] == v) r = 1;
1670         supportRef[s] = cStartNew + (support[s] - cStart)*2 + r;
1671       }
1672       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1673 #if defined(PETSC_USE_DEBUG)
1674       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
1675       for (p = 0; p < size; ++p) {
1676         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);
1677       }
1678 #endif
1679     }
1680     /* Cell vertices have support of 2 cells */
1681     for (c = cStart; c < cEnd; ++c) {
1682       const PetscInt  newp = vStartNew + (vEnd - vStart) + (c - cStart);
1683 
1684       supportRef[0] = cStartNew + (c - cStart)*2 + 0;
1685       supportRef[1] = cStartNew + (c - cStart)*2 + 1;
1686       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1687 #if defined(PETSC_USE_DEBUG)
1688       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
1689       for (p = 0; p < 2; ++p) {
1690         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);
1691       }
1692 #endif
1693     }
1694     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1695     break;
1696   case REFINER_SIMPLEX_2D:
1697     /*
1698      2
1699      |\
1700      | \
1701      |  \
1702      |   \
1703      | C  \
1704      |     \
1705      |      \
1706      2---1---1
1707      |\  D  / \
1708      | 2   0   \
1709      |A \ /  B  \
1710      0---0-------1
1711      */
1712     /* All cells have 3 faces */
1713     for (c = cStart; c < cEnd; ++c) {
1714       const PetscInt  newp = cStartNew + (c - cStart)*4;
1715       const PetscInt *cone, *ornt;
1716       PetscInt        coneNew[3], orntNew[3];
1717 
1718       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1719       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1720       /* A triangle */
1721       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1722       orntNew[0] = ornt[0];
1723       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1724       orntNew[1] = -2;
1725       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1726       orntNew[2] = ornt[2];
1727       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1728       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1729 #if defined(PETSC_USE_DEBUG)
1730       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);
1731       for (p = 0; p < 3; ++p) {
1732         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);
1733       }
1734 #endif
1735       /* B triangle */
1736       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1737       orntNew[0] = ornt[0];
1738       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1739       orntNew[1] = ornt[1];
1740       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1741       orntNew[2] = -2;
1742       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1743       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1744 #if defined(PETSC_USE_DEBUG)
1745       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);
1746       for (p = 0; p < 3; ++p) {
1747         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);
1748       }
1749 #endif
1750       /* C triangle */
1751       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1752       orntNew[0] = -2;
1753       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1754       orntNew[1] = ornt[1];
1755       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1756       orntNew[2] = ornt[2];
1757       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1758       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1759 #if defined(PETSC_USE_DEBUG)
1760       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);
1761       for (p = 0; p < 3; ++p) {
1762         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);
1763       }
1764 #endif
1765       /* D triangle */
1766       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1767       orntNew[0] = 0;
1768       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1769       orntNew[1] = 0;
1770       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1771       orntNew[2] = 0;
1772       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1773       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1774 #if defined(PETSC_USE_DEBUG)
1775       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);
1776       for (p = 0; p < 3; ++p) {
1777         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);
1778       }
1779 #endif
1780     }
1781     /* Split faces have 2 vertices and the same cells as the parent */
1782     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1783     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
1784     for (f = fStart; f < fEnd; ++f) {
1785       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1786 
1787       for (r = 0; r < 2; ++r) {
1788         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1789         const PetscInt *cone, *ornt, *support;
1790         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1791 
1792         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1793         coneNew[0]       = vStartNew + (cone[0] - vStart);
1794         coneNew[1]       = vStartNew + (cone[1] - vStart);
1795         coneNew[(r+1)%2] = newv;
1796         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1797 #if defined(PETSC_USE_DEBUG)
1798         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
1799         for (p = 0; p < 2; ++p) {
1800           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);
1801         }
1802 #endif
1803         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1804         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1805         for (s = 0; s < supportSize; ++s) {
1806           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1807           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1808           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1809           for (c = 0; c < coneSize; ++c) {
1810             if (cone[c] == f) break;
1811           }
1812           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1813         }
1814         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1815 #if defined(PETSC_USE_DEBUG)
1816         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
1817         for (p = 0; p < supportSize; ++p) {
1818           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);
1819         }
1820 #endif
1821       }
1822     }
1823     /* Interior faces have 2 vertices and 2 cells */
1824     for (c = cStart; c < cEnd; ++c) {
1825       const PetscInt *cone;
1826 
1827       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1828       for (r = 0; r < 3; ++r) {
1829         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
1830         PetscInt       coneNew[2];
1831         PetscInt       supportNew[2];
1832 
1833         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
1834         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
1835         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1836 #if defined(PETSC_USE_DEBUG)
1837         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
1838         for (p = 0; p < 2; ++p) {
1839           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);
1840         }
1841 #endif
1842         supportNew[0] = (c - cStart)*4 + (r+1)%3;
1843         supportNew[1] = (c - cStart)*4 + 3;
1844         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1845 #if defined(PETSC_USE_DEBUG)
1846         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
1847         for (p = 0; p < 2; ++p) {
1848           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);
1849         }
1850 #endif
1851       }
1852     }
1853     /* Old vertices have identical supports */
1854     for (v = vStart; v < vEnd; ++v) {
1855       const PetscInt  newp = vStartNew + (v - vStart);
1856       const PetscInt *support, *cone;
1857       PetscInt        size, s;
1858 
1859       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1860       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1861       for (s = 0; s < size; ++s) {
1862         PetscInt r = 0;
1863 
1864         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1865         if (cone[1] == v) r = 1;
1866         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1867       }
1868       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1869 #if defined(PETSC_USE_DEBUG)
1870       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
1871       for (p = 0; p < size; ++p) {
1872         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);
1873       }
1874 #endif
1875     }
1876     /* Face vertices have 2 + cells*2 supports */
1877     for (f = fStart; f < fEnd; ++f) {
1878       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1879       const PetscInt *cone, *support;
1880       PetscInt        size, s;
1881 
1882       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1883       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1884       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1885       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1886       for (s = 0; s < size; ++s) {
1887         PetscInt r = 0;
1888 
1889         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1890         if      (cone[1] == f) r = 1;
1891         else if (cone[2] == f) r = 2;
1892         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
1893         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
1894       }
1895       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1896 #if defined(PETSC_USE_DEBUG)
1897       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
1898       for (p = 0; p < 2+size*2; ++p) {
1899         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);
1900       }
1901 #endif
1902     }
1903     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1904     break;
1905   case REFINER_SIMPLEX_TO_HEX_2D:
1906     /*
1907      2
1908      |\
1909      | \
1910      |  \
1911      |   \
1912      | C  \
1913      |     \
1914      2      1
1915      |\    / \
1916      | 2  1   \
1917      |  \/     \
1918      |   |      \
1919      |A  |   B   \
1920      |   0        \
1921      |   |         \
1922      0---0----------1
1923      */
1924     /* All cells have 4 faces */
1925     for (c = cStart; c < cEnd; ++c) {
1926       const PetscInt  newp = cStartNew + (c - cStart)*3;
1927       const PetscInt *cone, *ornt;
1928       PetscInt        coneNew[4], orntNew[4];
1929 
1930       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1931       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1932       /* A quad */
1933       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1934       orntNew[0] = ornt[0];
1935       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1936       orntNew[1] = 0;
1937       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1938       orntNew[2] = -2;
1939       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1940       orntNew[3] = ornt[2];
1941       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1942       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1943 #if defined(PETSC_USE_DEBUG)
1944       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);
1945       for (p = 0; p < 4; ++p) {
1946         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);
1947       }
1948 #endif
1949       /* B quad */
1950       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1951       orntNew[0] = ornt[0];
1952       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1953       orntNew[1] = ornt[1];
1954       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1955       orntNew[2] = 0;
1956       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1957       orntNew[3] = -2;
1958       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1959       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1960 #if defined(PETSC_USE_DEBUG)
1961       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);
1962       for (p = 0; p < 4; ++p) {
1963         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);
1964       }
1965 #endif
1966       /* C quad */
1967       coneNew[0] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1968       orntNew[0] = ornt[1];
1969       coneNew[1] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1970       orntNew[1] = ornt[2];
1971       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1972       orntNew[2] = 0;
1973       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1974       orntNew[3] = -2;
1975       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1976       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1977 #if defined(PETSC_USE_DEBUG)
1978       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);
1979       for (p = 0; p < 4; ++p) {
1980         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);
1981       }
1982 #endif
1983     }
1984     /* Split faces have 2 vertices and the same cells as the parent */
1985     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1986     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
1987     for (f = fStart; f < fEnd; ++f) {
1988       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1989 
1990       for (r = 0; r < 2; ++r) {
1991         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1992         const PetscInt *cone, *ornt, *support;
1993         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1994 
1995         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1996         coneNew[0]       = vStartNew + (cone[0] - vStart);
1997         coneNew[1]       = vStartNew + (cone[1] - vStart);
1998         coneNew[(r+1)%2] = newv;
1999         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2000 #if defined(PETSC_USE_DEBUG)
2001         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2002         for (p = 0; p < 2; ++p) {
2003           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);
2004         }
2005 #endif
2006         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2007         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2008         for (s = 0; s < supportSize; ++s) {
2009           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2010           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2011           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2012           for (c = 0; c < coneSize; ++c) {
2013             if (cone[c] == f) break;
2014           }
2015           supportRef[s] = cStartNew + (support[s] - cStart)*3 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
2016         }
2017         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2018 #if defined(PETSC_USE_DEBUG)
2019         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2020         for (p = 0; p < supportSize; ++p) {
2021           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);
2022         }
2023 #endif
2024       }
2025     }
2026     /* Interior faces have 2 vertices and 2 cells */
2027     for (c = cStart; c < cEnd; ++c) {
2028       const PetscInt *cone;
2029 
2030       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2031       for (r = 0; r < 3; ++r) {
2032         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
2033         PetscInt       coneNew[2];
2034         PetscInt       supportNew[2];
2035 
2036         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2037         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
2038         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2039 #if defined(PETSC_USE_DEBUG)
2040         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2041         for (p = 0; p < 2; ++p) {
2042           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);
2043         }
2044 #endif
2045         supportNew[0] = (c - cStart)*3 + r%3;
2046         supportNew[1] = (c - cStart)*3 + (r+1)%3;
2047         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2048 #if defined(PETSC_USE_DEBUG)
2049         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2050         for (p = 0; p < 2; ++p) {
2051           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);
2052         }
2053 #endif
2054       }
2055     }
2056     /* Old vertices have identical supports */
2057     for (v = vStart; v < vEnd; ++v) {
2058       const PetscInt  newp = vStartNew + (v - vStart);
2059       const PetscInt *support, *cone;
2060       PetscInt        size, s;
2061 
2062       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2063       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2064       for (s = 0; s < size; ++s) {
2065         PetscInt r = 0;
2066 
2067         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2068         if (cone[1] == v) r = 1;
2069         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2070       }
2071       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2072 #if defined(PETSC_USE_DEBUG)
2073       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2074       for (p = 0; p < size; ++p) {
2075         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);
2076       }
2077 #endif
2078     }
2079     /* Split-face vertices have cells + 2 supports */
2080     for (f = fStart; f < fEnd; ++f) {
2081       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2082       const PetscInt *cone, *support;
2083       PetscInt        size, s;
2084 
2085       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2086       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2087       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2088       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2089       for (s = 0; s < size; ++s) {
2090         PetscInt r = 0;
2091 
2092         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2093         if      (cone[1] == f) r = 1;
2094         else if (cone[2] == f) r = 2;
2095         supportRef[2+s+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
2096       }
2097       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2098 #if defined(PETSC_USE_DEBUG)
2099       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2100       for (p = 0; p < 2+size; ++p) {
2101         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);
2102       }
2103 #endif
2104     }
2105     /* Interior vertices have 3 supports */
2106     for (c = cStart; c < cEnd; ++c) {
2107       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
2108 
2109       supportRef[0] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 0;
2110       supportRef[1] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 1;
2111       supportRef[2] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 2;
2112       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2113     }
2114     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2115     break;
2116   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
2117     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
2118     cMax = PetscMin(cEnd, cMax);
2119     for (c = cStart; c < cMax; ++c) {
2120       const PetscInt  newp = cStartNew + (c - cStart)*3;
2121       const PetscInt *cone, *ornt;
2122       PetscInt        coneNew[4], orntNew[4];
2123 
2124       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2125       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2126       /* A quad */
2127       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2128       orntNew[0] = ornt[0];
2129       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
2130       orntNew[1] = 0;
2131       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
2132       orntNew[2] = -2;
2133       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2134       orntNew[3] = ornt[2];
2135       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2136       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2137 #if defined(PETSC_USE_DEBUG)
2138       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);
2139       for (p = 0; p < 4; ++p) {
2140         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);
2141       }
2142 #endif
2143       /* B quad */
2144       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2145       orntNew[0] = ornt[0];
2146       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2147       orntNew[1] = ornt[1];
2148       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
2149       orntNew[2] = 0;
2150       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
2151       orntNew[3] = -2;
2152       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2153       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2154 #if defined(PETSC_USE_DEBUG)
2155       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);
2156       for (p = 0; p < 4; ++p) {
2157         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);
2158       }
2159 #endif
2160       /* C quad */
2161       coneNew[0] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2162       orntNew[0] = ornt[1];
2163       coneNew[1] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2164       orntNew[1] = ornt[2];
2165       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
2166       orntNew[2] = 0;
2167       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
2168       orntNew[3] = -2;
2169       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2170       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2171 #if defined(PETSC_USE_DEBUG)
2172       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);
2173       for (p = 0; p < 4; ++p) {
2174         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);
2175       }
2176 #endif
2177     }
2178     /*
2179      2---------1---------3
2180      |         |         |
2181      |    D    1    C    |
2182      |         |         |
2183      2----2----0----3----3
2184      |         |         |
2185      |    A    0    B    |
2186      |         |         |
2187      0---------0---------1
2188      */
2189     /* Parent cells are input as prisms but children are quads, since the mesh is no longer hybrid */
2190     for (c = cMax; c < cEnd; ++c) {
2191       const PetscInt  newp  = cStartNew + (cMax - cStart)*3 + (c - cMax)*4;
2192       const PetscInt  newpt = (cMax - cStart)*3 + (c - cMax)*4;
2193       const PetscInt *cone, *ornt;
2194       PetscInt        coneNew[4], orntNew[4];
2195 
2196       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2197       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2198       /* A quad */
2199       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2200       orntNew[0] = ornt[0];
2201       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + newpt + 0;
2202       orntNew[1] = 0;
2203       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + newpt + 2;
2204       orntNew[2] = -2;
2205       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2206       orntNew[3] = ornt[2] < 0 ? 0 : -2;
2207       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2208       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2209 #if defined(PETSC_USE_DEBUG)
2210       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);
2211       for (p = 0; p < 4; ++p) {
2212         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);
2213       }
2214 #endif
2215       /* B quad */
2216       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2217       orntNew[0] = ornt[0];
2218       coneNew[1] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
2219       orntNew[1] = ornt[3];
2220       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + newpt + 3;
2221       orntNew[2] = 0;
2222       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + newpt + 0;
2223       orntNew[3] = -2;
2224       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2225       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2226 #if defined(PETSC_USE_DEBUG)
2227       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);
2228       for (p = 0; p < 4; ++p) {
2229         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);
2230       }
2231 #endif
2232       /* C quad */
2233       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + newpt + 3;
2234       orntNew[0] = -2;
2235       coneNew[1] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
2236       orntNew[1] = ornt[3];
2237       coneNew[2] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2238       orntNew[2] = ornt[1] < 0 ? 0 : -2;
2239       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + newpt + 1;
2240       orntNew[3] = 0;
2241       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2242       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2243 #if defined(PETSC_USE_DEBUG)
2244       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);
2245       for (p = 0; p < 4; ++p) {
2246         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);
2247       }
2248 #endif
2249       /* D quad */
2250       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + newpt + 2;
2251       orntNew[0] = 0;
2252       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + newpt + 1;
2253       orntNew[1] = -2;
2254       coneNew[2] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2255       orntNew[2] = ornt[1] < 0 ? 0 : -2;
2256       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2257       orntNew[3] = ornt[2] < 0 ? 0 : -2;
2258       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2259       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2260 #if defined(PETSC_USE_DEBUG)
2261       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);
2262       for (p = 0; p < 4; ++p) {
2263         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);
2264       }
2265 #endif
2266     }
2267     /* Split faces have 2 vertices and the same cells as the parent */
2268     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2269     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2270     for (f = fStart; f < fEnd; ++f) {
2271       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
2272 
2273       for (r = 0; r < 2; ++r) {
2274         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2275         const PetscInt *cone, *ornt, *support;
2276         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2277 
2278         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2279         coneNew[0]       = vStartNew + (cone[0] - vStart);
2280         coneNew[1]       = vStartNew + (cone[1] - vStart);
2281         coneNew[(r+1)%2] = newv;
2282         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2283 #if defined(PETSC_USE_DEBUG)
2284         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2285         for (p = 0; p < 2; ++p) {
2286           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);
2287         }
2288 #endif
2289         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2290         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2291         for (s = 0; s < supportSize; ++s) {
2292           const PetscInt p2q[4][2] = { {0, 1},
2293                                        {3, 2},
2294                                        {0, 3},
2295                                        {1, 2} };
2296 
2297           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2298           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2299           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2300           for (c = 0; c < coneSize; ++c) {
2301             if (cone[c] == f) break;
2302           }
2303           if (coneSize == 3)      supportRef[s] = cStartNew + (support[s] - cStart)*3 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
2304           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]);
2305           else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected cone size %D", coneSize);
2306         }
2307         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2308 #if defined(PETSC_USE_DEBUG)
2309         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2310         for (p = 0; p < supportSize; ++p) {
2311           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);
2312         }
2313 #endif
2314       }
2315     }
2316     /* Interior faces have 2 vertices and 2 cells */
2317     for (c = cStart; c < cMax; ++c) {
2318       const PetscInt *cone;
2319 
2320       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2321       for (r = 0; r < 3; ++r) {
2322         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
2323         PetscInt       coneNew[2];
2324         PetscInt       supportNew[2];
2325 
2326         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2327         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
2328         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2329 #if defined(PETSC_USE_DEBUG)
2330         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2331         for (p = 0; p < 2; ++p) {
2332           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);
2333         }
2334 #endif
2335         supportNew[0] = (c - cStart)*3 + r%3;
2336         supportNew[1] = (c - cStart)*3 + (r+1)%3;
2337         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2338 #if defined(PETSC_USE_DEBUG)
2339         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2340         for (p = 0; p < 2; ++p) {
2341           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);
2342         }
2343 #endif
2344       }
2345     }
2346     /* Hybrid interior faces have 2 vertices and 2 cells */
2347     for (c = cMax; c < cEnd; ++c) {
2348       const PetscInt *cone;
2349       PetscInt        coneNew[2], supportNew[2];
2350 
2351       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2352       for (r = 0; r < 4; ++r) {
2353         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + r;
2354 
2355         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2356         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (cMax - cStart) + (c - cMax);
2357 	ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2358 #if defined(PETSC_USE_DEBUG)
2359         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2360         for (p = 0; p < 2; ++p) {
2361           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);
2362         }
2363 #endif
2364         if (r==0) {
2365           supportNew[0] = (cMax - cStart)*3 + (c - cMax)*4 + 0;
2366           supportNew[1] = (cMax - cStart)*3 + (c - cMax)*4 + 1;
2367         } else if (r==1) {
2368           supportNew[0] = (cMax - cStart)*3 + (c - cMax)*4 + 2;
2369           supportNew[1] = (cMax - cStart)*3 + (c - cMax)*4 + 3;
2370         } else if (r==2) {
2371           supportNew[0] = (cMax - cStart)*3 + (c - cMax)*4 + 0;
2372           supportNew[1] = (cMax - cStart)*3 + (c - cMax)*4 + 3;
2373         } else {
2374           supportNew[0] = (cMax - cStart)*3 + (c - cMax)*4 + 1;
2375           supportNew[1] = (cMax - cStart)*3 + (c - cMax)*4 + 2;
2376         }
2377         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2378 #if defined(PETSC_USE_DEBUG)
2379         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2380         for (p = 0; p < 2; ++p) {
2381           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);
2382         }
2383 #endif
2384       }
2385     }
2386     /* Old vertices have identical supports */
2387     for (v = vStart; v < vEnd; ++v) {
2388       const PetscInt  newp = vStartNew + (v - vStart);
2389       const PetscInt *support, *cone;
2390       PetscInt        size, s;
2391 
2392       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2393       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2394       for (s = 0; s < size; ++s) {
2395         PetscInt r = 0;
2396 
2397         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2398         if (cone[1] == v) r = 1;
2399         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2400       }
2401       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2402 #if defined(PETSC_USE_DEBUG)
2403       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2404       for (p = 0; p < size; ++p) {
2405         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);
2406       }
2407 #endif
2408     }
2409     /* Split-face vertices have cells + 2 supports */
2410     for (f = fStart; f < fEnd; ++f) {
2411       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2412       const PetscInt *cone, *support;
2413       PetscInt        size, s;
2414 
2415       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2416       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2417       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2418       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2419       for (s = 0; s < size; ++s) {
2420         PetscInt r = 0, coneSize;
2421 
2422         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2423         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2424         if (coneSize == 3) {
2425           if      (cone[1] == f) r = 1;
2426           else if (cone[2] == f) r = 2;
2427           supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
2428         } else if (coneSize == 4) {
2429           if      (cone[1] == f) r = 1;
2430           else if (cone[2] == f) r = 2;
2431           else if (cone[3] == f) r = 3;
2432           supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (support[s] - cMax)*4 + r;
2433         } else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected cone size %D", coneSize);
2434       }
2435       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2436 #if defined(PETSC_USE_DEBUG)
2437       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2438       for (p = 0; p < 2+size; ++p) {
2439         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);
2440       }
2441 #endif
2442     }
2443     /* Interior vertices have 3 supports */
2444     for (c = cStart; c < cMax; ++c) {
2445       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
2446 
2447       supportRef[0] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 0;
2448       supportRef[1] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 1;
2449       supportRef[2] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 2;
2450       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2451     }
2452     /* Hybrid interior vertices have 4 supports */
2453     for (c = cMax; c < cEnd; ++c) {
2454       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
2455 
2456       supportRef[0] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + 0;
2457       supportRef[1] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + 1;
2458       supportRef[2] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + 2;
2459       supportRef[3] = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (c - cMax)*4 + 3;
2460       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2461     }
2462     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2463     break;
2464   case REFINER_HEX_2D:
2465     /*
2466      3---------2---------2
2467      |         |         |
2468      |    D    2    C    |
2469      |         |         |
2470      3----3----0----1----1
2471      |         |         |
2472      |    A    0    B    |
2473      |         |         |
2474      0---------0---------1
2475      */
2476     /* All cells have 4 faces */
2477     for (c = cStart; c < cEnd; ++c) {
2478       const PetscInt  newp = (c - cStart)*4;
2479       const PetscInt *cone, *ornt;
2480       PetscInt        coneNew[4], orntNew[4];
2481 
2482       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2483       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2484       /* A quad */
2485       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2486       orntNew[0] = ornt[0];
2487       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
2488       orntNew[1] = 0;
2489       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
2490       orntNew[2] = -2;
2491       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
2492       orntNew[3] = ornt[3];
2493       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2494       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2495 #if defined(PETSC_USE_DEBUG)
2496       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);
2497       for (p = 0; p < 4; ++p) {
2498         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);
2499       }
2500 #endif
2501       /* B quad */
2502       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2503       orntNew[0] = ornt[0];
2504       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2505       orntNew[1] = ornt[1];
2506       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
2507       orntNew[2] = -2;
2508       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
2509       orntNew[3] = -2;
2510       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2511       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2512 #if defined(PETSC_USE_DEBUG)
2513       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);
2514       for (p = 0; p < 4; ++p) {
2515         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);
2516       }
2517 #endif
2518       /* C quad */
2519       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
2520       orntNew[0] = 0;
2521       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2522       orntNew[1] = ornt[1];
2523       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2524       orntNew[2] = ornt[2];
2525       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
2526       orntNew[3] = -2;
2527       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2528       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2529 #if defined(PETSC_USE_DEBUG)
2530       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);
2531       for (p = 0; p < 4; ++p) {
2532         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);
2533       }
2534 #endif
2535       /* D quad */
2536       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
2537       orntNew[0] = 0;
2538       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
2539       orntNew[1] = 0;
2540       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2541       orntNew[2] = ornt[2];
2542       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
2543       orntNew[3] = ornt[3];
2544       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2545       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2546 #if defined(PETSC_USE_DEBUG)
2547       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);
2548       for (p = 0; p < 4; ++p) {
2549         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);
2550       }
2551 #endif
2552     }
2553     /* Split faces have 2 vertices and the same cells as the parent */
2554     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2555     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2556     for (f = fStart; f < fEnd; ++f) {
2557       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
2558 
2559       for (r = 0; r < 2; ++r) {
2560         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2561         const PetscInt *cone, *ornt, *support;
2562         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2563 
2564         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2565         coneNew[0]       = vStartNew + (cone[0] - vStart);
2566         coneNew[1]       = vStartNew + (cone[1] - vStart);
2567         coneNew[(r+1)%2] = newv;
2568         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2569 #if defined(PETSC_USE_DEBUG)
2570         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2571         for (p = 0; p < 2; ++p) {
2572           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);
2573         }
2574 #endif
2575         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2576         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2577         for (s = 0; s < supportSize; ++s) {
2578           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2579           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2580           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2581           for (c = 0; c < coneSize; ++c) {
2582             if (cone[c] == f) break;
2583           }
2584           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
2585         }
2586         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2587 #if defined(PETSC_USE_DEBUG)
2588         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2589         for (p = 0; p < supportSize; ++p) {
2590           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);
2591         }
2592 #endif
2593       }
2594     }
2595     /* Interior faces have 2 vertices and 2 cells */
2596     for (c = cStart; c < cEnd; ++c) {
2597       const PetscInt *cone;
2598       PetscInt        coneNew[2], supportNew[2];
2599 
2600       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2601       for (r = 0; r < 4; ++r) {
2602         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
2603 
2604 	if (r==1 || r==2) {
2605           coneNew[0] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
2606           coneNew[1] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2607 	} else {
2608           coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2609           coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
2610 	}
2611 	ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2612 #if defined(PETSC_USE_DEBUG)
2613         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2614         for (p = 0; p < 2; ++p) {
2615           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);
2616         }
2617 #endif
2618         supportNew[0] = (c - cStart)*4 + r;
2619         supportNew[1] = (c - cStart)*4 + (r+1)%4;
2620         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2621 #if defined(PETSC_USE_DEBUG)
2622         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2623         for (p = 0; p < 2; ++p) {
2624           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);
2625         }
2626 #endif
2627       }
2628     }
2629     /* Old vertices have identical supports */
2630     for (v = vStart; v < vEnd; ++v) {
2631       const PetscInt  newp = vStartNew + (v - vStart);
2632       const PetscInt *support, *cone;
2633       PetscInt        size, s;
2634 
2635       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2636       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2637       for (s = 0; s < size; ++s) {
2638         PetscInt r = 0;
2639 
2640         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2641         if (cone[1] == v) r = 1;
2642         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2643       }
2644       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2645 #if defined(PETSC_USE_DEBUG)
2646       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2647       for (p = 0; p < size; ++p) {
2648         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);
2649       }
2650 #endif
2651     }
2652     /* Face vertices have 2 + cells supports */
2653     for (f = fStart; f < fEnd; ++f) {
2654       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2655       const PetscInt *cone, *support;
2656       PetscInt        size, s;
2657 
2658       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2659       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2660       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2661       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2662       for (s = 0; s < size; ++s) {
2663         PetscInt r = 0;
2664 
2665         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2666         if      (cone[1] == f) r = 1;
2667         else if (cone[2] == f) r = 2;
2668         else if (cone[3] == f) r = 3;
2669         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
2670       }
2671       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2672 #if defined(PETSC_USE_DEBUG)
2673       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2674       for (p = 0; p < 2+size; ++p) {
2675         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);
2676       }
2677 #endif
2678     }
2679     /* Cell vertices have 4 supports */
2680     for (c = cStart; c < cEnd; ++c) {
2681       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
2682       PetscInt       supportNew[4];
2683 
2684       for (r = 0; r < 4; ++r) {
2685         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
2686       }
2687       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2688     }
2689     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2690     break;
2691   case REFINER_HYBRID_SIMPLEX_2D:
2692     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
2693     cMax = PetscMin(cEnd, cMax);
2694     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
2695     fMax = PetscMin(fEnd, fMax);
2696     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);CHKERRQ(ierr);
2697     /* Interior cells have 3 faces */
2698     for (c = cStart; c < cMax; ++c) {
2699       const PetscInt  newp = cStartNew + (c - cStart)*4;
2700       const PetscInt *cone, *ornt;
2701       PetscInt        coneNew[3], orntNew[3];
2702 
2703       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2704       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2705       /* A triangle */
2706       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2707       orntNew[0] = ornt[0];
2708       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
2709       orntNew[1] = -2;
2710       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2711       orntNew[2] = ornt[2];
2712       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2713       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2714 #if defined(PETSC_USE_DEBUG)
2715       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);
2716       for (p = 0; p < 3; ++p) {
2717         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);
2718       }
2719 #endif
2720       /* B triangle */
2721       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2722       orntNew[0] = ornt[0];
2723       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2724       orntNew[1] = ornt[1];
2725       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
2726       orntNew[2] = -2;
2727       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2728       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2729 #if defined(PETSC_USE_DEBUG)
2730       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);
2731       for (p = 0; p < 3; ++p) {
2732         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);
2733       }
2734 #endif
2735       /* C triangle */
2736       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
2737       orntNew[0] = -2;
2738       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2739       orntNew[1] = ornt[1];
2740       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2741       orntNew[2] = ornt[2];
2742       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2743       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2744 #if defined(PETSC_USE_DEBUG)
2745       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);
2746       for (p = 0; p < 3; ++p) {
2747         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);
2748       }
2749 #endif
2750       /* D triangle */
2751       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
2752       orntNew[0] = 0;
2753       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
2754       orntNew[1] = 0;
2755       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
2756       orntNew[2] = 0;
2757       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2758       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2759 #if defined(PETSC_USE_DEBUG)
2760       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);
2761       for (p = 0; p < 3; ++p) {
2762         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);
2763       }
2764 #endif
2765     }
2766     /*
2767      2----3----3
2768      |         |
2769      |    B    |
2770      |         |
2771      0----4--- 1
2772      |         |
2773      |    A    |
2774      |         |
2775      0----2----1
2776      */
2777     /* Hybrid cells have 4 faces */
2778     for (c = cMax; c < cEnd; ++c) {
2779       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
2780       const PetscInt *cone, *ornt;
2781       PetscInt        coneNew[4], orntNew[4], r;
2782 
2783       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2784       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2785       r    = (ornt[0] < 0 ? 1 : 0);
2786       /* A quad */
2787       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + r;
2788       orntNew[0]   = ornt[0];
2789       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + r;
2790       orntNew[1]   = ornt[1];
2791       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2+r] - fMax);
2792       orntNew[2+r] = 0;
2793       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
2794       orntNew[3-r] = 0;
2795       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2796       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2797 #if defined(PETSC_USE_DEBUG)
2798       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);
2799       for (p = 0; p < 4; ++p) {
2800         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);
2801       }
2802 #endif
2803       /* B quad */
2804       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + 1-r;
2805       orntNew[0]   = ornt[0];
2806       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + 1-r;
2807       orntNew[1]   = ornt[1];
2808       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
2809       orntNew[2+r] = 0;
2810       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3-r] - fMax);
2811       orntNew[3-r] = 0;
2812       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2813       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2814 #if defined(PETSC_USE_DEBUG)
2815       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);
2816       for (p = 0; p < 4; ++p) {
2817         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);
2818       }
2819 #endif
2820     }
2821     /* Interior split faces have 2 vertices and the same cells as the parent */
2822     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2823     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2824     for (f = fStart; f < fMax; ++f) {
2825       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
2826 
2827       for (r = 0; r < 2; ++r) {
2828         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2829         const PetscInt *cone, *ornt, *support;
2830         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2831 
2832         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2833         coneNew[0]       = vStartNew + (cone[0] - vStart);
2834         coneNew[1]       = vStartNew + (cone[1] - vStart);
2835         coneNew[(r+1)%2] = newv;
2836         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2837 #if defined(PETSC_USE_DEBUG)
2838         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2839         for (p = 0; p < 2; ++p) {
2840           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);
2841         }
2842 #endif
2843         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2844         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2845         for (s = 0; s < supportSize; ++s) {
2846           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2847           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2848           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2849           for (c = 0; c < coneSize; ++c) if (cone[c] == f) break;
2850           if (support[s] >= cMax) {
2851             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[c] < 0 ? 1-r : r);
2852           } else {
2853             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
2854           }
2855         }
2856         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2857 #if defined(PETSC_USE_DEBUG)
2858         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2859         for (p = 0; p < supportSize; ++p) {
2860           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);
2861         }
2862 #endif
2863       }
2864     }
2865     /* Interior cell faces have 2 vertices and 2 cells */
2866     for (c = cStart; c < cMax; ++c) {
2867       const PetscInt *cone;
2868 
2869       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2870       for (r = 0; r < 3; ++r) {
2871         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
2872         PetscInt       coneNew[2];
2873         PetscInt       supportNew[2];
2874 
2875         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
2876         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
2877         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2878 #if defined(PETSC_USE_DEBUG)
2879         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2880         for (p = 0; p < 2; ++p) {
2881           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);
2882         }
2883 #endif
2884         supportNew[0] = (c - cStart)*4 + (r+1)%3;
2885         supportNew[1] = (c - cStart)*4 + 3;
2886         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2887 #if defined(PETSC_USE_DEBUG)
2888         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2889         for (p = 0; p < 2; ++p) {
2890           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);
2891         }
2892 #endif
2893       }
2894     }
2895     /* Interior hybrid faces have 2 vertices and the same cells */
2896     for (f = fMax; f < fEnd; ++f) {
2897       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
2898       const PetscInt *cone, *ornt;
2899       const PetscInt *support;
2900       PetscInt        coneNew[2];
2901       PetscInt        supportNew[2];
2902       PetscInt        size, s, r;
2903 
2904       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2905       coneNew[0] = vStartNew + (cone[0] - vStart);
2906       coneNew[1] = vStartNew + (cone[1] - vStart);
2907       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2908 #if defined(PETSC_USE_DEBUG)
2909       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2910       for (p = 0; p < 2; ++p) {
2911         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);
2912       }
2913 #endif
2914       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2915       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2916       for (s = 0; s < size; ++s) {
2917         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2918         ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2919         for (r = 0; r < 2; ++r) {
2920           if (cone[r+2] == f) break;
2921         }
2922         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[0] < 0 ? 1-r : r);
2923       }
2924       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2925 #if defined(PETSC_USE_DEBUG)
2926       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2927       for (p = 0; p < size; ++p) {
2928         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);
2929       }
2930 #endif
2931     }
2932     /* Cell hybrid faces have 2 vertices and 2 cells */
2933     for (c = cMax; c < cEnd; ++c) {
2934       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
2935       const PetscInt *cone;
2936       PetscInt        coneNew[2];
2937       PetscInt        supportNew[2];
2938 
2939       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2940       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
2941       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
2942       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2943 #if defined(PETSC_USE_DEBUG)
2944       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2945       for (p = 0; p < 2; ++p) {
2946         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);
2947       }
2948 #endif
2949       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
2950       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
2951       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2952 #if defined(PETSC_USE_DEBUG)
2953       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
2954       for (p = 0; p < 2; ++p) {
2955         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);
2956       }
2957 #endif
2958     }
2959     /* Old vertices have identical supports */
2960     for (v = vStart; v < vEnd; ++v) {
2961       const PetscInt  newp = vStartNew + (v - vStart);
2962       const PetscInt *support, *cone;
2963       PetscInt        size, s;
2964 
2965       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2966       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2967       for (s = 0; s < size; ++s) {
2968         if (support[s] >= fMax) {
2969           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
2970         } else {
2971           PetscInt r = 0;
2972 
2973           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2974           if (cone[1] == v) r = 1;
2975           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2976         }
2977       }
2978       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2979 #if defined(PETSC_USE_DEBUG)
2980       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
2981       for (p = 0; p < size; ++p) {
2982         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);
2983       }
2984 #endif
2985     }
2986     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
2987     for (f = fStart; f < fMax; ++f) {
2988       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2989       const PetscInt *cone, *support;
2990       PetscInt        size, newSize = 2, s;
2991 
2992       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2993       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2994       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2995       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2996       for (s = 0; s < size; ++s) {
2997         PetscInt r = 0;
2998 
2999         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3000         if (support[s] >= cMax) {
3001           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
3002 
3003           newSize += 1;
3004         } else {
3005           if      (cone[1] == f) r = 1;
3006           else if (cone[2] == f) r = 2;
3007           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
3008           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
3009 
3010           newSize += 2;
3011         }
3012       }
3013       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3014 #if defined(PETSC_USE_DEBUG)
3015       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
3016       for (p = 0; p < newSize; ++p) {
3017         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);
3018       }
3019 #endif
3020     }
3021     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3022     break;
3023   case REFINER_HYBRID_HEX_2D:
3024     /* Hybrid Hex 2D */
3025     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
3026     cMax = PetscMin(cEnd, cMax);
3027     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
3028     fMax = PetscMin(fEnd, fMax);
3029     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);CHKERRQ(ierr);
3030     /* Interior cells have 4 faces */
3031     for (c = cStart; c < cMax; ++c) {
3032       const PetscInt  newp = cStartNew + (c - cStart)*4;
3033       const PetscInt *cone, *ornt;
3034       PetscInt        coneNew[4], orntNew[4];
3035 
3036       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3037       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3038       /* A quad */
3039       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
3040       orntNew[0] = ornt[0];
3041       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
3042       orntNew[1] = 0;
3043       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
3044       orntNew[2] = -2;
3045       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
3046       orntNew[3] = ornt[3];
3047       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3048       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3049 #if defined(PETSC_USE_DEBUG)
3050       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);
3051       for (p = 0; p < 4; ++p) {
3052         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);
3053       }
3054 #endif
3055       /* B quad */
3056       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
3057       orntNew[0] = ornt[0];
3058       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
3059       orntNew[1] = ornt[1];
3060       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
3061       orntNew[2] = 0;
3062       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
3063       orntNew[3] = -2;
3064       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3065       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3066 #if defined(PETSC_USE_DEBUG)
3067       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);
3068       for (p = 0; p < 4; ++p) {
3069         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);
3070       }
3071 #endif
3072       /* C quad */
3073       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
3074       orntNew[0] = -2;
3075       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
3076       orntNew[1] = ornt[1];
3077       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
3078       orntNew[2] = ornt[2];
3079       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
3080       orntNew[3] = 0;
3081       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3082       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3083 #if defined(PETSC_USE_DEBUG)
3084       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);
3085       for (p = 0; p < 4; ++p) {
3086         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);
3087       }
3088 #endif
3089       /* D quad */
3090       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
3091       orntNew[0] = 0;
3092       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
3093       orntNew[1] = -2;
3094       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
3095       orntNew[2] = ornt[2];
3096       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
3097       orntNew[3] = ornt[3];
3098       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3099       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3100 #if defined(PETSC_USE_DEBUG)
3101       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);
3102       for (p = 0; p < 4; ++p) {
3103         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);
3104       }
3105 #endif
3106     }
3107     /*
3108      2----3----3
3109      |         |
3110      |    B    |
3111      |         |
3112      0----4--- 1
3113      |         |
3114      |    A    |
3115      |         |
3116      0----2----1
3117      */
3118     /* Hybrid cells have 4 faces */
3119     for (c = cMax; c < cEnd; ++c) {
3120       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
3121       const PetscInt *cone, *ornt;
3122       PetscInt        coneNew[4], orntNew[4];
3123 
3124       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3125       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3126       /* A quad */
3127       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
3128       orntNew[0] = ornt[0];
3129       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
3130       orntNew[1] = ornt[1];
3131       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[2] - fMax);
3132       orntNew[2] = 0;
3133       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
3134       orntNew[3] = 0;
3135       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3136       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3137 #if defined(PETSC_USE_DEBUG)
3138       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);
3139       for (p = 0; p < 4; ++p) {
3140         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);
3141       }
3142 #endif
3143       /* B quad */
3144       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
3145       orntNew[0] = ornt[0];
3146       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
3147       orntNew[1] = ornt[1];
3148       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
3149       orntNew[2] = 0;
3150       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[3] - fMax);
3151       orntNew[3] = 0;
3152       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3153       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3154 #if defined(PETSC_USE_DEBUG)
3155       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);
3156       for (p = 0; p < 4; ++p) {
3157         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);
3158       }
3159 #endif
3160     }
3161     /* Interior split faces have 2 vertices and the same cells as the parent */
3162     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3163     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
3164     for (f = fStart; f < fMax; ++f) {
3165       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
3166 
3167       for (r = 0; r < 2; ++r) {
3168         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
3169         const PetscInt *cone, *ornt, *support;
3170         PetscInt        coneNew[2], coneSize, c, supportSize, s;
3171 
3172         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3173         coneNew[0]       = vStartNew + (cone[0] - vStart);
3174         coneNew[1]       = vStartNew + (cone[1] - vStart);
3175         coneNew[(r+1)%2] = newv;
3176         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3177 #if defined(PETSC_USE_DEBUG)
3178         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3179         for (p = 0; p < 2; ++p) {
3180           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);
3181         }
3182 #endif
3183         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3184         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3185         for (s = 0; s < supportSize; ++s) {
3186           if (support[s] >= cMax) {
3187             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
3188           } else {
3189             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3190             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3191             ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3192             for (c = 0; c < coneSize; ++c) {
3193               if (cone[c] == f) break;
3194             }
3195             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
3196           }
3197         }
3198         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3199 #if defined(PETSC_USE_DEBUG)
3200         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3201         for (p = 0; p < supportSize; ++p) {
3202           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);
3203         }
3204 #endif
3205       }
3206     }
3207     /* Interior cell faces have 2 vertices and 2 cells */
3208     for (c = cStart; c < cMax; ++c) {
3209       const PetscInt *cone;
3210 
3211       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3212       for (r = 0; r < 4; ++r) {
3213         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
3214         PetscInt       coneNew[2], supportNew[2];
3215 
3216         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
3217         coneNew[1] = vStartNew + (vEnd - vStart) + (fMax    - fStart) + (c - cStart);
3218         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3219 #if defined(PETSC_USE_DEBUG)
3220         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3221         for (p = 0; p < 2; ++p) {
3222           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);
3223         }
3224 #endif
3225         supportNew[0] = (c - cStart)*4 + r;
3226         supportNew[1] = (c - cStart)*4 + (r+1)%4;
3227         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3228 #if defined(PETSC_USE_DEBUG)
3229         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3230         for (p = 0; p < 2; ++p) {
3231           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);
3232         }
3233 #endif
3234       }
3235     }
3236     /* Hybrid faces have 2 vertices and the same cells */
3237     for (f = fMax; f < fEnd; ++f) {
3238       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
3239       const PetscInt *cone, *support;
3240       PetscInt        coneNew[2], supportNew[2];
3241       PetscInt        size, s, r;
3242 
3243       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3244       coneNew[0] = vStartNew + (cone[0] - vStart);
3245       coneNew[1] = vStartNew + (cone[1] - vStart);
3246       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3247 #if defined(PETSC_USE_DEBUG)
3248       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3249       for (p = 0; p < 2; ++p) {
3250         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);
3251       }
3252 #endif
3253       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3254       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3255       for (s = 0; s < size; ++s) {
3256         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3257         for (r = 0; r < 2; ++r) {
3258           if (cone[r+2] == f) break;
3259         }
3260         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
3261       }
3262       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3263 #if defined(PETSC_USE_DEBUG)
3264       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3265       for (p = 0; p < size; ++p) {
3266         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);
3267       }
3268 #endif
3269     }
3270     /* Cell hybrid faces have 2 vertices and 2 cells */
3271     for (c = cMax; c < cEnd; ++c) {
3272       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
3273       const PetscInt *cone;
3274       PetscInt        coneNew[2], supportNew[2];
3275 
3276       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3277       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
3278       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
3279       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3280 #if defined(PETSC_USE_DEBUG)
3281       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3282       for (p = 0; p < 2; ++p) {
3283         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);
3284       }
3285 #endif
3286       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
3287       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
3288       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3289 #if defined(PETSC_USE_DEBUG)
3290       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3291       for (p = 0; p < 2; ++p) {
3292         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);
3293       }
3294 #endif
3295     }
3296     /* Old vertices have identical supports */
3297     for (v = vStart; v < vEnd; ++v) {
3298       const PetscInt  newp = vStartNew + (v - vStart);
3299       const PetscInt *support, *cone;
3300       PetscInt        size, s;
3301 
3302       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
3303       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
3304       for (s = 0; s < size; ++s) {
3305         if (support[s] >= fMax) {
3306           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (support[s] - fMax);
3307         } else {
3308           PetscInt r = 0;
3309 
3310           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3311           if (cone[1] == v) r = 1;
3312           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
3313         }
3314       }
3315       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3316 #if defined(PETSC_USE_DEBUG)
3317       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
3318       for (p = 0; p < size; ++p) {
3319         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);
3320       }
3321 #endif
3322     }
3323     /* Face vertices have 2 + cells supports */
3324     for (f = fStart; f < fMax; ++f) {
3325       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
3326       const PetscInt *cone, *support;
3327       PetscInt        size, s;
3328 
3329       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3330       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3331       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
3332       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
3333       for (s = 0; s < size; ++s) {
3334         PetscInt r = 0;
3335 
3336         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3337         if (support[s] >= cMax) {
3338           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (support[s] - cMax);
3339         } else {
3340           if      (cone[1] == f) r = 1;
3341           else if (cone[2] == f) r = 2;
3342           else if (cone[3] == f) r = 3;
3343           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*4 + r;
3344         }
3345       }
3346       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3347 #if defined(PETSC_USE_DEBUG)
3348       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
3349       for (p = 0; p < 2+size; ++p) {
3350         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);
3351       }
3352 #endif
3353     }
3354     /* Cell vertices have 4 supports */
3355     for (c = cStart; c < cMax; ++c) {
3356       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
3357       PetscInt       supportNew[4];
3358 
3359       for (r = 0; r < 4; ++r) {
3360         supportNew[r] = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
3361       }
3362       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3363     }
3364     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3365     break;
3366   case REFINER_SIMPLEX_3D:
3367     /* All cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
3368     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
3369     for (c = cStart; c < cEnd; ++c) {
3370       const PetscInt  newp = cStartNew + (c - cStart)*8;
3371       const PetscInt *cone, *ornt;
3372       PetscInt        coneNew[4], orntNew[4];
3373 
3374       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3375       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3376       /* A tetrahedron: {0, a, c, d} */
3377       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
3378       orntNew[0] = ornt[0];
3379       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
3380       orntNew[1] = ornt[1];
3381       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
3382       orntNew[2] = ornt[2];
3383       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
3384       orntNew[3] = 0;
3385       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3386       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3387 #if defined(PETSC_USE_DEBUG)
3388       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);
3389       for (p = 0; p < 4; ++p) {
3390         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);
3391       }
3392 #endif
3393       /* B tetrahedron: {a, 1, b, e} */
3394       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
3395       orntNew[0] = ornt[0];
3396       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
3397       orntNew[1] = ornt[1];
3398       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
3399       orntNew[2] = 0;
3400       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
3401       orntNew[3] = ornt[3];
3402       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3403       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3404 #if defined(PETSC_USE_DEBUG)
3405       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);
3406       for (p = 0; p < 4; ++p) {
3407         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);
3408       }
3409 #endif
3410       /* C tetrahedron: {c, b, 2, f} */
3411       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
3412       orntNew[0] = ornt[0];
3413       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
3414       orntNew[1] = 0;
3415       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
3416       orntNew[2] = ornt[2];
3417       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
3418       orntNew[3] = ornt[3];
3419       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3420       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3421 #if defined(PETSC_USE_DEBUG)
3422       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);
3423       for (p = 0; p < 4; ++p) {
3424         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);
3425       }
3426 #endif
3427       /* D tetrahedron: {d, e, f, 3} */
3428       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
3429       orntNew[0] = 0;
3430       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
3431       orntNew[1] = ornt[1];
3432       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
3433       orntNew[2] = ornt[2];
3434       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
3435       orntNew[3] = ornt[3];
3436       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3437       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3438 #if defined(PETSC_USE_DEBUG)
3439       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);
3440       for (p = 0; p < 4; ++p) {
3441         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);
3442       }
3443 #endif
3444       /* A' tetrahedron: {c, d, a, f} */
3445       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
3446       orntNew[0] = -3;
3447       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
3448       orntNew[1] = ornt[2] < 0 ? -(GetTriMidEdge_Static(ornt[2], 0)+1) : GetTriMidEdge_Static(ornt[2], 0);
3449       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
3450       orntNew[2] = 0;
3451       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
3452       orntNew[3] = 2;
3453       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
3454       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
3455 #if defined(PETSC_USE_DEBUG)
3456       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);
3457       for (p = 0; p < 4; ++p) {
3458         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);
3459       }
3460 #endif
3461       /* B' tetrahedron: {e, b, a, f} */
3462       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
3463       orntNew[0] = -2;
3464       coneNew[1] = fStartNew + (cone[3] - fStart)*4 + 3;
3465       orntNew[1] = ornt[3] < 0 ? -(GetTriMidEdge_Static(ornt[3], 1)+1) : GetTriMidEdge_Static(ornt[3], 1);
3466       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
3467       orntNew[2] = 0;
3468       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
3469       orntNew[3] = 0;
3470       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
3471       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
3472 #if defined(PETSC_USE_DEBUG)
3473       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);
3474       for (p = 0; p < 4; ++p) {
3475         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);
3476       }
3477 #endif
3478       /* C' tetrahedron: {f, a, c, b} */
3479       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
3480       orntNew[0] = -2;
3481       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
3482       orntNew[1] = -2;
3483       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
3484       orntNew[2] = -1;
3485       coneNew[3] = fStartNew + (cone[0] - fStart)*4 + 3;
3486       orntNew[3] = ornt[0] < 0 ? -(GetTriMidEdge_Static(ornt[0], 2)+1) : GetTriMidEdge_Static(ornt[0], 2);
3487       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
3488       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
3489 #if defined(PETSC_USE_DEBUG)
3490       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);
3491       for (p = 0; p < 4; ++p) {
3492         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);
3493       }
3494 #endif
3495       /* D' tetrahedron: {f, a, e, d} */
3496       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
3497       orntNew[0] = -2;
3498       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
3499       orntNew[1] = -1;
3500       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
3501       orntNew[2] = -2;
3502       coneNew[3] = fStartNew + (cone[1] - fStart)*4 + 3;
3503       orntNew[3] = ornt[1] < 0 ? -(GetTriMidEdge_Static(ornt[1], 1)+1) : GetTriMidEdge_Static(ornt[1], 1);
3504       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
3505       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
3506 #if defined(PETSC_USE_DEBUG)
3507       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);
3508       for (p = 0; p < 4; ++p) {
3509         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);
3510       }
3511 #endif
3512     }
3513     /* Split faces have 3 edges and the same cells as the parent */
3514     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3515     ierr = PetscMalloc1(2 + maxSupportSize*3, &supportRef);CHKERRQ(ierr);
3516     for (f = fStart; f < fEnd; ++f) {
3517       const PetscInt  newp = fStartNew + (f - fStart)*4;
3518       const PetscInt *cone, *ornt, *support;
3519       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
3520 
3521       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3522       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3523       /* A triangle */
3524       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
3525       orntNew[0] = ornt[0];
3526       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
3527       orntNew[1] = -2;
3528       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
3529       orntNew[2] = ornt[2];
3530       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3531       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3532 #if defined(PETSC_USE_DEBUG)
3533       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);
3534       for (p = 0; p < 3; ++p) {
3535         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);
3536       }
3537 #endif
3538       /* B triangle */
3539       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
3540       orntNew[0] = ornt[0];
3541       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
3542       orntNew[1] = ornt[1];
3543       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
3544       orntNew[2] = -2;
3545       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3546       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3547 #if defined(PETSC_USE_DEBUG)
3548       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);
3549       for (p = 0; p < 3; ++p) {
3550         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);
3551       }
3552 #endif
3553       /* C triangle */
3554       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
3555       orntNew[0] = -2;
3556       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
3557       orntNew[1] = ornt[1];
3558       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
3559       orntNew[2] = ornt[2];
3560       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3561       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3562 #if defined(PETSC_USE_DEBUG)
3563       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);
3564       for (p = 0; p < 3; ++p) {
3565         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);
3566       }
3567 #endif
3568       /* D triangle */
3569       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
3570       orntNew[0] = 0;
3571       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
3572       orntNew[1] = 0;
3573       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
3574       orntNew[2] = 0;
3575       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3576       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3577 #if defined(PETSC_USE_DEBUG)
3578       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);
3579       for (p = 0; p < 3; ++p) {
3580         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);
3581       }
3582 #endif
3583       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3584       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3585       for (r = 0; r < 4; ++r) {
3586         for (s = 0; s < supportSize; ++s) {
3587           PetscInt subf;
3588           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3589           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3590           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3591           for (c = 0; c < coneSize; ++c) {
3592             if (cone[c] == f) break;
3593           }
3594           subf = GetTriSubfaceInverse_Static(ornt[c], r);
3595           supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
3596         }
3597         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
3598 #if defined(PETSC_USE_DEBUG)
3599         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);
3600         for (p = 0; p < supportSize; ++p) {
3601           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);
3602         }
3603 #endif
3604       }
3605     }
3606     /* Interior faces have 3 edges and 2 cells */
3607     for (c = cStart; c < cEnd; ++c) {
3608       PetscInt        newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8;
3609       const PetscInt *cone, *ornt;
3610       PetscInt        coneNew[3], orntNew[3];
3611       PetscInt        supportNew[2];
3612 
3613       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3614       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3615       /* Face A: {c, a, d} */
3616       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3617       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3618       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3619       orntNew[1] = ornt[1] < 0 ? -2 : 0;
3620       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 2);
3621       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3622       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3623       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3624 #if defined(PETSC_USE_DEBUG)
3625       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3626       for (p = 0; p < 3; ++p) {
3627         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);
3628       }
3629 #endif
3630       supportNew[0] = (c - cStart)*8 + 0;
3631       supportNew[1] = (c - cStart)*8 + 0+4;
3632       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3633 #if defined(PETSC_USE_DEBUG)
3634       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3635       for (p = 0; p < 2; ++p) {
3636         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);
3637       }
3638 #endif
3639       ++newp;
3640       /* Face B: {a, b, e} */
3641       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3642       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3643       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 0);
3644       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3645       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3646       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3647       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3648       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3649 #if defined(PETSC_USE_DEBUG)
3650       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3651       for (p = 0; p < 3; ++p) {
3652         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);
3653       }
3654 #endif
3655       supportNew[0] = (c - cStart)*8 + 1;
3656       supportNew[1] = (c - cStart)*8 + 1+4;
3657       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3658 #if defined(PETSC_USE_DEBUG)
3659       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3660       for (p = 0; p < 2; ++p) {
3661         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);
3662       }
3663 #endif
3664       ++newp;
3665       /* Face C: {c, f, b} */
3666       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3667       orntNew[0] = ornt[2] < 0 ? -2 : 0;
3668       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3669       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3670       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 1);
3671       orntNew[2] = ornt[0] < 0 ? -2 : 0;
3672       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3673       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3674 #if defined(PETSC_USE_DEBUG)
3675       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3676       for (p = 0; p < 3; ++p) {
3677         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);
3678       }
3679 #endif
3680       supportNew[0] = (c - cStart)*8 + 2;
3681       supportNew[1] = (c - cStart)*8 + 2+4;
3682       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3683 #if defined(PETSC_USE_DEBUG)
3684       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3685       for (p = 0; p < 2; ++p) {
3686         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);
3687       }
3688 #endif
3689       ++newp;
3690       /* Face D: {d, e, f} */
3691       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 0);
3692       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3693       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3694       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3695       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3696       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3697       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3698       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3699 #if defined(PETSC_USE_DEBUG)
3700       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3701       for (p = 0; p < 3; ++p) {
3702         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);
3703       }
3704 #endif
3705       supportNew[0] = (c - cStart)*8 + 3;
3706       supportNew[1] = (c - cStart)*8 + 3+4;
3707       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3708 #if defined(PETSC_USE_DEBUG)
3709       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3710       for (p = 0; p < 2; ++p) {
3711         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);
3712       }
3713 #endif
3714       ++newp;
3715       /* Face E: {d, f, a} */
3716       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3717       orntNew[0] = ornt[2] < 0 ? 0 : -2;
3718       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3719       orntNew[1] = -2;
3720       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3721       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3722       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3723       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3724 #if defined(PETSC_USE_DEBUG)
3725       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3726       for (p = 0; p < 3; ++p) {
3727         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);
3728       }
3729 #endif
3730       supportNew[0] = (c - cStart)*8 + 0+4;
3731       supportNew[1] = (c - cStart)*8 + 3+4;
3732       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3733 #if defined(PETSC_USE_DEBUG)
3734       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3735       for (p = 0; p < 2; ++p) {
3736         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);
3737       }
3738 #endif
3739       ++newp;
3740       /* Face F: {c, a, f} */
3741       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3742       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3743       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3744       orntNew[1] = 0;
3745       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3746       orntNew[2] = ornt[2] < 0 ? 0 : -2;
3747       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3748       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3749 #if defined(PETSC_USE_DEBUG)
3750       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3751       for (p = 0; p < 3; ++p) {
3752         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);
3753       }
3754 #endif
3755       supportNew[0] = (c - cStart)*8 + 0+4;
3756       supportNew[1] = (c - cStart)*8 + 2+4;
3757       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3758 #if defined(PETSC_USE_DEBUG)
3759       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3760       for (p = 0; p < 2; ++p) {
3761         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);
3762       }
3763 #endif
3764       ++newp;
3765       /* Face G: {e, a, f} */
3766       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3767       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3768       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3769       orntNew[1] = 0;
3770       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3771       orntNew[2] = ornt[3] < 0 ? 0 : -2;
3772       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3773       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3774 #if defined(PETSC_USE_DEBUG)
3775       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3776       for (p = 0; p < 3; ++p) {
3777         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);
3778       }
3779 #endif
3780       supportNew[0] = (c - cStart)*8 + 1+4;
3781       supportNew[1] = (c - cStart)*8 + 3+4;
3782       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3783 #if defined(PETSC_USE_DEBUG)
3784       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3785       for (p = 0; p < 2; ++p) {
3786         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);
3787       }
3788 #endif
3789       ++newp;
3790       /* Face H: {a, b, f} */
3791       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3792       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3793       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3794       orntNew[1] = ornt[3] < 0 ? 0 : -2;
3795       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3796       orntNew[2] = -2;
3797       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3798       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3799 #if defined(PETSC_USE_DEBUG)
3800       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3801       for (p = 0; p < 3; ++p) {
3802         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);
3803       }
3804 #endif
3805       supportNew[0] = (c - cStart)*8 + 1+4;
3806       supportNew[1] = (c - cStart)*8 + 2+4;
3807       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3808 #if defined(PETSC_USE_DEBUG)
3809       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
3810       for (p = 0; p < 2; ++p) {
3811         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);
3812       }
3813 #endif
3814       ++newp;
3815     }
3816     /* Split Edges have 2 vertices and the same faces as the parent */
3817     for (e = eStart; e < eEnd; ++e) {
3818       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
3819 
3820       for (r = 0; r < 2; ++r) {
3821         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
3822         const PetscInt *cone, *ornt, *support;
3823         PetscInt        coneNew[2], coneSize, c, supportSize, s;
3824 
3825         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3826         coneNew[0]       = vStartNew + (cone[0] - vStart);
3827         coneNew[1]       = vStartNew + (cone[1] - vStart);
3828         coneNew[(r+1)%2] = newv;
3829         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3830 #if defined(PETSC_USE_DEBUG)
3831         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
3832         for (p = 0; p < 2; ++p) {
3833           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);
3834         }
3835 #endif
3836         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
3837         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3838         for (s = 0; s < supportSize; ++s) {
3839           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3840           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3841           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3842           for (c = 0; c < coneSize; ++c) {
3843             if (cone[c] == e) break;
3844           }
3845           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
3846         }
3847         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3848 #if defined(PETSC_USE_DEBUG)
3849         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
3850         for (p = 0; p < supportSize; ++p) {
3851           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);
3852         }
3853 #endif
3854       }
3855     }
3856     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
3857     for (f = fStart; f < fEnd; ++f) {
3858       const PetscInt *cone, *ornt, *support;
3859       PetscInt        coneSize, supportSize, s;
3860 
3861       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3862       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3863       for (r = 0; r < 3; ++r) {
3864         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
3865         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
3866         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
3867                                     -1, -1,  1,  6,  0,  4,
3868                                      2,  5,  3,  4, -1, -1,
3869                                     -1, -1,  3,  6,  2,  7};
3870 
3871         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3872         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
3873         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
3874         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3875 #if defined(PETSC_USE_DEBUG)
3876         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
3877         for (p = 0; p < 2; ++p) {
3878           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);
3879         }
3880 #endif
3881         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
3882         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
3883         for (s = 0; s < supportSize; ++s) {
3884           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3885           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3886           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3887           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
3888           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
3889           er = GetTriMidEdgeInverse_Static(ornt[c], r);
3890           if (er == eint[c]) {
3891             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
3892           } else {
3893             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
3894             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
3895           }
3896         }
3897         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3898 #if defined(PETSC_USE_DEBUG)
3899         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
3900         for (p = 0; p < intFaces; ++p) {
3901           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);
3902         }
3903 #endif
3904       }
3905     }
3906     /* Interior edges have 2 vertices and 4 faces */
3907     for (c = cStart; c < cEnd; ++c) {
3908       const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3909       const PetscInt *cone, *ornt, *fcone;
3910       PetscInt        coneNew[2], supportNew[4], find;
3911 
3912       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3913       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3914       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
3915       find = GetTriEdge_Static(ornt[0], 0);
3916       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3917       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
3918       find = GetTriEdge_Static(ornt[2], 1);
3919       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3920       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3921 #if defined(PETSC_USE_DEBUG)
3922       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
3923       for (p = 0; p < 2; ++p) {
3924         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);
3925       }
3926 #endif
3927       supportNew[0] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 4;
3928       supportNew[1] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 5;
3929       supportNew[2] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 6;
3930       supportNew[3] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 7;
3931       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3932 #if defined(PETSC_USE_DEBUG)
3933       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
3934       for (p = 0; p < 4; ++p) {
3935         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);
3936       }
3937 #endif
3938     }
3939     /* Old vertices have identical supports */
3940     for (v = vStart; v < vEnd; ++v) {
3941       const PetscInt  newp = vStartNew + (v - vStart);
3942       const PetscInt *support, *cone;
3943       PetscInt        size, s;
3944 
3945       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
3946       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
3947       for (s = 0; s < size; ++s) {
3948         PetscInt r = 0;
3949 
3950         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3951         if (cone[1] == v) r = 1;
3952         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
3953       }
3954       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3955 #if defined(PETSC_USE_DEBUG)
3956       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
3957       for (p = 0; p < size; ++p) {
3958         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);
3959       }
3960 #endif
3961     }
3962     /* Edge vertices have 2 + face*2 + 0/1 supports */
3963     for (e = eStart; e < eEnd; ++e) {
3964       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
3965       const PetscInt *cone, *support;
3966       PetscInt       *star = NULL, starSize, cellSize = 0, coneSize, size, s;
3967 
3968       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
3969       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3970       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
3971       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
3972       for (s = 0; s < size; ++s) {
3973         PetscInt r = 0;
3974 
3975         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3976         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3977         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
3978         supportRef[2+s*2+0] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
3979         supportRef[2+s*2+1] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
3980       }
3981       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
3982       for (s = 0; s < starSize*2; s += 2) {
3983         const PetscInt *cone, *ornt;
3984         PetscInt        e01, e23;
3985 
3986         if ((star[s] >= cStart) && (star[s] < cEnd)) {
3987           /* Check edge 0-1 */
3988           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
3989           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
3990           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
3991           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
3992           /* Check edge 2-3 */
3993           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
3994           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
3995           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
3996           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
3997           if ((e01 == e) || (e23 == e)) {supportRef[2+size*2+cellSize++] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (star[s] - cStart);}
3998         }
3999       }
4000       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4001       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4002 #if defined(PETSC_USE_DEBUG)
4003       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
4004       for (p = 0; p < 2+size*2+cellSize; ++p) {
4005         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);
4006       }
4007 #endif
4008     }
4009     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4010     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
4011     break;
4012   case REFINER_HYBRID_SIMPLEX_3D:
4013     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
4014     /* Interior cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
4015     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
4016     for (c = cStart; c < cMax; ++c) {
4017       const PetscInt  newp = cStartNew + (c - cStart)*8;
4018       const PetscInt *cone, *ornt;
4019       PetscInt        coneNew[4], orntNew[4];
4020 
4021       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4022       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4023       /* A tetrahedron: {0, a, c, d} */
4024       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
4025       orntNew[0] = ornt[0];
4026       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
4027       orntNew[1] = ornt[1];
4028       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
4029       orntNew[2] = ornt[2];
4030       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
4031       orntNew[3] = 0;
4032       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4033       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4034 #if defined(PETSC_USE_DEBUG)
4035       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);
4036       for (p = 0; p < 4; ++p) {
4037         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);
4038       }
4039 #endif
4040       /* B tetrahedron: {a, 1, b, e} */
4041       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
4042       orntNew[0] = ornt[0];
4043       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
4044       orntNew[1] = ornt[1];
4045       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
4046       orntNew[2] = 0;
4047       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
4048       orntNew[3] = ornt[3];
4049       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4050       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4051 #if defined(PETSC_USE_DEBUG)
4052       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);
4053       for (p = 0; p < 4; ++p) {
4054         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);
4055       }
4056 #endif
4057       /* C tetrahedron: {c, b, 2, f} */
4058       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
4059       orntNew[0] = ornt[0];
4060       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
4061       orntNew[1] = 0;
4062       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
4063       orntNew[2] = ornt[2];
4064       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
4065       orntNew[3] = ornt[3];
4066       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4067       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4068 #if defined(PETSC_USE_DEBUG)
4069       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);
4070       for (p = 0; p < 4; ++p) {
4071         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);
4072       }
4073 #endif
4074       /* D tetrahedron: {d, e, f, 3} */
4075       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
4076       orntNew[0] = 0;
4077       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
4078       orntNew[1] = ornt[1];
4079       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
4080       orntNew[2] = ornt[2];
4081       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
4082       orntNew[3] = ornt[3];
4083       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4084       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4085 #if defined(PETSC_USE_DEBUG)
4086       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);
4087       for (p = 0; p < 4; ++p) {
4088         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);
4089       }
4090 #endif
4091       /* A' tetrahedron: {d, a, c, f} */
4092       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
4093       orntNew[0] = -3;
4094       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
4095       orntNew[1] = ornt[2] < 0 ? -(GetTriMidEdge_Static(ornt[2], 0)+1) : GetTriMidEdge_Static(ornt[2], 0);
4096       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
4097       orntNew[2] = 0;
4098       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
4099       orntNew[3] = 2;
4100       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
4101       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
4102 #if defined(PETSC_USE_DEBUG)
4103       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);
4104       for (p = 0; p < 4; ++p) {
4105         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);
4106       }
4107 #endif
4108       /* B' tetrahedron: {e, b, a, f} */
4109       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
4110       orntNew[0] = -3;
4111       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
4112       orntNew[1] = 1;
4113       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
4114       orntNew[2] = 0;
4115       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + 3;
4116       orntNew[3] = ornt[3] < 0 ? -(GetTriMidEdge_Static(ornt[3], 0)+1) : GetTriMidEdge_Static(ornt[3], 0);
4117       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
4118       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
4119 #if defined(PETSC_USE_DEBUG)
4120       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);
4121       for (p = 0; p < 4; ++p) {
4122         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);
4123       }
4124 #endif
4125       /* C' tetrahedron: {b, f, c, a} */
4126       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
4127       orntNew[0] = -3;
4128       coneNew[1] = fStartNew + (cone[0] - fStart)*4 + 3;
4129       orntNew[1] = ornt[0] < 0 ? -(GetTriMidEdge_Static(ornt[0], 2)+1) : GetTriMidEdge_Static(ornt[0], 2);
4130       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
4131       orntNew[2] = -3;
4132       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
4133       orntNew[3] = -2;
4134       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
4135       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
4136 #if defined(PETSC_USE_DEBUG)
4137       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);
4138       for (p = 0; p < 4; ++p) {
4139         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);
4140       }
4141 #endif
4142       /* D' tetrahedron: {f, e, d, a} */
4143       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
4144       orntNew[0] = -3;
4145       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
4146       orntNew[1] = -3;
4147       coneNew[2] = fStartNew + (cone[1] - fStart)*4 + 3;
4148       orntNew[2] = ornt[1] < 0 ? -(GetTriMidEdge_Static(ornt[1], 0)+1) : GetTriMidEdge_Static(ornt[1], 0);
4149       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
4150       orntNew[3] = -3;
4151       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
4152       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
4153 #if defined(PETSC_USE_DEBUG)
4154       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);
4155       for (p = 0; p < 4; ++p) {
4156         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);
4157       }
4158 #endif
4159     }
4160     /* Hybrid cells have 5 faces */
4161     for (c = cMax; c < cEnd; ++c) {
4162       const PetscInt  newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4;
4163       const PetscInt *cone, *ornt, *fornt;
4164       PetscInt        coneNew[5], orntNew[5], o, of, i;
4165 
4166       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4167       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4168       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
4169       o = ornt[0] < 0 ? -1 : 1;
4170       for (r = 0; r < 3; ++r) {
4171         coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], r);
4172         orntNew[0] = ornt[0];
4173         coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], r);
4174         orntNew[1] = ornt[1];
4175         of = fornt[GetTriEdge_Static(ornt[0], r)]       < 0 ? -1 : 1;
4176         i  = GetTriEdgeInverse_Static(ornt[0], r)       + 2;
4177         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], r)]       - fMax)*2 + (o*of < 0 ? 1 : 0);
4178         orntNew[i] = 0;
4179         i  = GetTriEdgeInverse_Static(ornt[0], (r+1)%3) + 2;
4180         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + GetTriSubface_Static(ornt[0], r);
4181         orntNew[i] = 0;
4182         of = fornt[GetTriEdge_Static(ornt[0], (r+2)%3)] < 0 ? -1 : 1;
4183         i  = GetTriEdgeInverse_Static(ornt[0], (r+2)%3) + 2;
4184         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);
4185         orntNew[i] = 0;
4186         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
4187         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
4188 #if defined(PETSC_USE_DEBUG)
4189         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);
4190         for (p = 0; p < 2; ++p) {
4191           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);
4192         }
4193         for (p = 2; p < 5; ++p) {
4194           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);
4195         }
4196 #endif
4197       }
4198       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + 3;
4199       orntNew[0] = 0;
4200       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + 3;
4201       orntNew[1] = 0;
4202       coneNew[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
4203       orntNew[2] = 0;
4204       coneNew[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
4205       orntNew[3] = 0;
4206       coneNew[4] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
4207       orntNew[4] = 0;
4208       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4209       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4210 #if defined(PETSC_USE_DEBUG)
4211       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);
4212       for (p = 0; p < 2; ++p) {
4213         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);
4214       }
4215       for (p = 2; p < 5; ++p) {
4216         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);
4217       }
4218 #endif
4219     }
4220     /* Split faces have 3 edges and the same cells as the parent */
4221     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4222     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
4223     for (f = fStart; f < fMax; ++f) {
4224       const PetscInt  newp = fStartNew + (f - fStart)*4;
4225       const PetscInt *cone, *ornt, *support;
4226       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
4227 
4228       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4229       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4230       /* A triangle */
4231       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
4232       orntNew[0] = ornt[0];
4233       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
4234       orntNew[1] = -2;
4235       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
4236       orntNew[2] = ornt[2];
4237       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4238       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4239 #if defined(PETSC_USE_DEBUG)
4240       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);
4241       for (p = 0; p < 3; ++p) {
4242         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);
4243       }
4244 #endif
4245       /* B triangle */
4246       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
4247       orntNew[0] = ornt[0];
4248       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
4249       orntNew[1] = ornt[1];
4250       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
4251       orntNew[2] = -2;
4252       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4253       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4254 #if defined(PETSC_USE_DEBUG)
4255       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);
4256       for (p = 0; p < 3; ++p) {
4257         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);
4258       }
4259 #endif
4260       /* C triangle */
4261       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
4262       orntNew[0] = -2;
4263       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
4264       orntNew[1] = ornt[1];
4265       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
4266       orntNew[2] = ornt[2];
4267       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4268       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4269 #if defined(PETSC_USE_DEBUG)
4270       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);
4271       for (p = 0; p < 3; ++p) {
4272         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);
4273       }
4274 #endif
4275       /* D triangle */
4276       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
4277       orntNew[0] = 0;
4278       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
4279       orntNew[1] = 0;
4280       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
4281       orntNew[2] = 0;
4282       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4283       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4284 #if defined(PETSC_USE_DEBUG)
4285       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);
4286       for (p = 0; p < 3; ++p) {
4287         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);
4288       }
4289 #endif
4290       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4291       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4292       for (r = 0; r < 4; ++r) {
4293         for (s = 0; s < supportSize; ++s) {
4294           PetscInt subf;
4295           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4296           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4297           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4298           for (c = 0; c < coneSize; ++c) {
4299             if (cone[c] == f) break;
4300           }
4301           subf = GetTriSubfaceInverse_Static(ornt[c], r);
4302           if (support[s] < cMax) {
4303             supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
4304           } else {
4305             supportRef[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (r==3 ? r : subf);
4306           }
4307         }
4308         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
4309 #if defined(PETSC_USE_DEBUG)
4310         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);
4311         for (p = 0; p < supportSize; ++p) {
4312           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);
4313         }
4314 #endif
4315       }
4316     }
4317     /* Interior cell faces have 3 edges and 2 cells */
4318     for (c = cStart; c < cMax; ++c) {
4319       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8;
4320       const PetscInt *cone, *ornt;
4321       PetscInt        coneNew[3], orntNew[3];
4322       PetscInt        supportNew[2];
4323 
4324       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4325       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4326       /* Face A: {c, a, d} */
4327       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
4328       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4329       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
4330       orntNew[1] = ornt[1] < 0 ? -2 : 0;
4331       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 2);
4332       orntNew[2] = ornt[2] < 0 ? -2 : 0;
4333       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4334       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4335 #if defined(PETSC_USE_DEBUG)
4336       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4337       for (p = 0; p < 3; ++p) {
4338         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);
4339       }
4340 #endif
4341       supportNew[0] = (c - cStart)*8 + 0;
4342       supportNew[1] = (c - cStart)*8 + 0+4;
4343       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4344 #if defined(PETSC_USE_DEBUG)
4345       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4346       for (p = 0; p < 2; ++p) {
4347         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);
4348       }
4349 #endif
4350       ++newp;
4351       /* Face B: {a, b, e} */
4352       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
4353       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4354       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 0);
4355       orntNew[1] = ornt[3] < 0 ? -2 : 0;
4356       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
4357       orntNew[2] = ornt[1] < 0 ? -2 : 0;
4358       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4359       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4360 #if defined(PETSC_USE_DEBUG)
4361       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);
4362       for (p = 0; p < 3; ++p) {
4363         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);
4364       }
4365 #endif
4366       supportNew[0] = (c - cStart)*8 + 1;
4367       supportNew[1] = (c - cStart)*8 + 1+4;
4368       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4369 #if defined(PETSC_USE_DEBUG)
4370       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4371       for (p = 0; p < 2; ++p) {
4372         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);
4373       }
4374 #endif
4375       ++newp;
4376       /* Face C: {c, f, b} */
4377       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
4378       orntNew[0] = ornt[2] < 0 ? -2 : 0;
4379       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
4380       orntNew[1] = ornt[3] < 0 ? -2 : 0;
4381       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 1);
4382       orntNew[2] = ornt[0] < 0 ? -2 : 0;
4383       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4384       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4385 #if defined(PETSC_USE_DEBUG)
4386       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4387       for (p = 0; p < 3; ++p) {
4388         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);
4389       }
4390 #endif
4391       supportNew[0] = (c - cStart)*8 + 2;
4392       supportNew[1] = (c - cStart)*8 + 2+4;
4393       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4394 #if defined(PETSC_USE_DEBUG)
4395       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4396       for (p = 0; p < 2; ++p) {
4397         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);
4398       }
4399 #endif
4400       ++newp;
4401       /* Face D: {d, e, f} */
4402       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 0);
4403       orntNew[0] = ornt[1] < 0 ? -2 : 0;
4404       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
4405       orntNew[1] = ornt[3] < 0 ? -2 : 0;
4406       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
4407       orntNew[2] = ornt[2] < 0 ? -2 : 0;
4408       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4409       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4410 #if defined(PETSC_USE_DEBUG)
4411       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4412       for (p = 0; p < 3; ++p) {
4413         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);
4414       }
4415 #endif
4416       supportNew[0] = (c - cStart)*8 + 3;
4417       supportNew[1] = (c - cStart)*8 + 3+4;
4418       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4419 #if defined(PETSC_USE_DEBUG)
4420       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4421       for (p = 0; p < 2; ++p) {
4422         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);
4423       }
4424 #endif
4425       ++newp;
4426       /* Face E: {d, f, a} */
4427       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
4428       orntNew[0] = ornt[2] < 0 ? 0 : -2;
4429       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4430       orntNew[1] = -2;
4431       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
4432       orntNew[2] = ornt[1] < 0 ? -2 : 0;
4433       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4434       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4435 #if defined(PETSC_USE_DEBUG)
4436       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4437       for (p = 0; p < 3; ++p) {
4438         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);
4439       }
4440 #endif
4441       supportNew[0] = (c - cStart)*8 + 0+4;
4442       supportNew[1] = (c - cStart)*8 + 3+4;
4443       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4444 #if defined(PETSC_USE_DEBUG)
4445       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4446       for (p = 0; p < 2; ++p) {
4447         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);
4448       }
4449 #endif
4450       ++newp;
4451       /* Face F: {c, a, f} */
4452       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
4453       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4454       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4455       orntNew[1] = 0;
4456       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
4457       orntNew[2] = ornt[2] < 0 ? 0 : -2;
4458       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4459       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4460 #if defined(PETSC_USE_DEBUG)
4461       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4462       for (p = 0; p < 3; ++p) {
4463         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);
4464       }
4465 #endif
4466       supportNew[0] = (c - cStart)*8 + 0+4;
4467       supportNew[1] = (c - cStart)*8 + 2+4;
4468       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4469 #if defined(PETSC_USE_DEBUG)
4470       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4471       for (p = 0; p < 2; ++p) {
4472         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);
4473       }
4474 #endif
4475       ++newp;
4476       /* Face G: {e, a, f} */
4477       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
4478       orntNew[0] = ornt[1] < 0 ? -2 : 0;
4479       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4480       orntNew[1] = 0;
4481       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
4482       orntNew[2] = ornt[3] < 0 ? 0 : -2;
4483       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4484       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4485 #if defined(PETSC_USE_DEBUG)
4486       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4487       for (p = 0; p < 3; ++p) {
4488         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);
4489       }
4490 #endif
4491       supportNew[0] = (c - cStart)*8 + 1+4;
4492       supportNew[1] = (c - cStart)*8 + 3+4;
4493       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4494 #if defined(PETSC_USE_DEBUG)
4495       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4496       for (p = 0; p < 2; ++p) {
4497         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);
4498       }
4499 #endif
4500       ++newp;
4501       /* Face H: {a, b, f} */
4502       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
4503       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4504       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
4505       orntNew[1] = ornt[3] < 0 ? 0 : -2;
4506       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4507       orntNew[2] = -2;
4508       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4509       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4510 #if defined(PETSC_USE_DEBUG)
4511       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4512       for (p = 0; p < 3; ++p) {
4513         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);
4514       }
4515 #endif
4516       supportNew[0] = (c - cStart)*8 + 1+4;
4517       supportNew[1] = (c - cStart)*8 + 2+4;
4518       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4519 #if defined(PETSC_USE_DEBUG)
4520       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
4521       for (p = 0; p < 2; ++p) {
4522         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);
4523       }
4524 #endif
4525       ++newp;
4526     }
4527     /* Hybrid split faces have 4 edges and same cells */
4528     for (f = fMax; f < fEnd; ++f) {
4529       const PetscInt *cone, *ornt, *support;
4530       PetscInt        coneNew[4], orntNew[4];
4531       PetscInt        supportNew[2], size, s, c;
4532 
4533       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4534       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4535       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4536       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4537       for (r = 0; r < 2; ++r) {
4538         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
4539 
4540         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
4541         orntNew[0]   = ornt[0];
4542         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
4543         orntNew[1]   = ornt[1];
4544         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (cone[2+r] - eMax);
4545         orntNew[2+r] = 0;
4546         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd      - eMax) + (f - fMax);
4547         orntNew[3-r] = 0;
4548         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4549         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4550 #if defined(PETSC_USE_DEBUG)
4551         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp, fMaxNew, fEndNew);
4552         for (p = 0; p < 2; ++p) {
4553           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);
4554         }
4555         for (p = 2; p < 4; ++p) {
4556           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);
4557         }
4558 #endif
4559         for (s = 0; s < size; ++s) {
4560           const PetscInt *coneCell, *orntCell, *fornt;
4561           PetscInt        o, of;
4562 
4563           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
4564           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
4565           o = orntCell[0] < 0 ? -1 : 1;
4566           for (c = 2; c < 5; ++c) if (coneCell[c] == f) break;
4567           if (c >= 5) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %D in cone of cell %D", f, support[s]);
4568           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
4569           of = fornt[c-2] < 0 ? -1 : 1;
4570           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetTriEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%3;
4571         }
4572         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4573 #if defined(PETSC_USE_DEBUG)
4574         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp, fMaxNew, fEndNew);
4575         for (p = 0; p < size; ++p) {
4576           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);
4577         }
4578 #endif
4579       }
4580     }
4581     /* Hybrid cell faces have 4 edges and 2 cells */
4582     for (c = cMax; c < cEnd; ++c) {
4583       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3;
4584       const PetscInt *cone, *ornt;
4585       PetscInt        coneNew[4], orntNew[4];
4586       PetscInt        supportNew[2];
4587 
4588       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4589       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4590       for (r = 0; r < 3; ++r) {
4591         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + (r+2)%3;
4592         orntNew[0] = 0;
4593         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + (r+2)%3;
4594         orntNew[1] = 0;
4595         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+(r+2)%3] - fMax);
4596         orntNew[2] = 0;
4597         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+r]       - fMax);
4598         orntNew[3] = 0;
4599         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
4600         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
4601 #if defined(PETSC_USE_DEBUG)
4602         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);
4603         for (p = 0; p < 2; ++p) {
4604           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);
4605         }
4606         for (p = 2; p < 4; ++p) {
4607           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);
4608         }
4609 #endif
4610         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetTriSubface_Static(ornt[0], r);
4611         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + 3;
4612         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
4613 #if defined(PETSC_USE_DEBUG)
4614         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);
4615         for (p = 0; p < 2; ++p) {
4616           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);
4617         }
4618 #endif
4619       }
4620     }
4621     /* Interior split edges have 2 vertices and the same faces as the parent */
4622     for (e = eStart; e < eMax; ++e) {
4623       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
4624 
4625       for (r = 0; r < 2; ++r) {
4626         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
4627         const PetscInt *cone, *ornt, *support;
4628         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4629 
4630         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4631         coneNew[0]       = vStartNew + (cone[0] - vStart);
4632         coneNew[1]       = vStartNew + (cone[1] - vStart);
4633         coneNew[(r+1)%2] = newv;
4634         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4635 #if defined(PETSC_USE_DEBUG)
4636         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4637         for (p = 0; p < 2; ++p) {
4638           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);
4639         }
4640 #endif
4641         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
4642         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4643         for (s = 0; s < supportSize; ++s) {
4644           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4645           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4646           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4647           for (c = 0; c < coneSize; ++c) if (cone[c] == e) break;
4648           if (support[s] < fMax) {
4649             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
4650           } else {
4651             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
4652           }
4653         }
4654         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4655 #if defined(PETSC_USE_DEBUG)
4656         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4657         for (p = 0; p < supportSize; ++p) {
4658           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);
4659         }
4660 #endif
4661       }
4662     }
4663     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
4664     for (f = fStart; f < fMax; ++f) {
4665       const PetscInt *cone, *ornt, *support;
4666       PetscInt        coneSize, supportSize, s;
4667 
4668       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4669       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4670       for (r = 0; r < 3; ++r) {
4671         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
4672         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
4673         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
4674                                     -1, -1,  1,  6,  0,  4,
4675                                      2,  5,  3,  4, -1, -1,
4676                                     -1, -1,  3,  6,  2,  7};
4677 
4678         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4679         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
4680         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
4681         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4682 #if defined(PETSC_USE_DEBUG)
4683         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4684         for (p = 0; p < 2; ++p) {
4685           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);
4686         }
4687 #endif
4688         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
4689         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
4690         for (s = 0; s < supportSize; ++s) {
4691           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4692           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4693           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4694           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
4695           if (support[s] < cMax) {
4696             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
4697             er = GetTriMidEdgeInverse_Static(ornt[c], r);
4698             if (er == eint[c]) {
4699               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
4700             } else {
4701               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
4702               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
4703             }
4704           } else {
4705             supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (r + 1)%3;
4706           }
4707         }
4708         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4709 #if defined(PETSC_USE_DEBUG)
4710         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4711         for (p = 0; p < intFaces; ++p) {
4712           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);
4713         }
4714 #endif
4715       }
4716     }
4717     /* Interior cell edges have 2 vertices and 4 faces */
4718     for (c = cStart; c < cMax; ++c) {
4719       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4720       const PetscInt *cone, *ornt, *fcone;
4721       PetscInt        coneNew[2], supportNew[4], find;
4722 
4723       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4724       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4725       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
4726       find = GetTriEdge_Static(ornt[0], 0);
4727       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4728       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
4729       find = GetTriEdge_Static(ornt[2], 1);
4730       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4731       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4732 #if defined(PETSC_USE_DEBUG)
4733       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4734       for (p = 0; p < 2; ++p) {
4735         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);
4736       }
4737 #endif
4738       supportNew[0] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 4;
4739       supportNew[1] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 5;
4740       supportNew[2] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 6;
4741       supportNew[3] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 7;
4742       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4743 #if defined(PETSC_USE_DEBUG)
4744       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
4745       for (p = 0; p < 4; ++p) {
4746         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);
4747       }
4748 #endif
4749     }
4750     /* Hybrid edges have two vertices and the same faces */
4751     for (e = eMax; e < eEnd; ++e) {
4752       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
4753       const PetscInt *cone, *support, *fcone;
4754       PetscInt        coneNew[2], size, fsize, s;
4755 
4756       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4757       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4758       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4759       coneNew[0] = vStartNew + (cone[0] - vStart);
4760       coneNew[1] = vStartNew + (cone[1] - vStart);
4761       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4762 #if defined(PETSC_USE_DEBUG)
4763       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
4764       for (p = 0; p < 2; ++p) {
4765         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);
4766       }
4767 #endif
4768       for (s = 0; s < size; ++s) {
4769         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
4770         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
4771         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
4772         if ((c < 2) || (c > 3)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Edge %D not found in cone of face %D", e, support[s]);
4773         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + c-2;
4774       }
4775       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4776 #if defined(PETSC_USE_DEBUG)
4777       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
4778       for (p = 0; p < size; ++p) {
4779         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);
4780       }
4781 #endif
4782     }
4783     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
4784     for (f = fMax; f < fEnd; ++f) {
4785       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
4786       const PetscInt *cone, *support, *ccone, *cornt;
4787       PetscInt        coneNew[2], size, csize, s;
4788 
4789       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4790       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4791       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4792       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
4793       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
4794       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4795 #if defined(PETSC_USE_DEBUG)
4796       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
4797       for (p = 0; p < 2; ++p) {
4798         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);
4799       }
4800 #endif
4801       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 0;
4802       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 1;
4803       for (s = 0; s < size; ++s) {
4804         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
4805         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
4806         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
4807         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
4808         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]);
4809         supportRef[2+s*2+0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + c-2;
4810         supportRef[2+s*2+1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (c-1)%3;
4811       }
4812       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4813 #if defined(PETSC_USE_DEBUG)
4814       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
4815       for (p = 0; p < 2+size*2; ++p) {
4816         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);
4817       }
4818 #endif
4819     }
4820     /* Interior vertices have identical supports */
4821     for (v = vStart; v < vEnd; ++v) {
4822       const PetscInt  newp = vStartNew + (v - vStart);
4823       const PetscInt *support, *cone;
4824       PetscInt        size, s;
4825 
4826       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4827       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4828       for (s = 0; s < size; ++s) {
4829         PetscInt r = 0;
4830 
4831         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4832         if (cone[1] == v) r = 1;
4833         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4834         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (support[s] - eMax);
4835       }
4836       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4837 #if defined(PETSC_USE_DEBUG)
4838       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
4839       for (p = 0; p < size; ++p) {
4840         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);
4841       }
4842 #endif
4843     }
4844     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
4845     for (e = eStart; e < eMax; ++e) {
4846       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4847       const PetscInt *cone, *support;
4848       PetscInt       *star = NULL, starSize, faceSize = 0, cellSize = 0, coneSize, size, s;
4849 
4850       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4851       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4852       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4853       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4854       for (s = 0; s < size; ++s) {
4855         PetscInt r = 0;
4856 
4857         if (support[s] < fMax) {
4858           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4859           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4860           for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
4861           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
4862           supportRef[2+faceSize+1] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
4863           faceSize += 2;
4864         } else {
4865           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (support[s] - fMax);
4866           ++faceSize;
4867         }
4868       }
4869       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4870       for (s = 0; s < starSize*2; s += 2) {
4871         const PetscInt *cone, *ornt;
4872         PetscInt        e01, e23;
4873 
4874         if ((star[s] >= cStart) && (star[s] < cMax)) {
4875           /* Check edge 0-1 */
4876           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
4877           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
4878           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
4879           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
4880           /* Check edge 2-3 */
4881           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
4882           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
4883           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
4884           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
4885           if ((e01 == e) || (e23 == e)) {supportRef[2+faceSize+cellSize++] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (star[s] - cStart);}
4886         }
4887       }
4888       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4889       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4890 #if defined(PETSC_USE_DEBUG)
4891       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
4892       for (p = 0; p < 2+faceSize+cellSize; ++p) {
4893         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);
4894       }
4895 #endif
4896     }
4897     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4898     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
4899     break;
4900   case REFINER_SIMPLEX_TO_HEX_3D:
4901     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
4902     /* All cells have 6 faces */
4903     for (c = cStart; c < cEnd; ++c) {
4904       const PetscInt  newp = cStartNew + (c - cStart)*4;
4905       const PetscInt *cone, *ornt;
4906       PetscInt        coneNew[6];
4907       PetscInt        orntNew[6];
4908 
4909       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4910       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4911       /* A hex */
4912       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 0); /* B */
4913       orntNew[0] = ornt[0] < 0 ? -1 : 1;
4914       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 3;               /* T */
4915       orntNew[1] = -4;
4916       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 0); /* F */
4917       orntNew[2] = ornt[2] < 0 ? -1 : 1;
4918       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 0;               /* K */
4919       orntNew[3] = -1;
4920       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 2;               /* R */
4921       orntNew[4] = 0;
4922       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 0); /* L */
4923       orntNew[5] = ornt[1] < 0 ? -1 : 1;
4924       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4925       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4926 #if defined(PETSC_USE_DEBUG)
4927       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);
4928       for (p = 0; p < 6; ++p) {
4929         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);
4930       }
4931 #endif
4932       /* B hex */
4933       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 1); /* B */
4934       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4935       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 4;               /* T */
4936       orntNew[1] = 0;
4937       coneNew[2] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 0;               /* F */
4938       orntNew[2] = 0;
4939       coneNew[3] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 1); /* K */
4940       orntNew[3] = ornt[3] < 0 ? -2 : 0;
4941       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 1;               /* R */
4942       orntNew[4] = 0;
4943       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 2); /* L */
4944       orntNew[5] = ornt[1] < 0 ? -4 : 2;
4945       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4946       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4947 #if defined(PETSC_USE_DEBUG)
4948       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);
4949       for (p = 0; p < 6; ++p) {
4950         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);
4951       }
4952 #endif
4953       /* C hex */
4954       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 2); /* B */
4955       orntNew[0] = ornt[0] < 0 ? -4 : 2;
4956       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 5;               /* T */
4957       orntNew[1] = -4;
4958       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 1); /* F */
4959       orntNew[2] = ornt[2] < 0 ? -2 : 0;
4960       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 1;               /* K */
4961       orntNew[3] = -1;
4962       coneNew[4] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 0); /* R */
4963       orntNew[4] = ornt[3] < 0 ? -1 : 1;
4964       coneNew[5] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 2;               /* L */
4965       orntNew[5] = -4;
4966       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4967       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4968 #if defined(PETSC_USE_DEBUG)
4969       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);
4970       for (p = 0; p < 6; ++p) {
4971         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);
4972       }
4973 #endif
4974       /* D hex */
4975       coneNew[0] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 3;               /* B */
4976       orntNew[0] = 0;
4977       coneNew[1] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 2); /* T */
4978       orntNew[1] = ornt[3] < 0 ? -1 : 1;
4979       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 2); /* F */
4980       orntNew[2] = ornt[2] < 0 ? -4 : 2;
4981       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 4;               /* K */
4982       orntNew[3] = -1;
4983       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 5;               /* R */
4984       orntNew[4] = 0;
4985       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 1); /* L */
4986       orntNew[5] = ornt[1] < 0 ? -2 : 0;
4987       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4988       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4989 #if defined(PETSC_USE_DEBUG)
4990       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);
4991       for (p = 0; p < 6; ++p) {
4992         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);
4993       }
4994 #endif
4995     }
4996     /* Split faces have 4 edges and the same cells as the parent */
4997     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4998     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
4999     for (f = fStart; f < fEnd; ++f) {
5000       const PetscInt  newp = fStartNew + (f - fStart)*3;
5001       const PetscInt *cone, *ornt, *support;
5002       PetscInt        coneNew[4], orntNew[4], coneSize, supportSize, s;
5003 
5004       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5005       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
5006       /* A quad */
5007       coneNew[0] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
5008       orntNew[0] = ornt[2];
5009       coneNew[1] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
5010       orntNew[1] = ornt[0];
5011       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
5012       orntNew[2] = 0;
5013       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
5014       orntNew[3] = -2;
5015       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5016       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5017 #if defined(PETSC_USE_DEBUG)
5018       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);
5019       for (p = 0; p < 4; ++p) {
5020         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);
5021       }
5022 #endif
5023       /* B quad */
5024       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
5025       orntNew[0] = ornt[0];
5026       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
5027       orntNew[1] = ornt[1];
5028       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
5029       orntNew[2] = 0;
5030       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
5031       orntNew[3] = -2;
5032       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5033       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5034 #if defined(PETSC_USE_DEBUG)
5035       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);
5036       for (p = 0; p < 4; ++p) {
5037         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);
5038       }
5039 #endif
5040       /* C quad */
5041       coneNew[0] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
5042       orntNew[0] = ornt[1];
5043       coneNew[1] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
5044       orntNew[1] = ornt[2];
5045       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
5046       orntNew[2] = 0;
5047       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
5048       orntNew[3] = -2;
5049       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5050       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5051 #if defined(PETSC_USE_DEBUG)
5052       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);
5053       for (p = 0; p < 4; ++p) {
5054         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);
5055       }
5056 #endif
5057       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5058       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5059       for (r = 0; r < 3; ++r) {
5060         for (s = 0; s < supportSize; ++s) {
5061           PetscInt subf;
5062           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5063           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5064           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5065           for (c = 0; c < coneSize; ++c) {
5066             if (cone[c] == f) break;
5067           }
5068           subf = GetTriSubfaceInverse_Static(ornt[c], r);
5069           supportRef[s] = cStartNew + (support[s] - cStart)*4 + faces[c*3+subf];
5070         }
5071         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
5072 #if defined(PETSC_USE_DEBUG)
5073         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);
5074         for (p = 0; p < supportSize; ++p) {
5075           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);
5076         }
5077 #endif
5078       }
5079     }
5080     /* Interior faces have 4 edges and 2 cells */
5081     for (c = cStart; c < cEnd; ++c) {
5082       PetscInt        newp = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6;
5083       const PetscInt *cone, *ornt;
5084       PetscInt        coneNew[4], orntNew[4];
5085       PetscInt        supportNew[2];
5086 
5087       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5088       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5089       /* Face {a, g, m, h} */
5090       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],0);
5091       orntNew[0] = 0;
5092       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
5093       orntNew[1] = 0;
5094       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
5095       orntNew[2] = -2;
5096       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],2);
5097       orntNew[3] = -2;
5098       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5099       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5100 #if defined(PETSC_USE_DEBUG)
5101       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5102       for (p = 0; p < 4; ++p) {
5103         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);
5104       }
5105 #endif
5106       supportNew[0] = (c - cStart)*4 + 0;
5107       supportNew[1] = (c - cStart)*4 + 1;
5108       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5109 #if defined(PETSC_USE_DEBUG)
5110       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5111       for (p = 0; p < 2; ++p) {
5112         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);
5113       }
5114 #endif
5115       ++newp;
5116       /* Face {g, b, l , m} */
5117       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],1);
5118       orntNew[0] = -2;
5119       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],0);
5120       orntNew[1] = 0;
5121       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
5122       orntNew[2] = 0;
5123       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
5124       orntNew[3] = -2;
5125       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5126       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5127 #if defined(PETSC_USE_DEBUG)
5128       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5129       for (p = 0; p < 4; ++p) {
5130         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);
5131       }
5132 #endif
5133       supportNew[0] = (c - cStart)*4 + 1;
5134       supportNew[1] = (c - cStart)*4 + 2;
5135       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5136 #if defined(PETSC_USE_DEBUG)
5137       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5138       for (p = 0; p < 2; ++p) {
5139         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);
5140       }
5141 #endif
5142       ++newp;
5143       /* Face {c, g, m, i} */
5144       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],2);
5145       orntNew[0] = 0;
5146       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
5147       orntNew[1] = 0;
5148       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
5149       orntNew[2] = -2;
5150       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],0);
5151       orntNew[3] = -2;
5152       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5153       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5154 #if defined(PETSC_USE_DEBUG)
5155       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5156       for (p = 0; p < 4; ++p) {
5157         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);
5158       }
5159 #endif
5160       supportNew[0] = (c - cStart)*4 + 0;
5161       supportNew[1] = (c - cStart)*4 + 2;
5162       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5163 #if defined(PETSC_USE_DEBUG)
5164       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5165       for (p = 0; p < 2; ++p) {
5166         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);
5167       }
5168 #endif
5169       ++newp;
5170       /* Face {d, h, m, i} */
5171       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],0);
5172       orntNew[0] = 0;
5173       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
5174       orntNew[1] = 0;
5175       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
5176       orntNew[2] = -2;
5177       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],2);
5178       orntNew[3] = -2;
5179       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5180       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5181 #if defined(PETSC_USE_DEBUG)
5182       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5183       for (p = 0; p < 4; ++p) {
5184         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);
5185       }
5186 #endif
5187       supportNew[0] = (c - cStart)*4 + 0;
5188       supportNew[1] = (c - cStart)*4 + 3;
5189       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5190 #if defined(PETSC_USE_DEBUG)
5191       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5192       for (p = 0; p < 2; ++p) {
5193         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);
5194       }
5195 #endif
5196       ++newp;
5197       /* Face {h, m, l, e} */
5198       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
5199       orntNew[0] = 0;
5200       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
5201       orntNew[1] = -2;
5202       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],1);
5203       orntNew[2] = -2;
5204       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],1);
5205       orntNew[3] = 0;
5206       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5207       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5208 #if defined(PETSC_USE_DEBUG)
5209       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5210       for (p = 0; p < 4; ++p) {
5211         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);
5212       }
5213 #endif
5214       supportNew[0] = (c - cStart)*4 + 1;
5215       supportNew[1] = (c - cStart)*4 + 3;
5216       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5217 #if defined(PETSC_USE_DEBUG)
5218       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5219       for (p = 0; p < 2; ++p) {
5220         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);
5221       }
5222 #endif
5223       ++newp;
5224       /* Face {i, m, l, f} */
5225       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
5226       orntNew[0] = 0;
5227       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
5228       orntNew[1] = -2;
5229       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],2);
5230       orntNew[2] = -2;
5231       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],1);
5232       orntNew[3] = 0;
5233       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5234       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5235 #if defined(PETSC_USE_DEBUG)
5236       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5237       for (p = 0; p < 4; ++p) {
5238         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);
5239       }
5240 #endif
5241       supportNew[0] = (c - cStart)*4 + 2;
5242       supportNew[1] = (c - cStart)*4 + 3;
5243       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5244 #if defined(PETSC_USE_DEBUG)
5245       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5246       for (p = 0; p < 2; ++p) {
5247         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);
5248       }
5249 #endif
5250       ++newp;
5251     }
5252     /* Split Edges have 2 vertices and the same faces as the parent */
5253     for (e = eStart; e < eEnd; ++e) {
5254       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
5255 
5256       for (r = 0; r < 2; ++r) {
5257         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
5258         const PetscInt *cone, *ornt, *support;
5259         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5260 
5261         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
5262         coneNew[0]       = vStartNew + (cone[0] - vStart);
5263         coneNew[1]       = vStartNew + (cone[1] - vStart);
5264         coneNew[(r+1)%2] = newv;
5265         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5266 #if defined(PETSC_USE_DEBUG)
5267         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5268         for (p = 0; p < 2; ++p) {
5269           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);
5270         }
5271 #endif
5272         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
5273         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5274         for (s = 0; s < supportSize; ++s) {
5275           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5276           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5277           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5278           for (c = 0; c < coneSize; ++c) {
5279             if (cone[c] == e) break;
5280           }
5281           supportRef[s] = fStartNew + (support[s] - fStart)*3 + (c + (ornt[c] < 0 ? 1-r : r))%3;
5282         }
5283         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5284 #if defined(PETSC_USE_DEBUG)
5285         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5286         for (p = 0; p < supportSize; ++p) {
5287           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);
5288         }
5289 #endif
5290       }
5291     }
5292     /* Face edges have 2 vertices and 2 + cell faces supports */
5293     for (f = fStart; f < fEnd; ++f) {
5294       const PetscInt *cone, *ornt, *support;
5295       PetscInt        coneSize, supportSize, s;
5296 
5297       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5298       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5299       for (r = 0; r < 3; ++r) {
5300         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
5301         PetscInt        coneNew[2];
5302         PetscInt        fint[4][3] = { {0, 1, 2},
5303                                        {3, 4, 0},
5304                                        {2, 5, 3},
5305                                        {1, 4, 5} };
5306 
5307         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5308         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
5309         coneNew[1] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + f - fStart;
5310         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5311 #if defined(PETSC_USE_DEBUG)
5312         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5313         for (p = 0; p < 2; ++p) {
5314           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);
5315         }
5316 #endif
5317         supportRef[0] = fStartNew + (f - fStart)*3 + (r+0)%3;
5318         supportRef[1] = fStartNew + (f - fStart)*3 + (r+1)%3;
5319         for (s = 0; s < supportSize; ++s) {
5320           PetscInt er;
5321           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5322           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5323           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5324           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
5325           er = GetTriInteriorEdgeInverse_Static(ornt[c], r);
5326           supportRef[2+s] = fStartNew + (fEnd - fStart)*3 + (support[s] - cStart)*6 + fint[c][er];
5327         }
5328         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5329 #if defined(PETSC_USE_DEBUG)
5330         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5331         for (p = 0; p < supportSize + 2; ++p) {
5332           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);
5333         }
5334 #endif
5335       }
5336     }
5337     /* Interior cell edges have 2 vertices and 3 faces */
5338     for (c = cStart; c < cEnd; ++c) {
5339       const PetscInt *cone;
5340       PetscInt       fint[4][3] = { {0,1,2},
5341                                     {0,3,4},
5342                                     {2,3,5},
5343                                     {1,4,5} } ;
5344 
5345       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5346       for (r = 0; r < 4; r++) {
5347         PetscInt       coneNew[2], supportNew[3];
5348         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + r;
5349 
5350         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
5351         coneNew[1] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd -fStart) + c - cStart;
5352         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5353 #if defined(PETSC_USE_DEBUG)
5354         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5355         for (p = 0; p < 2; ++p) {
5356           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);
5357         }
5358 #endif
5359         supportNew[0] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][0];
5360         supportNew[1] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][1];
5361         supportNew[2] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][2];
5362         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5363 #if defined(PETSC_USE_DEBUG)
5364         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
5365         for (p = 0; p < 3; ++p) {
5366           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);
5367         }
5368 #endif
5369       }
5370     }
5371     /* Old vertices have identical supports */
5372     for (v = vStart; v < vEnd; ++v) {
5373       const PetscInt  newp = vStartNew + (v - vStart);
5374       const PetscInt *support, *cone;
5375       PetscInt        size, s;
5376 
5377       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5378       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5379       for (s = 0; s < size; ++s) {
5380         PetscInt r = 0;
5381 
5382         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5383         if (cone[1] == v) r = 1;
5384         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
5385       }
5386       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5387 #if defined(PETSC_USE_DEBUG)
5388       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
5389       for (p = 0; p < size; ++p) {
5390         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);
5391       }
5392 #endif
5393     }
5394     /* Edge vertices have 2 + faces supports */
5395     for (e = eStart; e < eEnd; ++e) {
5396       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
5397       const PetscInt *cone, *support;
5398       PetscInt        size, s;
5399 
5400       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
5401       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5402       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
5403       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
5404       for (s = 0; s < size; ++s) {
5405         PetscInt r = 0, coneSize;
5406 
5407         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5408         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5409         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
5410         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + r;
5411       }
5412       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5413 #if defined(PETSC_USE_DEBUG)
5414       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
5415       for (p = 0; p < 2+size; ++p) {
5416         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);
5417       }
5418 #endif
5419     }
5420     /* Face vertices have 3 + cells supports */
5421     for (f = fStart; f < fEnd; ++f) {
5422       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
5423       const PetscInt *cone, *support;
5424       PetscInt        size, s;
5425 
5426       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5427       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5428       supportRef[0] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 0;
5429       supportRef[1] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 1;
5430       supportRef[2] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 2;
5431       for (s = 0; s < size; ++s) {
5432         PetscInt r = 0, coneSize;
5433 
5434         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5435         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5436         for (r = 0; r < coneSize; ++r) {if (cone[r] == f) break;}
5437         supportRef[3+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (support[s] - cStart)*4 + r;
5438       }
5439       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5440 #if defined(PETSC_USE_DEBUG)
5441       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
5442       for (p = 0; p < 3+size; ++p) {
5443         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);
5444       }
5445 #endif
5446     }
5447     /* Interior cell vertices have 4 supports */
5448     for (c = cStart; c < cEnd; ++c) {
5449       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + c - cStart;
5450       supportRef[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
5451       supportRef[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
5452       supportRef[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
5453       supportRef[3] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
5454       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5455 #if defined(PETSC_USE_DEBUG)
5456       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
5457       for (p = 0; p < 4; ++p) {
5458         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);
5459       }
5460 #endif
5461     }
5462     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5463     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
5464     break;
5465   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
5466     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5467     cMax = PetscMin(cEnd, cMax);
5468     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5469     fMax = PetscMin(fEnd, fMax);
5470     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5471     eMax = PetscMin(eEnd, eMax);
5472     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
5473     /* All cells have 6 faces */
5474     for (c = cStart; c < cMax; ++c) {
5475       const PetscInt  newp = cStartNew + (c - cStart)*4;
5476       const PetscInt *cone, *ornt;
5477       PetscInt        coneNew[6];
5478       PetscInt        orntNew[6];
5479 
5480       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5481 #if defined(PETSC_USE_DEBUG)
5482       for (p = 0; p < 4; ++p) {
5483         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);
5484       }
5485 #endif
5486       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5487       /* A hex */
5488       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 0); /* B */
5489       orntNew[0] = ornt[0] < 0 ? -1 : 1;
5490       coneNew[1] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 3;               /* T */
5491       orntNew[1] = -4;
5492       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 0); /* F */
5493       orntNew[2] = ornt[2] < 0 ? -1 : 1;
5494       coneNew[3] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 0;               /* K */
5495       orntNew[3] = -1;
5496       coneNew[4] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 2;               /* R */
5497       orntNew[4] = 0;
5498       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 0); /* L */
5499       orntNew[5] = ornt[1] < 0 ? -1 : 1;
5500       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5501       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5502 #if defined(PETSC_USE_DEBUG)
5503       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);
5504       for (p = 0; p < 6; ++p) {
5505         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);
5506       }
5507 #endif
5508       /* B hex */
5509       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 1); /* B */
5510       orntNew[0] = ornt[0] < 0 ? -2 : 0;
5511       coneNew[1] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 4;               /* T */
5512       orntNew[1] = 0;
5513       coneNew[2] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 0;               /* F */
5514       orntNew[2] = 0;
5515       coneNew[3] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 1); /* K */
5516       orntNew[3] = ornt[3] < 0 ? -2 : 0;
5517       coneNew[4] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 1;               /* R */
5518       orntNew[4] = 0;
5519       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 2); /* L */
5520       orntNew[5] = ornt[1] < 0 ? -4 : 2;
5521       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5522       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5523 #if defined(PETSC_USE_DEBUG)
5524       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);
5525       for (p = 0; p < 6; ++p) {
5526         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);
5527       }
5528 #endif
5529       /* C hex */
5530       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 2); /* B */
5531       orntNew[0] = ornt[0] < 0 ? -4 : 2;
5532       coneNew[1] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 5;               /* T */
5533       orntNew[1] = -4;
5534       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 1); /* F */
5535       orntNew[2] = ornt[2] < 0 ? -2 : 0;
5536       coneNew[3] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 1;               /* K */
5537       orntNew[3] = -1;
5538       coneNew[4] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 0); /* R */
5539       orntNew[4] = ornt[3] < 0 ? -1 : 1;
5540       coneNew[5] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 2;               /* L */
5541       orntNew[5] = -4;
5542       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5543       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5544 #if defined(PETSC_USE_DEBUG)
5545       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);
5546       for (p = 0; p < 6; ++p) {
5547         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);
5548       }
5549 #endif
5550       /* D hex */
5551       coneNew[0] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 3;               /* B */
5552       orntNew[0] = 0;
5553       coneNew[1] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 2); /* T */
5554       orntNew[1] = ornt[3] < 0 ? -1 : 1;
5555       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 2); /* F */
5556       orntNew[2] = ornt[2] < 0 ? -4 : 2;
5557       coneNew[3] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 4;               /* K */
5558       orntNew[3] = -1;
5559       coneNew[4] = fStartNew + (fMax    - fStart)*3 + (c - cStart)*6 + 5;               /* R */
5560       orntNew[4] = 0;
5561       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 1); /* L */
5562       orntNew[5] = ornt[1] < 0 ? -2 : 0;
5563       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5564       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5565 #if defined(PETSC_USE_DEBUG)
5566       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);
5567       for (p = 0; p < 6; ++p) {
5568         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);
5569       }
5570 #endif
5571     }
5572     for (c = cMax; c < cEnd; ++c) {
5573       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*3;
5574       const PetscInt *cone, *ornt, *fornt;
5575       PetscInt        coneNew[6], orntNew[6];
5576       PetscInt        o, of, cf;
5577 
5578       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5579 #if defined(PETSC_USE_DEBUG)
5580       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);
5581       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);
5582       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);
5583       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);
5584       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);
5585 #endif
5586       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5587       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
5588       o    = ornt[0] < 0 ? -1 : 1;
5589       /* A hex */
5590       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 0);                            /* B */
5591       orntNew[0] = ornt[0] < 0 ? -1 :  1;
5592       coneNew[1] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 0);                            /* T */
5593       orntNew[1] = ornt[1] < 0 ?  1 : -1;
5594       cf         = GetTriEdge_Static(ornt[0], 2);
5595       of         = fornt[cf] < 0 ? -1 : 1;
5596       coneNew[2] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 0 : 1); /* F */
5597       orntNew[2] = o*of < 0 ? 0 : -1;
5598       coneNew[3] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;         /* K */
5599       orntNew[3] = -1;
5600       coneNew[4] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;         /* R */
5601       orntNew[4] = 0;
5602       cf         = GetTriEdge_Static(ornt[0], 0);
5603       of         = fornt[cf] < 0 ? -1 : 1;
5604       coneNew[5] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 1 : 0); /* L */
5605       orntNew[5] = o*of < 0 ? 1 : -4;
5606       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5607       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5608 #if defined(PETSC_USE_DEBUG)
5609       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);
5610       for (p = 0; p < 6; ++p) {
5611         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);
5612       }
5613 #endif
5614       /* B hex */
5615       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 1);                            /* B */
5616       orntNew[0] = ornt[0] < 0 ? -2 :  0;
5617       coneNew[1] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 1);                            /* T */
5618       orntNew[1] = ornt[1] < 0 ?  2 : -4;
5619       coneNew[2] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;         /* F */
5620       orntNew[2] = 0;
5621       cf         = GetTriEdge_Static(ornt[0], 1);
5622       of         = fornt[cf] < 0 ? -1 : 1;
5623       coneNew[3] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 1 : 0); /* K */
5624       orntNew[3] = o*of < 0 ? 0 : -1;
5625       coneNew[4] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;         /* R */
5626       orntNew[4] = -1;
5627       cf         = GetTriEdge_Static(ornt[0], 0);
5628       of         = fornt[cf] < 0 ? -1 : 1;
5629       coneNew[5] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 0 : 1); /* L */
5630       orntNew[5] = o*of < 0 ? 1 : -4;
5631       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5632       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5633 #if defined(PETSC_USE_DEBUG)
5634       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);
5635       for (p = 0; p < 6; ++p) {
5636         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);
5637       }
5638 #endif
5639       /* C hex */
5640       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 2);                            /* B */
5641       orntNew[0] = ornt[0] < 0 ? -4 : 2;
5642       coneNew[1] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 2);                            /* T */
5643       orntNew[1] = ornt[1] < 0 ? 0 : -2;
5644       cf         = GetTriEdge_Static(ornt[0], 2);
5645       of         = fornt[cf] < 0 ? -1 : 1;
5646       coneNew[2] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 1 : 0); /* F */
5647       orntNew[2] = o*of < 0 ? 0 : -1;
5648       coneNew[3] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;         /* K */
5649       orntNew[3] = 0;
5650       cf         = GetTriEdge_Static(ornt[0], 1);
5651       of         = fornt[cf] < 0 ? -1 : 1;
5652       coneNew[4] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (cone[2+cf] - fMax)*2 + (o*of < 0 ? 0 : 1); /* R */
5653       orntNew[4] = o*of < 0 ? 0 : -1;
5654       coneNew[5] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;         /* L */
5655       orntNew[5] = -4;
5656       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5657       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5658 #if defined(PETSC_USE_DEBUG)
5659       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);
5660       for (p = 0; p < 6; ++p) {
5661         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);
5662       }
5663 #endif
5664     }
5665 
5666     /* Split faces have 4 edges and the same cells as the parent */
5667     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5668     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
5669     for (f = fStart; f < fMax; ++f) {
5670       const PetscInt  newp = fStartNew + (f - fStart)*3;
5671       const PetscInt *cone, *ornt, *support;
5672       PetscInt        coneNew[4], orntNew[4], coneSize, supportSize, s;
5673 
5674       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5675 #if defined(PETSC_USE_DEBUG)
5676       for (p = 0; p < 3; ++p) {
5677         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);
5678       }
5679 #endif
5680       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
5681       /* A quad */
5682       coneNew[0] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
5683       orntNew[0] = ornt[2];
5684       coneNew[1] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
5685       orntNew[1] = ornt[0];
5686       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
5687       orntNew[2] = 0;
5688       coneNew[3] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
5689       orntNew[3] = -2;
5690       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5691       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5692 #if defined(PETSC_USE_DEBUG)
5693       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);
5694       for (p = 0; p < 4; ++p) {
5695         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);
5696       }
5697 #endif
5698       /* B quad */
5699       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
5700       orntNew[0] = ornt[0];
5701       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
5702       orntNew[1] = ornt[1];
5703       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
5704       orntNew[2] = 0;
5705       coneNew[3] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
5706       orntNew[3] = -2;
5707       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5708       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5709 #if defined(PETSC_USE_DEBUG)
5710       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);
5711       for (p = 0; p < 4; ++p) {
5712         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);
5713       }
5714 #endif
5715       /* C quad */
5716       coneNew[0] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
5717       orntNew[0] = ornt[1];
5718       coneNew[1] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
5719       orntNew[1] = ornt[2];
5720       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
5721       orntNew[2] = 0;
5722       coneNew[3] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
5723       orntNew[3] = -2;
5724       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5725       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5726 #if defined(PETSC_USE_DEBUG)
5727       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);
5728       for (p = 0; p < 4; ++p) {
5729         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);
5730       }
5731 #endif
5732       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5733       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5734       for (r = 0; r < 3; ++r) {
5735         for (s = 0; s < supportSize; ++s) {
5736           PetscInt subf;
5737 
5738           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5739           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);
5740           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);
5741           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5742           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5743           for (c = 0; c < coneSize; ++c) {
5744             if (cone[c] == f) break;
5745           }
5746           subf = GetTriSubfaceInverse_Static(ornt[c], r);
5747           if (coneSize == 4) {
5748             supportRef[s] = cStartNew + (support[s] - cStart)*4 + faces[c*3+subf];
5749           } else if (coneSize == 5) {
5750             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);
5751             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*3 + subf;
5752           } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for cell %D (cMax %D)", coneSize, support[s], cMax);
5753         }
5754         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
5755 #if defined(PETSC_USE_DEBUG)
5756         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);
5757         for (p = 0; p < supportSize; ++p) {
5758           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);
5759         }
5760 #endif
5761       }
5762     }
5763     /* Interior faces have 4 edges and 2 cells */
5764     for (c = cStart; c < cMax; ++c) {
5765       PetscInt        newp = fStartNew + (fMax - fStart)*3 + (c - cStart)*6;
5766       const PetscInt *cone, *ornt;
5767       PetscInt        coneNew[4], orntNew[4];
5768       PetscInt        supportNew[2];
5769 
5770       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5771 #if defined(PETSC_USE_DEBUG)
5772       for (p = 0; p < 4; ++p) {
5773         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);
5774       }
5775 #endif
5776       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5777       /* Face {a, g, m, h} */
5778       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],0);
5779       orntNew[0] = 0;
5780       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 0;
5781       orntNew[1] = 0;
5782       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 1;
5783       orntNew[2] = -2;
5784       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],2);
5785       orntNew[3] = -2;
5786       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5787       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5788 #if defined(PETSC_USE_DEBUG)
5789       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5790       for (p = 0; p < 4; ++p) {
5791         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);
5792       }
5793 #endif
5794       supportNew[0] = cStartNew + (c - cStart)*4 + 0;
5795       supportNew[1] = cStartNew + (c - cStart)*4 + 1;
5796       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5797 #if defined(PETSC_USE_DEBUG)
5798       for (p = 0; p < 2; ++p) {
5799         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);
5800       }
5801 #endif
5802       ++newp;
5803       /* Face {g, b, l , m} */
5804       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],1);
5805       orntNew[0] = -2;
5806       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],0);
5807       orntNew[1] = 0;
5808       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 3;
5809       orntNew[2] = 0;
5810       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 0;
5811       orntNew[3] = -2;
5812       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5813       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5814 #if defined(PETSC_USE_DEBUG)
5815       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5816       for (p = 0; p < 4; ++p) {
5817         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);
5818       }
5819 #endif
5820       supportNew[0] = cStartNew + (c - cStart)*4 + 1;
5821       supportNew[1] = cStartNew + (c - cStart)*4 + 2;
5822       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5823 #if defined(PETSC_USE_DEBUG)
5824       for (p = 0; p < 2; ++p) {
5825         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);
5826       }
5827 #endif
5828       ++newp;
5829       /* Face {c, g, m, i} */
5830       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],2);
5831       orntNew[0] = 0;
5832       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 0;
5833       orntNew[1] = 0;
5834       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 2;
5835       orntNew[2] = -2;
5836       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],0);
5837       orntNew[3] = -2;
5838       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5839       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5840 #if defined(PETSC_USE_DEBUG)
5841       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5842       for (p = 0; p < 4; ++p) {
5843         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);
5844       }
5845 #endif
5846       supportNew[0] = cStartNew + (c - cStart)*4 + 0;
5847       supportNew[1] = cStartNew + (c - cStart)*4 + 2;
5848       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5849 #if defined(PETSC_USE_DEBUG)
5850       for (p = 0; p < 2; ++p) {
5851         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);
5852       }
5853 #endif
5854       ++newp;
5855       /* Face {d, h, m, i} */
5856       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],0);
5857       orntNew[0] = 0;
5858       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 1;
5859       orntNew[1] = 0;
5860       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 2;
5861       orntNew[2] = -2;
5862       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],2);
5863       orntNew[3] = -2;
5864       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5865       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5866 #if defined(PETSC_USE_DEBUG)
5867       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5868       for (p = 0; p < 4; ++p) {
5869         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);
5870       }
5871 #endif
5872       supportNew[0] = cStartNew + (c - cStart)*4 + 0;
5873       supportNew[1] = cStartNew + (c - cStart)*4 + 3;
5874       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5875 #if defined(PETSC_USE_DEBUG)
5876       for (p = 0; p < 2; ++p) {
5877         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);
5878       }
5879 #endif
5880       ++newp;
5881       /* Face {h, m, l, e} */
5882       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 1;
5883       orntNew[0] = 0;
5884       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 3;
5885       orntNew[1] = -2;
5886       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],1);
5887       orntNew[2] = -2;
5888       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],1);
5889       orntNew[3] = 0;
5890       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5891       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5892 #if defined(PETSC_USE_DEBUG)
5893       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5894       for (p = 0; p < 4; ++p) {
5895         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);
5896       }
5897 #endif
5898       supportNew[0] = cStartNew + (c - cStart)*4 + 1;
5899       supportNew[1] = cStartNew + (c - cStart)*4 + 3;
5900       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5901 #if defined(PETSC_USE_DEBUG)
5902       for (p = 0; p < 2; ++p) {
5903         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);
5904       }
5905 #endif
5906       ++newp;
5907       /* Face {i, m, l, f} */
5908       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 2;
5909       orntNew[0] = 0;
5910       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 3;
5911       orntNew[1] = -2;
5912       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],2);
5913       orntNew[2] = -2;
5914       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],1);
5915       orntNew[3] = 0;
5916       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5917       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5918 #if defined(PETSC_USE_DEBUG)
5919       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5920       for (p = 0; p < 4; ++p) {
5921         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);
5922       }
5923 #endif
5924       supportNew[0] = cStartNew + (c - cStart)*4 + 2;
5925       supportNew[1] = cStartNew + (c - cStart)*4 + 3;
5926       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5927 #if defined(PETSC_USE_DEBUG)
5928       for (p = 0; p < 2; ++p) {
5929         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);
5930       }
5931 #endif
5932       ++newp;
5933     }
5934     /* Hybrid split faces have 4 edges and same cells */
5935     for (f = fMax; f < fEnd; ++f) {
5936       const PetscInt *cone, *ornt, *support;
5937       PetscInt        coneNew[4], orntNew[4];
5938       PetscInt        size, s;
5939       const PetscInt  newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (f - fMax)*2;
5940 
5941       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5942 #if defined(PETSC_USE_DEBUG)
5943       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);
5944       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);
5945       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);
5946       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);
5947 #endif
5948       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
5949       /* A face */
5950       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
5951       orntNew[0] = ornt[0];
5952       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (f - fMax);
5953       orntNew[1] = 0;
5954       coneNew[2] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
5955       orntNew[2] = ornt[1] < 0 ? 0 : -2;
5956       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (cone[2] - eMax);
5957       orntNew[3] = ornt[2] < 0 ? 0 : -2;
5958       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5959       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5960 #if defined(PETSC_USE_DEBUG)
5961       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
5962       for (p = 0; p < 4; ++p) {
5963         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);
5964       }
5965 #endif
5966 
5967       /* B face */
5968       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
5969       orntNew[0] = ornt[0];
5970       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (cone[3] - eMax);
5971       orntNew[1] = ornt[3];
5972       coneNew[2] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
5973       orntNew[2] = ornt[1] < 0 ? 0 : -2;
5974       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (f - fMax);
5975       orntNew[3] = -2;
5976       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5977       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5978 #if defined(PETSC_USE_DEBUG)
5979       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);
5980       for (p = 0; p < 4; ++p) {
5981         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);
5982       }
5983 #endif
5984 
5985       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5986       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5987       for (r = 0; r < 2; ++r) {
5988         for (s = 0; s < size; ++s) {
5989           const PetscInt *coneCell, *orntCell, *fornt;
5990           PetscInt        coneSize, o, of, c;
5991 
5992           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5993           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);
5994           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
5995           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
5996           o = orntCell[0] < 0 ? -1 : 1;
5997           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
5998           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);
5999           if (c == coneSize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %D in cone of cell %D", f, support[s]);
6000           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
6001           of = fornt[c-2] < 0 ? -1 : 1;
6002           supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*3 + (GetTriEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%3;
6003         }
6004         ierr = DMPlexSetSupport(rdm, newp + r, supportRef);CHKERRQ(ierr);
6005 #if defined(PETSC_USE_DEBUG)
6006         for (p = 0; p < size; ++p) {
6007           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);
6008         }
6009 #endif
6010       }
6011     }
6012     /* Interior hybrid faces have 4 edges and 2 cells */
6013     for (c = cMax; c < cEnd; ++c) {
6014       PetscInt        newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3;
6015       const PetscInt *cone, *ornt;
6016       PetscInt        coneNew[4], orntNew[4];
6017       PetscInt        supportNew[2];
6018 
6019       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6020 #if defined(PETSC_USE_DEBUG)
6021       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);
6022       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);
6023       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);
6024       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);
6025       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);
6026 #endif
6027       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6028       /* Face {a, g, h, d} */
6029       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],0);
6030       orntNew[0] = 0;
6031       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + c - cMax;
6032       orntNew[1] = 0;
6033       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],0);
6034       orntNew[2] = -2;
6035       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (cone[2] - fMax);
6036       orntNew[3] = -2;
6037       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6038       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6039 #if defined(PETSC_USE_DEBUG)
6040       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6041       for (p = 0; p < 4; ++p) {
6042         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);
6043       }
6044 #endif
6045       supportNew[0] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 0;
6046       supportNew[1] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 1;
6047       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6048 #if defined(PETSC_USE_DEBUG)
6049       for (p = 0; p < 2; ++p) {
6050         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);
6051       }
6052 #endif
6053       ++newp;
6054       /* Face {b, g, h, l} */
6055       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],1);
6056       orntNew[0] = 0;
6057       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + c - cMax;
6058       orntNew[1] = 0;
6059       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],1);
6060       orntNew[2] = -2;
6061       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (cone[3] - fMax);
6062       orntNew[3] = -2;
6063       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6064       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6065 #if defined(PETSC_USE_DEBUG)
6066       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6067       for (p = 0; p < 4; ++p) {
6068         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);
6069       }
6070 #endif
6071       supportNew[0] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 1;
6072       supportNew[1] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 2;
6073       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6074 #if defined(PETSC_USE_DEBUG)
6075       for (p = 0; p < 2; ++p) {
6076         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);
6077       }
6078 #endif
6079       ++newp;
6080       /* Face {c, g, h, f} */
6081       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],2);
6082       orntNew[0] = 0;
6083       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + c - cMax;
6084       orntNew[1] = 0;
6085       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],2);
6086       orntNew[2] = -2;
6087       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (cone[4] - fMax);
6088       orntNew[3] = -2;
6089       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6090       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6091 #if defined(PETSC_USE_DEBUG)
6092       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6093       for (p = 0; p < 4; ++p) {
6094         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);
6095       }
6096 #endif
6097       supportNew[0] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 2;
6098       supportNew[1] = cStartNew + (cMax - cStart)*4 + (c - cMax)*3 + 0;
6099       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6100 #if defined(PETSC_USE_DEBUG)
6101       for (p = 0; p < 2; ++p) {
6102         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);
6103       }
6104 #endif
6105     }
6106     /* Face edges have 2 vertices and 2 + cell faces supports */
6107     for (f = fStart; f < fMax; ++f) {
6108       const PetscInt *cone, *ornt, *support;
6109       PetscInt        coneSize, supportSize, s;
6110 
6111       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6112       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6113       for (r = 0; r < 3; ++r) {
6114         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
6115         PetscInt        coneNew[2];
6116         PetscInt        fint[4][3] = { {0, 1, 2},
6117                                        {3, 4, 0},
6118                                        {2, 5, 3},
6119                                        {1, 4, 5} };
6120 
6121         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6122         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);
6123         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
6124         coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + f - fStart;
6125         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6126 #if defined(PETSC_USE_DEBUG)
6127         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6128         for (p = 0; p < 2; ++p) {
6129           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);
6130         }
6131 #endif
6132         supportRef[0] = fStartNew + (f - fStart)*3 + (r+0)%3;
6133         supportRef[1] = fStartNew + (f - fStart)*3 + (r+1)%3;
6134         for (s = 0; s < supportSize; ++s) {
6135           PetscInt er;
6136 
6137           supportRef[2+s] = -1;
6138           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6139           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);
6140           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);
6141           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6142           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
6143           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
6144           er = GetTriInteriorEdgeInverse_Static(ornt[c], r);
6145           if (coneSize == 4) {
6146             supportRef[2+s] = fStartNew + (fMax - fStart)*3 + (support[s] - cStart)*6 + fint[c][er];
6147           } else if (coneSize == 5) {
6148             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);
6149             supportRef[2+s] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + er;
6150           }
6151         }
6152         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6153 #if defined(PETSC_USE_DEBUG)
6154         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6155         for (p = 0; p < supportSize + 2; ++p) {
6156           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);
6157         }
6158 #endif
6159       }
6160     }
6161     /* Interior cell edges have 2 vertices and 3 faces */
6162     for (c = cStart; c < cMax; ++c) {
6163       const PetscInt *cone;
6164       PetscInt       fint[4][3] = { {0,1,2},
6165                                     {0,3,4},
6166                                     {2,3,5},
6167                                     {1,4,5} } ;
6168 
6169       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6170       for (r = 0; r < 4; r++) {
6171         PetscInt       coneNew[2], supportNew[3];
6172         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + r;
6173 
6174         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);
6175         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
6176         coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax     -fStart) + c - cStart;
6177         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6178 #if defined(PETSC_USE_DEBUG)
6179         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6180         for (p = 0; p < 2; ++p) {
6181           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);
6182         }
6183 #endif
6184         supportNew[0] = fStartNew + (fMax - fStart)*3 + (c - cStart)*6 + fint[r][0];
6185         supportNew[1] = fStartNew + (fMax - fStart)*3 + (c - cStart)*6 + fint[r][1];
6186         supportNew[2] = fStartNew + (fMax - fStart)*3 + (c - cStart)*6 + fint[r][2];
6187         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6188 #if defined(PETSC_USE_DEBUG)
6189         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6190         for (p = 0; p < 3; ++p) {
6191           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);
6192         }
6193 #endif
6194       }
6195     }
6196     /* Hybrid edges have two vertices and the same faces */
6197     for (e = eMax; e < eEnd; ++e) {
6198       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (e - eMax);
6199       const PetscInt *cone, *support, *fcone;
6200       PetscInt        coneNew[2], size, fsize, s;
6201 
6202       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6203       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
6204       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
6205       coneNew[0] = vStartNew + (cone[0] - vStart);
6206       coneNew[1] = vStartNew + (cone[1] - vStart);
6207       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6208 #if defined(PETSC_USE_DEBUG)
6209       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is a edge [%D, %D)", newp, eStartNew, eEndNew);
6210       for (p = 0; p < 2; ++p) {
6211         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);
6212       }
6213 #endif
6214       for (s = 0; s < size; ++s) {
6215         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
6216         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
6217         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
6218         if ((c < 2) || (c > 3)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Edge %D not found in cone of face %D", e, support[s]);
6219         supportRef[s] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (support[s] - fMax)*2 + c-2;
6220       }
6221       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6222 #if defined(PETSC_USE_DEBUG)
6223       for (p = 0; p < size; ++p) {
6224         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);
6225       }
6226 #endif
6227     }
6228     /* Hybrid face edges have 2 vertices and 2 + cell faces supports */
6229     for (f = fMax; f < fEnd; ++f) {
6230       const PetscInt *cone, *ornt, *support;
6231       PetscInt        coneSize, supportSize;
6232       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + f - fMax;
6233       PetscInt        coneNew[2], s;
6234 
6235       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6236 #if defined(PETSC_USE_DEBUG)
6237       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);
6238       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);
6239 #endif
6240       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
6241       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
6242       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6243 #if defined(PETSC_USE_DEBUG)
6244       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6245       for (p = 0; p < 2; ++p) {
6246         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);
6247       }
6248 #endif
6249       supportRef[0] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (f- fMax)*2 + 0;
6250       supportRef[1] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (f- fMax)*2 + 1;
6251       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6252       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6253       for (s = 0; s < supportSize; ++s) {
6254         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6255         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);
6256         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6257         ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
6258         for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
6259         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);
6260         supportRef[2+s] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + c - 2;
6261       }
6262       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6263 #if defined(PETSC_USE_DEBUG)
6264       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6265       for (p = 0; p < supportSize + 2; ++p) {
6266         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);
6267       }
6268 #endif
6269     }
6270     /* Hybrid cell edges have 2 vertices and 3 faces */
6271     for (c = cMax; c < cEnd; ++c) {
6272       PetscInt       coneNew[2], supportNew[3];
6273       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + c - cMax;
6274       const PetscInt *cone;
6275 
6276       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6277 #if defined(PETSC_USE_DEBUG)
6278       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);
6279       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);
6280 #endif
6281       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
6282       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
6283       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6284 #if defined(PETSC_USE_DEBUG)
6285       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6286       for (p = 0; p < 2; ++p) {
6287         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);
6288       }
6289 #endif
6290       supportNew[0] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
6291       supportNew[1] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
6292       supportNew[2] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
6293       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6294 #if defined(PETSC_USE_DEBUG)
6295       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6296       for (p = 0; p < 3; ++p) {
6297         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);
6298       }
6299 #endif
6300     }
6301     /* Old vertices have identical supports */
6302     for (v = vStart; v < vEnd; ++v) {
6303       const PetscInt  newp = vStartNew + (v - vStart);
6304       const PetscInt *support, *cone;
6305       PetscInt        size, s;
6306 
6307       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6308       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6309       for (s = 0; s < size; ++s) {
6310         const PetscInt e = support[s];
6311 
6312         supportRef[s] = -1;
6313         if (eStart <= e) {
6314           if (e < eMax) {
6315             ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6316             supportRef[s] = eStartNew + (e - eStart)*2 + (cone[1] == v ? 1 : 0);
6317           } else if (e < eEnd) {
6318             supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + e - eMax;
6319           } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", e, eStart, eEnd);
6320         } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", e, eStart, eEnd);
6321       }
6322       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6323 #if defined(PETSC_USE_DEBUG)
6324       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
6325       for (p = 0; p < size; ++p) {
6326         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);
6327       }
6328 #endif
6329     }
6330     /* Interior edge vertices have 2 + faces supports */
6331     for (e = eStart; e < eMax; ++e) {
6332       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
6333       const PetscInt *cone, *support;
6334       PetscInt        size, s;
6335 
6336       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
6337       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
6338       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
6339       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
6340       for (s = 0; s < size; ++s) {
6341         PetscInt r, coneSize;
6342 
6343         supportRef[2+s] = -1;
6344         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6345         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);
6346         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);
6347         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6348         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
6349         if (coneSize == 3) supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + r;
6350         else if (coneSize == 4) {
6351           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);
6352           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + support[s] - fMax;
6353         } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for face %D (fMax %D)", coneSize, support[s], fMax);
6354       }
6355       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6356 #if defined(PETSC_USE_DEBUG)
6357       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
6358       for (p = 0; p < 2+size; ++p) {
6359         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);
6360       }
6361 #endif
6362     }
6363     /* Split Edges have 2 vertices and the same faces as the parent */
6364     for (e = eStart; e < eMax; ++e) {
6365       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
6366 
6367       for (r = 0; r < 2; ++r) {
6368         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
6369         const PetscInt *cone, *ornt, *support;
6370         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6371 
6372         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6373         coneNew[0]       = vStartNew + (cone[0] - vStart);
6374         coneNew[1]       = vStartNew + (cone[1] - vStart);
6375         coneNew[(r+1)%2] = newv;
6376         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6377 #if defined(PETSC_USE_DEBUG)
6378         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6379         for (p = 0; p < 2; ++p) {
6380           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);
6381         }
6382 #endif
6383         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
6384         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
6385         for (s = 0; s < supportSize; ++s) {
6386           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6387           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);
6388           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);
6389           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6390           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
6391           for (c = 0; c < coneSize; ++c) {
6392             if (cone[c] == e) break;
6393           }
6394           if (coneSize == 3) supportRef[s] = fStartNew + (support[s] - fStart)*3 + (c + (ornt[c] < 0 ? 1-r : r))%3;
6395           else if (coneSize == 4) {
6396             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);
6397             supportRef[s] = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
6398           } else SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected conesize %D for face %D (fMax %D)", coneSize, support[s], fMax);
6399         }
6400         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6401 #if defined(PETSC_USE_DEBUG)
6402         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6403         for (p = 0; p < supportSize; ++p) {
6404           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);
6405         }
6406 #endif
6407       }
6408     }
6409     /* Face vertices have 3 + cells supports */
6410     for (f = fStart; f < fMax; ++f) {
6411       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
6412       const PetscInt *cone, *support;
6413       PetscInt        size, s;
6414 
6415       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6416       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6417       supportRef[0] = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + 0;
6418       supportRef[1] = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + 1;
6419       supportRef[2] = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + 2;
6420       for (s = 0; s < size; ++s) {
6421         PetscInt r, coneSize;
6422 
6423         supportRef[3+s] = -1;
6424         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6425         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);
6426         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);
6427         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6428         for (r = 0; r < coneSize; ++r) {if (cone[r] == f) break;}
6429         if (coneSize == 4) supportRef[3+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (support[s] - cStart)*4 + r;
6430         else if (coneSize == 5) {
6431           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);
6432           supportRef[3+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + support[s] - cMax;
6433         }
6434       }
6435       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6436 #if defined(PETSC_USE_DEBUG)
6437       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
6438       for (p = 0; p < 3+size; ++p) {
6439         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);
6440       }
6441 #endif
6442     }
6443     /* Interior cell vertices have 4 supports */
6444     for (c = cStart; c < cMax; ++c) {
6445       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + c - cStart;
6446 
6447       supportRef[0] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 0;
6448       supportRef[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 1;
6449       supportRef[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 2;
6450       supportRef[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart)*4 + 3;
6451       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6452 #if defined(PETSC_USE_DEBUG)
6453       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
6454       for (p = 0; p < 4; ++p) {
6455         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);
6456       }
6457 #endif
6458     }
6459     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6460     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
6461     break;
6462   case REFINER_HEX_3D:
6463     /*
6464      Bottom (viewed from top)    Top
6465      1---------2---------2       7---------2---------6
6466      |         |         |       |         |         |
6467      |    B    2    C    |       |    H    2    G    |
6468      |         |         |       |         |         |
6469      3----3----0----1----1       3----3----0----1----1
6470      |         |         |       |         |         |
6471      |    A    0    D    |       |    E    0    F    |
6472      |         |         |       |         |         |
6473      0---------0---------3       4---------0---------5
6474      */
6475     /* All cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
6476     for (c = cStart; c < cEnd; ++c) {
6477       const PetscInt  newp = (c - cStart)*8;
6478       const PetscInt *cone, *ornt;
6479       PetscInt        coneNew[6], orntNew[6];
6480 
6481       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6482       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6483       /* A hex */
6484       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
6485       orntNew[0] = ornt[0];
6486       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
6487       orntNew[1] = 0;
6488       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
6489       orntNew[2] = ornt[2];
6490       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
6491       orntNew[3] = 0;
6492       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
6493       orntNew[4] = 0;
6494       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
6495       orntNew[5] = ornt[5];
6496       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6497       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6498 #if defined(PETSC_USE_DEBUG)
6499       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);
6500       for (p = 0; p < 6; ++p) {
6501         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);
6502       }
6503 #endif
6504       /* B hex */
6505       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
6506       orntNew[0] = ornt[0];
6507       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
6508       orntNew[1] = 0;
6509       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
6510       orntNew[2] = -1;
6511       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
6512       orntNew[3] = ornt[3];
6513       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
6514       orntNew[4] = 0;
6515       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
6516       orntNew[5] = ornt[5];
6517       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6518       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6519 #if defined(PETSC_USE_DEBUG)
6520       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);
6521       for (p = 0; p < 6; ++p) {
6522         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);
6523       }
6524 #endif
6525       /* C hex */
6526       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
6527       orntNew[0] = ornt[0];
6528       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
6529       orntNew[1] = 0;
6530       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
6531       orntNew[2] = -1;
6532       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
6533       orntNew[3] = ornt[3];
6534       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
6535       orntNew[4] = ornt[4];
6536       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
6537       orntNew[5] = -4;
6538       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6539       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6540 #if defined(PETSC_USE_DEBUG)
6541       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);
6542       for (p = 0; p < 6; ++p) {
6543         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);
6544       }
6545 #endif
6546       /* D hex */
6547       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
6548       orntNew[0] = ornt[0];
6549       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
6550       orntNew[1] = 0;
6551       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
6552       orntNew[2] = ornt[2];
6553       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
6554       orntNew[3] = 0;
6555       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
6556       orntNew[4] = ornt[4];
6557       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
6558       orntNew[5] = -4;
6559       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6560       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6561 #if defined(PETSC_USE_DEBUG)
6562       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);
6563       for (p = 0; p < 6; ++p) {
6564         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);
6565       }
6566 #endif
6567       /* E hex */
6568       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
6569       orntNew[0] = -4;
6570       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
6571       orntNew[1] = ornt[1];
6572       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
6573       orntNew[2] = ornt[2];
6574       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
6575       orntNew[3] = 0;
6576       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
6577       orntNew[4] = -1;
6578       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
6579       orntNew[5] = ornt[5];
6580       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
6581       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
6582 #if defined(PETSC_USE_DEBUG)
6583       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);
6584       for (p = 0; p < 6; ++p) {
6585         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);
6586       }
6587 #endif
6588       /* F hex */
6589       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
6590       orntNew[0] = -4;
6591       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
6592       orntNew[1] = ornt[1];
6593       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
6594       orntNew[2] = ornt[2];
6595       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
6596       orntNew[3] = -1;
6597       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
6598       orntNew[4] = ornt[4];
6599       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
6600       orntNew[5] = 1;
6601       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
6602       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
6603 #if defined(PETSC_USE_DEBUG)
6604       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);
6605       for (p = 0; p < 6; ++p) {
6606         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);
6607       }
6608 #endif
6609       /* G hex */
6610       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
6611       orntNew[0] = -4;
6612       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
6613       orntNew[1] = ornt[1];
6614       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
6615       orntNew[2] = 0;
6616       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
6617       orntNew[3] = ornt[3];
6618       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
6619       orntNew[4] = ornt[4];
6620       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
6621       orntNew[5] = -3;
6622       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
6623       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
6624 #if defined(PETSC_USE_DEBUG)
6625       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);
6626       for (p = 0; p < 6; ++p) {
6627         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);
6628       }
6629 #endif
6630       /* H hex */
6631       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
6632       orntNew[0] = -4;
6633       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
6634       orntNew[1] = ornt[1];
6635       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
6636       orntNew[2] = -1;
6637       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
6638       orntNew[3] = ornt[3];
6639       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
6640       orntNew[4] = 3;
6641       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
6642       orntNew[5] = ornt[5];
6643       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
6644       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
6645 #if defined(PETSC_USE_DEBUG)
6646       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);
6647       for (p = 0; p < 6; ++p) {
6648         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);
6649       }
6650 #endif
6651     }
6652     /* Split faces have 4 edges and the same cells as the parent */
6653     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6654     ierr = PetscMalloc1(4 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
6655     for (f = fStart; f < fEnd; ++f) {
6656       for (r = 0; r < 4; ++r) {
6657         /* TODO: This can come from GetFaces_Internal() */
6658         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};
6659         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
6660         const PetscInt *cone, *ornt, *support;
6661         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
6662 
6663         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6664         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
6665         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
6666         orntNew[(r+3)%4] = ornt[(r+3)%4];
6667         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
6668         orntNew[(r+0)%4] = ornt[r];
6669         coneNew[(r+1)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
6670         orntNew[(r+1)%4] = 0;
6671         coneNew[(r+2)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + (r+3)%4;
6672         orntNew[(r+2)%4] = -2;
6673         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6674         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6675 #if defined(PETSC_USE_DEBUG)
6676         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6677         for (p = 0; p < 4; ++p) {
6678           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);
6679         }
6680 #endif
6681         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6682         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6683         for (s = 0; s < supportSize; ++s) {
6684           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6685           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6686           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
6687           for (c = 0; c < coneSize; ++c) {
6688             if (cone[c] == f) break;
6689           }
6690           supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+GetQuadSubfaceInverse_Static(ornt[c], r)];
6691         }
6692         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6693 #if defined(PETSC_USE_DEBUG)
6694         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6695         for (p = 0; p < supportSize; ++p) {
6696           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);
6697         }
6698 #endif
6699       }
6700     }
6701     /* Interior faces have 4 edges and 2 cells */
6702     for (c = cStart; c < cEnd; ++c) {
6703       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};
6704       const PetscInt *cone, *ornt;
6705       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
6706 
6707       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6708       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6709       /* A-D face */
6710       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 0;
6711       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
6712       orntNew[0] = 0;
6713       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
6714       orntNew[1] = 0;
6715       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
6716       orntNew[2] = -2;
6717       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
6718       orntNew[3] = -2;
6719       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6720       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6721 #if defined(PETSC_USE_DEBUG)
6722       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6723       for (p = 0; p < 4; ++p) {
6724         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);
6725       }
6726 #endif
6727       /* C-D face */
6728       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 1;
6729       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
6730       orntNew[0] = 0;
6731       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
6732       orntNew[1] = 0;
6733       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
6734       orntNew[2] = -2;
6735       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
6736       orntNew[3] = -2;
6737       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6738       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6739 #if defined(PETSC_USE_DEBUG)
6740       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6741       for (p = 0; p < 4; ++p) {
6742         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);
6743       }
6744 #endif
6745       /* B-C face */
6746       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 2;
6747       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
6748       orntNew[0] = -2;
6749       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
6750       orntNew[1] = 0;
6751       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
6752       orntNew[2] = 0;
6753       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
6754       orntNew[3] = -2;
6755       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6756       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6757 #if defined(PETSC_USE_DEBUG)
6758       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6759       for (p = 0; p < 4; ++p) {
6760         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);
6761       }
6762 #endif
6763       /* A-B face */
6764       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 3;
6765       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
6766       orntNew[0] = -2;
6767       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
6768       orntNew[1] = 0;
6769       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
6770       orntNew[2] = 0;
6771       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
6772       orntNew[3] = -2;
6773       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6774       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6775 #if defined(PETSC_USE_DEBUG)
6776       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6777       for (p = 0; p < 4; ++p) {
6778         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);
6779       }
6780 #endif
6781       /* E-F face */
6782       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 4;
6783       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
6784       orntNew[0] = -2;
6785       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
6786       orntNew[1] = -2;
6787       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
6788       orntNew[2] = 0;
6789       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
6790       orntNew[3] = 0;
6791       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6792       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6793 #if defined(PETSC_USE_DEBUG)
6794       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6795       for (p = 0; p < 4; ++p) {
6796         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);
6797       }
6798 #endif
6799       /* F-G face */
6800       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 5;
6801       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
6802       orntNew[0] = -2;
6803       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
6804       orntNew[1] = -2;
6805       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
6806       orntNew[2] = 0;
6807       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
6808       orntNew[3] = 0;
6809       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6810       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6811 #if defined(PETSC_USE_DEBUG)
6812       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6813       for (p = 0; p < 4; ++p) {
6814         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);
6815       }
6816 #endif
6817       /* G-H face */
6818       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 6;
6819       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
6820       orntNew[0] = -2;
6821       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
6822       orntNew[1] = 0;
6823       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
6824       orntNew[2] = 0;
6825       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
6826       orntNew[3] = -2;
6827       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6828       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6829 #if defined(PETSC_USE_DEBUG)
6830       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6831       for (p = 0; p < 4; ++p) {
6832         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);
6833       }
6834 #endif
6835       /* E-H face */
6836       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 7;
6837       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
6838       orntNew[0] = -2;
6839       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
6840       orntNew[1] = -2;
6841       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
6842       orntNew[2] = 0;
6843       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
6844       orntNew[3] = 0;
6845       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6846       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6847 #if defined(PETSC_USE_DEBUG)
6848       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6849       for (p = 0; p < 4; ++p) {
6850         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);
6851       }
6852 #endif
6853       /* A-E face */
6854       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 8;
6855       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
6856       orntNew[0] = 0;
6857       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
6858       orntNew[1] = 0;
6859       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
6860       orntNew[2] = -2;
6861       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
6862       orntNew[3] = -2;
6863       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6864       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6865 #if defined(PETSC_USE_DEBUG)
6866       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6867       for (p = 0; p < 4; ++p) {
6868         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);
6869       }
6870 #endif
6871       /* D-F face */
6872       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 9;
6873       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
6874       orntNew[0] = -2;
6875       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
6876       orntNew[1] = 0;
6877       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
6878       orntNew[2] = 0;
6879       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
6880       orntNew[3] = -2;
6881       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6882       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6883 #if defined(PETSC_USE_DEBUG)
6884       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6885       for (p = 0; p < 4; ++p) {
6886         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);
6887       }
6888 #endif
6889       /* C-G face */
6890       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 10;
6891       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
6892       orntNew[0] = -2;
6893       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
6894       orntNew[1] = -2;
6895       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
6896       orntNew[2] = 0;
6897       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
6898       orntNew[3] = 0;
6899       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6900       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6901 #if defined(PETSC_USE_DEBUG)
6902       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6903       for (p = 0; p < 4; ++p) {
6904         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);
6905       }
6906 #endif
6907       /* B-H face */
6908       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 11;
6909       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
6910       orntNew[0] = 0;
6911       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
6912       orntNew[1] = -2;
6913       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
6914       orntNew[2] = -2;
6915       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
6916       orntNew[3] = 0;
6917       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6918       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6919 #if defined(PETSC_USE_DEBUG)
6920       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6921       for (p = 0; p < 4; ++p) {
6922         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);
6923       }
6924 #endif
6925       for (r = 0; r < 12; ++r) {
6926         newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
6927         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
6928         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
6929         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6930 #if defined(PETSC_USE_DEBUG)
6931         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fEndNew);
6932         for (p = 0; p < 2; ++p) {
6933           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);
6934         }
6935 #endif
6936       }
6937     }
6938     /* Split edges have 2 vertices and the same faces as the parent */
6939     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6940     for (e = eStart; e < eEnd; ++e) {
6941       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
6942 
6943       for (r = 0; r < 2; ++r) {
6944         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
6945         const PetscInt *cone, *ornt, *support;
6946         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6947 
6948         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6949         coneNew[0]       = vStartNew + (cone[0] - vStart);
6950         coneNew[1]       = vStartNew + (cone[1] - vStart);
6951         coneNew[(r+1)%2] = newv;
6952         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6953 #if defined(PETSC_USE_DEBUG)
6954         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6955         for (p = 0; p < 2; ++p) {
6956           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);
6957         }
6958 #endif
6959         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
6960         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
6961         for (s = 0; s < supportSize; ++s) {
6962           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6963           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6964           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
6965           for (c = 0; c < coneSize; ++c) {
6966             if (cone[c] == e) break;
6967           }
6968           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
6969         }
6970         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6971 #if defined(PETSC_USE_DEBUG)
6972         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6973         for (p = 0; p < supportSize; ++p) {
6974           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);
6975         }
6976 #endif
6977       }
6978     }
6979     /* Face edges have 2 vertices and 2+cells faces */
6980     for (f = fStart; f < fEnd; ++f) {
6981       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};
6982       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
6983       const PetscInt *cone, *coneCell, *orntCell, *support;
6984       PetscInt        coneNew[2], coneSize, c, supportSize, s;
6985 
6986       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6987       for (r = 0; r < 4; ++r) {
6988         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
6989 
6990         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
6991         coneNew[1] = newv;
6992         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6993 #if defined(PETSC_USE_DEBUG)
6994         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
6995         for (p = 0; p < 2; ++p) {
6996           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);
6997         }
6998 #endif
6999         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
7000         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
7001         supportRef[0] = fStartNew + (f - fStart)*4 + r;
7002         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
7003         for (s = 0; s < supportSize; ++s) {
7004           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
7005           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
7006           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
7007           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
7008           supportRef[2+s] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
7009         }
7010         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7011 #if defined(PETSC_USE_DEBUG)
7012         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
7013         for (p = 0; p < 2+supportSize; ++p) {
7014           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);
7015         }
7016 #endif
7017       }
7018     }
7019     /* Cell edges have 2 vertices and 4 faces */
7020     for (c = cStart; c < cEnd; ++c) {
7021       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};
7022       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
7023       const PetscInt *cone;
7024       PetscInt        coneNew[2], supportNew[4];
7025 
7026       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7027       for (r = 0; r < 6; ++r) {
7028         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
7029 
7030         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
7031         coneNew[1] = newv;
7032         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7033 #if defined(PETSC_USE_DEBUG)
7034         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
7035         for (p = 0; p < 2; ++p) {
7036           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);
7037         }
7038 #endif
7039         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
7040         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
7041 #if defined(PETSC_USE_DEBUG)
7042         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eEndNew);
7043         for (p = 0; p < 4; ++p) {
7044           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);
7045         }
7046 #endif
7047       }
7048     }
7049     /* Old vertices have identical supports */
7050     for (v = vStart; v < vEnd; ++v) {
7051       const PetscInt  newp = vStartNew + (v - vStart);
7052       const PetscInt *support, *cone;
7053       PetscInt        size, s;
7054 
7055       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
7056       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
7057       for (s = 0; s < size; ++s) {
7058         PetscInt r = 0;
7059 
7060         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7061         if (cone[1] == v) r = 1;
7062         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
7063       }
7064       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7065 #if defined(PETSC_USE_DEBUG)
7066       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
7067       for (p = 0; p < size; ++p) {
7068         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);
7069       }
7070 #endif
7071     }
7072     /* Edge vertices have 2 + faces supports */
7073     for (e = eStart; e < eEnd; ++e) {
7074       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
7075       const PetscInt *cone, *support;
7076       PetscInt        size, s;
7077 
7078       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
7079       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
7080       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
7081       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
7082       for (s = 0; s < size; ++s) {
7083         PetscInt r;
7084 
7085         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7086         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
7087         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*4 + r;
7088       }
7089       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7090 #if defined(PETSC_USE_DEBUG)
7091       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
7092       for (p = 0; p < 2+size; ++p) {
7093         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);
7094       }
7095 #endif
7096     }
7097     /* Face vertices have 4 + cells supports */
7098     for (f = fStart; f < fEnd; ++f) {
7099       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
7100       const PetscInt *cone, *support;
7101       PetscInt        size, s;
7102 
7103       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
7104       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
7105       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eEnd - eStart)*2 +  (f - fStart)*4 + r;
7106       for (s = 0; s < size; ++s) {
7107         PetscInt r;
7108 
7109         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7110         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
7111         supportRef[4+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (support[s] - cStart)*6 + r;
7112       }
7113       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7114 #if defined(PETSC_USE_DEBUG)
7115       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
7116       for (p = 0; p < 4+size; ++p) {
7117         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);
7118       }
7119 #endif
7120     }
7121     /* Cell vertices have 6 supports */
7122     for (c = cStart; c < cEnd; ++c) {
7123       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
7124       PetscInt       supportNew[6];
7125 
7126       for (r = 0; r < 6; ++r) {
7127         supportNew[r] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
7128       }
7129       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
7130     }
7131     ierr = PetscFree(supportRef);CHKERRQ(ierr);
7132     break;
7133   case REFINER_HYBRID_HEX_3D:
7134     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
7135     /*
7136      Bottom (viewed from top)    Top
7137      1---------2---------2       7---------2---------6
7138      |         |         |       |         |         |
7139      |    B    2    C    |       |    H    2    G    |
7140      |         |         |       |         |         |
7141      3----3----0----1----1       3----3----0----1----1
7142      |         |         |       |         |         |
7143      |    A    0    D    |       |    E    0    F    |
7144      |         |         |       |         |         |
7145      0---------0---------3       4---------0---------5
7146      */
7147     /* Interior cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
7148     for (c = cStart; c < cMax; ++c) {
7149       const PetscInt  newp = (c - cStart)*8;
7150       const PetscInt *cone, *ornt;
7151       PetscInt        coneNew[6], orntNew[6];
7152 
7153       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7154       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
7155       /* A hex */
7156       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
7157       orntNew[0] = ornt[0];
7158       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
7159       orntNew[1] = 0;
7160       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
7161       orntNew[2] = ornt[2];
7162       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
7163       orntNew[3] = 0;
7164       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
7165       orntNew[4] = 0;
7166       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
7167       orntNew[5] = ornt[5];
7168       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
7169       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
7170 #if defined(PETSC_USE_DEBUG)
7171       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);
7172       for (p = 0; p < 6; ++p) {
7173         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);
7174       }
7175 #endif
7176       /* B hex */
7177       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
7178       orntNew[0] = ornt[0];
7179       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
7180       orntNew[1] = 0;
7181       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
7182       orntNew[2] = -1;
7183       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
7184       orntNew[3] = ornt[3];
7185       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
7186       orntNew[4] = 0;
7187       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
7188       orntNew[5] = ornt[5];
7189       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
7190       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
7191 #if defined(PETSC_USE_DEBUG)
7192       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);
7193       for (p = 0; p < 6; ++p) {
7194         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);
7195       }
7196 #endif
7197       /* C hex */
7198       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
7199       orntNew[0] = ornt[0];
7200       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
7201       orntNew[1] = 0;
7202       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
7203       orntNew[2] = -1;
7204       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
7205       orntNew[3] = ornt[3];
7206       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
7207       orntNew[4] = ornt[4];
7208       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
7209       orntNew[5] = -4;
7210       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
7211       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
7212 #if defined(PETSC_USE_DEBUG)
7213       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);
7214       for (p = 0; p < 6; ++p) {
7215         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);
7216       }
7217 #endif
7218       /* D hex */
7219       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
7220       orntNew[0] = ornt[0];
7221       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
7222       orntNew[1] = 0;
7223       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
7224       orntNew[2] = ornt[2];
7225       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
7226       orntNew[3] = 0;
7227       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
7228       orntNew[4] = ornt[4];
7229       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
7230       orntNew[5] = -4;
7231       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
7232       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
7233 #if defined(PETSC_USE_DEBUG)
7234       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);
7235       for (p = 0; p < 6; ++p) {
7236         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);
7237       }
7238 #endif
7239       /* E hex */
7240       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
7241       orntNew[0] = -4;
7242       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
7243       orntNew[1] = ornt[1];
7244       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
7245       orntNew[2] = ornt[2];
7246       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
7247       orntNew[3] = 0;
7248       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
7249       orntNew[4] = -1;
7250       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
7251       orntNew[5] = ornt[5];
7252       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
7253       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
7254 #if defined(PETSC_USE_DEBUG)
7255       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);
7256       for (p = 0; p < 6; ++p) {
7257         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);
7258       }
7259 #endif
7260       /* F hex */
7261       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
7262       orntNew[0] = -4;
7263       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
7264       orntNew[1] = ornt[1];
7265       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
7266       orntNew[2] = ornt[2];
7267       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
7268       orntNew[3] = -1;
7269       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
7270       orntNew[4] = ornt[4];
7271       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
7272       orntNew[5] = 1;
7273       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
7274       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
7275 #if defined(PETSC_USE_DEBUG)
7276       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);
7277       for (p = 0; p < 6; ++p) {
7278         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);
7279       }
7280 #endif
7281       /* G hex */
7282       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
7283       orntNew[0] = -4;
7284       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
7285       orntNew[1] = ornt[1];
7286       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
7287       orntNew[2] = 0;
7288       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
7289       orntNew[3] = ornt[3];
7290       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
7291       orntNew[4] = ornt[4];
7292       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
7293       orntNew[5] = -3;
7294       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
7295       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
7296 #if defined(PETSC_USE_DEBUG)
7297       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);
7298       for (p = 0; p < 6; ++p) {
7299         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);
7300       }
7301 #endif
7302       /* H hex */
7303       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
7304       orntNew[0] = -4;
7305       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
7306       orntNew[1] = ornt[1];
7307       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
7308       orntNew[2] = -1;
7309       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
7310       orntNew[3] = ornt[3];
7311       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
7312       orntNew[4] = 3;
7313       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
7314       orntNew[5] = ornt[5];
7315       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
7316       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
7317 #if defined(PETSC_USE_DEBUG)
7318       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);
7319       for (p = 0; p < 6; ++p) {
7320         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);
7321       }
7322 #endif
7323     }
7324     /* Hybrid cells have 6 faces: Front, Back, Sides */
7325     /*
7326      3---------2---------2
7327      |         |         |
7328      |    D    2    C    |
7329      |         |         |
7330      3----3----0----1----1
7331      |         |         |
7332      |    A    0    B    |
7333      |         |         |
7334      0---------0---------1
7335      */
7336     for (c = cMax; c < cEnd; ++c) {
7337       const PetscInt  newp = (cMax - cStart)*8 + (c - cMax)*4;
7338       const PetscInt *cone, *ornt, *fornt;
7339       PetscInt        coneNew[6], orntNew[6], o, of, i;
7340 
7341       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7342       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
7343       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
7344       o = ornt[0] < 0 ? -1 : 1;
7345       for (r = 0; r < 4; ++r) {
7346         PetscInt subfA = GetQuadSubface_Static(ornt[0], r);
7347         PetscInt edgeA = GetQuadEdge_Static(ornt[0], r);
7348         PetscInt edgeB = GetQuadEdge_Static(ornt[0], (r+3)%4);
7349         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]);
7350         coneNew[0]         = fStartNew + (cone[0] - fStart)*4 + subfA;
7351         orntNew[0]         = ornt[0];
7352         coneNew[1]         = fStartNew + (cone[1] - fStart)*4 + subfA;
7353         orntNew[1]         = ornt[0];
7354         of = fornt[edgeA] < 0 ? -1 : 1;
7355         i  = GetQuadEdgeInverse_Static(ornt[0], r) + 2;
7356         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeA] - fMax)*2 + (o*of < 0 ? 1 : 0);
7357         orntNew[i] = ornt[edgeA];
7358         i  = GetQuadEdgeInverse_Static(ornt[0], (r+1)%4) + 2;
7359         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeA;
7360         orntNew[i] = 0;
7361         i  = GetQuadEdgeInverse_Static(ornt[0], (r+2)%4) + 2;
7362         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeB;
7363         orntNew[i] = -2;
7364         of = fornt[edgeB] < 0 ? -1 : 1;
7365         i  = GetQuadEdgeInverse_Static(ornt[0], (r+3)%4) + 2;
7366         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeB] - fMax)*2 + (o*of < 0 ? 0 : 1);
7367         orntNew[i] = ornt[edgeB];
7368         ierr       = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
7369         ierr       = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
7370 #if defined(PETSC_USE_DEBUG)
7371         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);
7372         for (p = 0; p < 2; ++p) {
7373           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);
7374         }
7375         for (p = 2; p < 6; ++p) {
7376           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);
7377         }
7378 #endif
7379       }
7380     }
7381     /* Interior split faces have 4 edges and the same cells as the parent */
7382     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
7383     ierr = PetscMalloc1(4 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
7384     for (f = fStart; f < fMax; ++f) {
7385       for (r = 0; r < 4; ++r) {
7386         /* TODO: This can come from GetFaces_Internal() */
7387         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};
7388         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
7389         const PetscInt *cone, *ornt, *support;
7390         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
7391 
7392         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
7393         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
7394         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
7395         orntNew[(r+3)%4] = ornt[(r+3)%4];
7396         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
7397         orntNew[(r+0)%4] = ornt[r];
7398         coneNew[(r+1)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
7399         orntNew[(r+1)%4] = 0;
7400         coneNew[(r+2)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + (r+3)%4;
7401         orntNew[(r+2)%4] = -2;
7402         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7403         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7404 #if defined(PETSC_USE_DEBUG)
7405         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7406         for (p = 0; p < 4; ++p) {
7407           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);
7408         }
7409 #endif
7410         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
7411         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
7412         for (s = 0; s < supportSize; ++s) {
7413           PetscInt subf;
7414           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
7415           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7416           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
7417           for (c = 0; c < coneSize; ++c) {
7418             if (cone[c] == f) break;
7419           }
7420           subf = GetQuadSubfaceInverse_Static(ornt[c], r);
7421           if (support[s] < cMax) {
7422             supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+subf];
7423           } else {
7424             supportRef[s] = cStartNew + (cMax       - cStart)*8 + (support[s] - cMax)*4 + subf;
7425           }
7426         }
7427         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7428 #if defined(PETSC_USE_DEBUG)
7429         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7430         for (p = 0; p < supportSize; ++p) {
7431           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);
7432         }
7433 #endif
7434       }
7435     }
7436     /* Interior cell faces have 4 edges and 2 cells */
7437     for (c = cStart; c < cMax; ++c) {
7438       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};
7439       const PetscInt *cone, *ornt;
7440       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
7441 
7442       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7443       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
7444       /* A-D face */
7445       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 0;
7446       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
7447       orntNew[0] = 0;
7448       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
7449       orntNew[1] = 0;
7450       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
7451       orntNew[2] = -2;
7452       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
7453       orntNew[3] = -2;
7454       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7455       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7456 #if defined(PETSC_USE_DEBUG)
7457       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7458       for (p = 0; p < 4; ++p) {
7459         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);
7460       }
7461 #endif
7462       /* C-D face */
7463       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 1;
7464       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
7465       orntNew[0] = 0;
7466       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
7467       orntNew[1] = 0;
7468       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
7469       orntNew[2] = -2;
7470       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
7471       orntNew[3] = -2;
7472       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7473       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7474 #if defined(PETSC_USE_DEBUG)
7475       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7476       for (p = 0; p < 4; ++p) {
7477         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);
7478       }
7479 #endif
7480       /* B-C face */
7481       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 2;
7482       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
7483       orntNew[0] = -2;
7484       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
7485       orntNew[1] = 0;
7486       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
7487       orntNew[2] = 0;
7488       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
7489       orntNew[3] = -2;
7490       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7491       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7492 #if defined(PETSC_USE_DEBUG)
7493       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7494       for (p = 0; p < 4; ++p) {
7495         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);
7496       }
7497 #endif
7498       /* A-B face */
7499       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 3;
7500       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
7501       orntNew[0] = -2;
7502       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
7503       orntNew[1] = 0;
7504       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
7505       orntNew[2] = 0;
7506       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
7507       orntNew[3] = -2;
7508       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7509       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7510 #if defined(PETSC_USE_DEBUG)
7511       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7512       for (p = 0; p < 4; ++p) {
7513         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);
7514       }
7515 #endif
7516       /* E-F face */
7517       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 4;
7518       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
7519       orntNew[0] = -2;
7520       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
7521       orntNew[1] = -2;
7522       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
7523       orntNew[2] = 0;
7524       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
7525       orntNew[3] = 0;
7526       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7527       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7528 #if defined(PETSC_USE_DEBUG)
7529       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7530       for (p = 0; p < 4; ++p) {
7531         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);
7532       }
7533 #endif
7534       /* F-G face */
7535       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 5;
7536       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
7537       orntNew[0] = -2;
7538       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
7539       orntNew[1] = -2;
7540       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
7541       orntNew[2] = 0;
7542       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
7543       orntNew[3] = 0;
7544       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7545       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7546 #if defined(PETSC_USE_DEBUG)
7547       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7548       for (p = 0; p < 4; ++p) {
7549         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);
7550       }
7551 #endif
7552       /* G-H face */
7553       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 6;
7554       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
7555       orntNew[0] = -2;
7556       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
7557       orntNew[1] = 0;
7558       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
7559       orntNew[2] = 0;
7560       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
7561       orntNew[3] = -2;
7562       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7563       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7564 #if defined(PETSC_USE_DEBUG)
7565       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7566       for (p = 0; p < 4; ++p) {
7567         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);
7568       }
7569 #endif
7570       /* E-H face */
7571       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 7;
7572       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
7573       orntNew[0] = -2;
7574       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
7575       orntNew[1] = -2;
7576       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
7577       orntNew[2] = 0;
7578       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
7579       orntNew[3] = 0;
7580       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7581       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7582 #if defined(PETSC_USE_DEBUG)
7583       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7584       for (p = 0; p < 4; ++p) {
7585         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);
7586       }
7587 #endif
7588       /* A-E face */
7589       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 8;
7590       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
7591       orntNew[0] = 0;
7592       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
7593       orntNew[1] = 0;
7594       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
7595       orntNew[2] = -2;
7596       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
7597       orntNew[3] = -2;
7598       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7599       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7600 #if defined(PETSC_USE_DEBUG)
7601       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7602       for (p = 0; p < 4; ++p) {
7603         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);
7604       }
7605 #endif
7606       /* D-F face */
7607       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 9;
7608       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
7609       orntNew[0] = -2;
7610       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
7611       orntNew[1] = 0;
7612       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
7613       orntNew[2] = 0;
7614       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
7615       orntNew[3] = -2;
7616       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7617       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7618 #if defined(PETSC_USE_DEBUG)
7619       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7620       for (p = 0; p < 4; ++p) {
7621         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);
7622       }
7623 #endif
7624       /* C-G face */
7625       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 10;
7626       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
7627       orntNew[0] = -2;
7628       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
7629       orntNew[1] = -2;
7630       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
7631       orntNew[2] = 0;
7632       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
7633       orntNew[3] = 0;
7634       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7635       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7636 #if defined(PETSC_USE_DEBUG)
7637       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7638       for (p = 0; p < 4; ++p) {
7639         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);
7640       }
7641 #endif
7642       /* B-H face */
7643       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 11;
7644       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
7645       orntNew[0] = 0;
7646       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
7647       orntNew[1] = -2;
7648       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
7649       orntNew[2] = -2;
7650       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
7651       orntNew[3] = 0;
7652       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7653       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7654 #if defined(PETSC_USE_DEBUG)
7655       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7656       for (p = 0; p < 4; ++p) {
7657         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);
7658       }
7659 #endif
7660       for (r = 0; r < 12; ++r) {
7661         newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
7662         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
7663         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
7664         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
7665 #if defined(PETSC_USE_DEBUG)
7666         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a face [%D, %D)", newp, fStartNew, fMaxNew);
7667         for (p = 0; p < 2; ++p) {
7668           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);
7669         }
7670 #endif
7671       }
7672     }
7673     /* Hybrid split faces have 4 edges and same cells */
7674     for (f = fMax; f < fEnd; ++f) {
7675       const PetscInt *cone, *ornt, *support;
7676       PetscInt        coneNew[4], orntNew[4];
7677       PetscInt        supportNew[2], size, s, c;
7678 
7679       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
7680       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
7681       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
7682       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
7683       for (r = 0; r < 2; ++r) {
7684         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
7685 
7686         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
7687         orntNew[0]   = ornt[0];
7688         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
7689         orntNew[1]   = ornt[1];
7690         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (cone[2+r] - eMax);
7691         orntNew[2+r] = 0;
7692         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd      - eMax) + (f - fMax);
7693         orntNew[3-r] = 0;
7694         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7695         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
7696 #if defined(PETSC_USE_DEBUG)
7697         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp, fMaxNew, fEndNew);
7698         for (p = 0; p < 2; ++p) {
7699           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);
7700         }
7701         for (p = 2; p < 4; ++p) {
7702           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);
7703         }
7704 #endif
7705         for (s = 0; s < size; ++s) {
7706           const PetscInt *coneCell, *orntCell, *fornt;
7707           PetscInt        o, of;
7708 
7709           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
7710           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
7711           o = orntCell[0] < 0 ? -1 : 1;
7712           for (c = 2; c < 6; ++c) if (coneCell[c] == f) break;
7713           if (c >= 6) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %D in cone of cell %D", f, support[s]);
7714           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
7715           of = fornt[c-2] < 0 ? -1 : 1;
7716           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetQuadEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%4;
7717         }
7718         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
7719 #if defined(PETSC_USE_DEBUG)
7720         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid face [%D, %D)", newp, fMaxNew, fEndNew);
7721         for (p = 0; p < size; ++p) {
7722           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);
7723         }
7724 #endif
7725       }
7726     }
7727     /* Hybrid cell faces have 4 edges and 2 cells */
7728     for (c = cMax; c < cEnd; ++c) {
7729       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4;
7730       const PetscInt *cone, *ornt;
7731       PetscInt        coneNew[4], orntNew[4];
7732       PetscInt        supportNew[2];
7733 
7734       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7735       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
7736       for (r = 0; r < 4; ++r) {
7737 #if 0
7738         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], r);
7739         orntNew[0] = 0;
7740         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], r);
7741         orntNew[1] = 0;
7742         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+GetQuadEdge_Static(ornt[0], r)] - fMax);
7743         orntNew[2] = 0;
7744         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd                                   - fMax) + (c - cMax);
7745         orntNew[3] = 0;
7746 #else
7747         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + r;
7748         orntNew[0] = 0;
7749         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + r;
7750         orntNew[1] = 0;
7751         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+r] - fMax);
7752         orntNew[2] = 0;
7753         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd      - fMax) + (c - cMax);
7754         orntNew[3] = 0;
7755 #endif
7756         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
7757         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
7758 #if defined(PETSC_USE_DEBUG)
7759         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);
7760         for (p = 0; p < 2; ++p) {
7761           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);
7762         }
7763         for (p = 2; p < 4; ++p) {
7764           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);
7765         }
7766 #endif
7767         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], r);
7768         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], (r+1)%4);
7769         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
7770 #if defined(PETSC_USE_DEBUG)
7771         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);
7772         for (p = 0; p < 2; ++p) {
7773           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);
7774         }
7775 #endif
7776       }
7777     }
7778     /* Interior split edges have 2 vertices and the same faces as the parent */
7779     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
7780     for (e = eStart; e < eMax; ++e) {
7781       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
7782 
7783       for (r = 0; r < 2; ++r) {
7784         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
7785         const PetscInt *cone, *ornt, *support;
7786         PetscInt        coneNew[2], coneSize, c, supportSize, s;
7787 
7788         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
7789         coneNew[0]       = vStartNew + (cone[0] - vStart);
7790         coneNew[1]       = vStartNew + (cone[1] - vStart);
7791         coneNew[(r+1)%2] = newv;
7792         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7793 #if defined(PETSC_USE_DEBUG)
7794         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
7795         for (p = 0; p < 2; ++p) {
7796           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);
7797         }
7798 #endif
7799         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
7800         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
7801         for (s = 0; s < supportSize; ++s) {
7802           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
7803           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
7804           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
7805           for (c = 0; c < coneSize; ++c) {
7806             if (cone[c] == e) break;
7807           }
7808           if (support[s] < fMax) {
7809             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%4;
7810           } else {
7811             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
7812           }
7813         }
7814         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7815 #if defined(PETSC_USE_DEBUG)
7816         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
7817         for (p = 0; p < supportSize; ++p) {
7818           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);
7819         }
7820 #endif
7821       }
7822     }
7823     /* Interior face edges have 2 vertices and 2+cells faces */
7824     for (f = fStart; f < fMax; ++f) {
7825       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};
7826       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
7827       const PetscInt *cone, *coneCell, *orntCell, *support;
7828       PetscInt        coneNew[2], coneSize, c, supportSize, s;
7829 
7830       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
7831       for (r = 0; r < 4; ++r) {
7832         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
7833 
7834         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
7835         coneNew[1] = newv;
7836         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7837 #if defined(PETSC_USE_DEBUG)
7838         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
7839         for (p = 0; p < 2; ++p) {
7840           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);
7841         }
7842 #endif
7843         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
7844         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
7845         supportRef[0] = fStartNew + (f - fStart)*4 + r;
7846         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
7847         for (s = 0; s < supportSize; ++s) {
7848           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
7849           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
7850           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
7851           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
7852           if (support[s] < cMax) {
7853             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
7854           } else {
7855             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + r;
7856           }
7857         }
7858         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7859 #if defined(PETSC_USE_DEBUG)
7860         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
7861         for (p = 0; p < 2+supportSize; ++p) {
7862           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);
7863         }
7864 #endif
7865       }
7866     }
7867     /* Interior cell edges have 2 vertices and 4 faces */
7868     for (c = cStart; c < cMax; ++c) {
7869       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};
7870       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
7871       const PetscInt *cone;
7872       PetscInt        coneNew[2], supportNew[4];
7873 
7874       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7875       for (r = 0; r < 6; ++r) {
7876         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
7877 
7878         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
7879         coneNew[1] = newv;
7880         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7881 #if defined(PETSC_USE_DEBUG)
7882         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
7883         for (p = 0; p < 2; ++p) {
7884           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);
7885         }
7886 #endif
7887         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
7888         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
7889 #if defined(PETSC_USE_DEBUG)
7890         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not an edge [%D, %D)", newp, eStartNew, eMaxNew);
7891         for (p = 0; p < 4; ++p) {
7892           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);
7893         }
7894 #endif
7895       }
7896     }
7897     /* Hybrid edges have two vertices and the same faces */
7898     for (e = eMax; e < eEnd; ++e) {
7899       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
7900       const PetscInt *cone, *support, *fcone;
7901       PetscInt        coneNew[2], size, fsize, s;
7902 
7903       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
7904       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
7905       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
7906       coneNew[0] = vStartNew + (cone[0] - vStart);
7907       coneNew[1] = vStartNew + (cone[1] - vStart);
7908       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7909 #if defined(PETSC_USE_DEBUG)
7910       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
7911       for (p = 0; p < 2; ++p) {
7912         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);
7913       }
7914 #endif
7915       for (s = 0; s < size; ++s) {
7916         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
7917         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
7918         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
7919         if ((c < 2) || (c > 3)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Edge %D not found in cone of face %D", e, support[s]);
7920         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + c-2;
7921       }
7922       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7923 #if defined(PETSC_USE_DEBUG)
7924       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
7925       for (p = 0; p < size; ++p) {
7926         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);
7927       }
7928 #endif
7929     }
7930     /* Hybrid face edges have 2 vertices and 2+cells faces */
7931     for (f = fMax; f < fEnd; ++f) {
7932       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
7933       const PetscInt *cone, *support, *ccone, *cornt;
7934       PetscInt        coneNew[2], size, csize, s;
7935 
7936       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
7937       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
7938       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
7939       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
7940       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
7941       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7942 #if defined(PETSC_USE_DEBUG)
7943       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
7944       for (p = 0; p < 2; ++p) {
7945         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);
7946       }
7947 #endif
7948       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 0;
7949       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 1;
7950       for (s = 0; s < size; ++s) {
7951         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
7952         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
7953         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
7954         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
7955         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]);
7956         supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + c-2;
7957       }
7958       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7959 #if defined(PETSC_USE_DEBUG)
7960       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
7961       for (p = 0; p < 2+size; ++p) {
7962         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);
7963       }
7964 #endif
7965     }
7966     /* Hybrid cell edges have 2 vertices and 4 faces */
7967     for (c = cMax; c < cEnd; ++c) {
7968       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
7969       const PetscInt *cone, *support;
7970       PetscInt        coneNew[2], size;
7971 
7972       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
7973       ierr = DMPlexGetSupportSize(dm, c, &size);CHKERRQ(ierr);
7974       ierr = DMPlexGetSupport(dm, c, &support);CHKERRQ(ierr);
7975       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
7976       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
7977       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
7978 #if defined(PETSC_USE_DEBUG)
7979       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
7980       for (p = 0; p < 2; ++p) {
7981         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);
7982       }
7983 #endif
7984       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 0;
7985       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 1;
7986       supportRef[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 2;
7987       supportRef[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 3;
7988       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
7989 #if defined(PETSC_USE_DEBUG)
7990       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a hybrid edge [%D, %D)", newp, eMaxNew, eEndNew);
7991       for (p = 0; p < 4; ++p) {
7992         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);
7993       }
7994 #endif
7995     }
7996     /* Interior vertices have identical supports */
7997     for (v = vStart; v < vEnd; ++v) {
7998       const PetscInt  newp = vStartNew + (v - vStart);
7999       const PetscInt *support, *cone;
8000       PetscInt        size, s;
8001 
8002       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
8003       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
8004       for (s = 0; s < size; ++s) {
8005         PetscInt r = 0;
8006 
8007         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
8008         if (cone[1] == v) r = 1;
8009         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
8010         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (support[s] - eMax);
8011       }
8012       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
8013 #if defined(PETSC_USE_DEBUG)
8014       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
8015       for (p = 0; p < size; ++p) {
8016         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);
8017       }
8018 #endif
8019     }
8020     /* Interior edge vertices have 2 + faces supports */
8021     for (e = eStart; e < eMax; ++e) {
8022       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
8023       const PetscInt *cone, *support;
8024       PetscInt        size, s;
8025 
8026       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
8027       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
8028       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
8029       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
8030       for (s = 0; s < size; ++s) {
8031         PetscInt r;
8032 
8033         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
8034         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
8035         if (support[s] < fMax) {
8036           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*4 + r;
8037         } else {
8038           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (support[s] - fMax);
8039         }
8040       }
8041       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
8042 #if defined(PETSC_USE_DEBUG)
8043       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
8044       for (p = 0; p < 2+size; ++p) {
8045         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);
8046       }
8047 #endif
8048     }
8049     /* Interior face vertices have 4 + cells supports */
8050     for (f = fStart; f < fMax; ++f) {
8051       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
8052       const PetscInt *cone, *support;
8053       PetscInt        size, s;
8054 
8055       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
8056       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
8057       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eMax - eStart)*2 +  (f - fStart)*4 + r;
8058       for (s = 0; s < size; ++s) {
8059         PetscInt r;
8060 
8061         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
8062         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
8063         if (support[s] < cMax) {
8064           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (support[s] - cStart)*6 + r;
8065         } else {
8066           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax       - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (support[s] - cMax);
8067         }
8068       }
8069       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
8070 #if defined(PETSC_USE_DEBUG)
8071       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Point %D is not a vertex [%D, %D)", newp, vStartNew, vEndNew);
8072       for (p = 0; p < 4+size; ++p) {
8073         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);
8074       }
8075 #endif
8076     }
8077     /* Cell vertices have 6 supports */
8078     for (c = cStart; c < cMax; ++c) {
8079       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
8080       PetscInt       supportNew[6];
8081 
8082       for (r = 0; r < 6; ++r) {
8083         supportNew[r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
8084       }
8085       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
8086     }
8087     ierr = PetscFree(supportRef);CHKERRQ(ierr);
8088     break;
8089   default:
8090     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %D", refiner);
8091   }
8092   PetscFunctionReturn(0);
8093 }
8094 
8095 static PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
8096 {
8097   PetscSection          coordSection, coordSectionNew;
8098   Vec                   coordinates, coordinatesNew;
8099   PetscScalar          *coords, *coordsNew;
8100   const PetscInt        numVertices = depthSize ? depthSize[0] : 0;
8101   PetscInt              dim, spaceDim, depth, bs, coordSizeNew, cStart, cEnd, cMax;
8102   PetscInt              c, vStart, vStartNew, vEnd, v, eStart, eEnd, eMax, e, fStart, fEnd, fMax, f;
8103   PetscInt              cStartNew, cEndNew, vEndNew, *parentId = NULL;
8104   VecType               vtype;
8105   PetscBool             isperiodic, localize = PETSC_FALSE, needcoords = PETSC_FALSE;
8106   const PetscReal      *maxCell, *L;
8107   const DMBoundaryType *bd;
8108   PetscErrorCode        ierr;
8109 
8110   PetscFunctionBegin;
8111   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
8112   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
8113   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8114   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
8115   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8116   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
8117   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, NULL);CHKERRQ(ierr);
8118   if (cMax < 0) cMax = cEnd;
8119   if (fMax < 0) fMax = fEnd;
8120   if (eMax < 0) eMax = eEnd;
8121   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, NULL, NULL, &vStartNew);CHKERRQ(ierr);
8122   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, NULL, NULL, &vEndNew);CHKERRQ(ierr);
8123   ierr = DMGetPeriodicity(dm, &isperiodic, &maxCell, &L, &bd);CHKERRQ(ierr);
8124   /* Determine if we need to localize coordinates when generating them */
8125   if (isperiodic && !maxCell) {
8126     ierr = DMGetCoordinatesLocalized(dm, &localize);CHKERRQ(ierr);
8127     if (!localize) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Cannot refine if coordinates have not been localized");
8128   }
8129   if (isperiodic) {
8130     ierr = PetscOptionsBegin(PetscObjectComm((PetscObject)dm),((PetscObject)dm)->prefix,"DMPlex coords refinement options","DM");CHKERRQ(ierr);
8131     ierr = PetscOptionsBool("-dm_plex_refine_localize","Automatically localize from parent cells",NULL,localize,&localize,NULL);CHKERRQ(ierr);
8132     ierr = PetscOptionsEnd();CHKERRQ(ierr);
8133     if (localize) {
8134       ierr = DMLocalizeCoordinates(dm);CHKERRQ(ierr);
8135     }
8136   }
8137   ierr = DMSetPeriodicity(rdm, isperiodic,  maxCell,  L,  bd);CHKERRQ(ierr);
8138 
8139   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8140   ierr = PetscSectionGetFieldComponents(coordSection, 0, &spaceDim);CHKERRQ(ierr);
8141   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
8142   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
8143   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, spaceDim);CHKERRQ(ierr);
8144 
8145   if (localize) {
8146     PetscInt p, r, newp, *pi;
8147 
8148     /* New coordinates will be already localized on the cell */
8149     ierr = PetscSectionSetChart(coordSectionNew, 0, vStartNew+numVertices);CHKERRQ(ierr);
8150 
8151     /* We need the parentId to properly localize coordinates */
8152     ierr = PetscMalloc1(cEndNew-cStartNew,&pi);CHKERRQ(ierr);
8153     switch (refiner) {
8154     case REFINER_NOOP:
8155       break;
8156     case REFINER_SIMPLEX_1D:
8157       for (p = cStart; p < cEnd; ++p) {
8158         for (r = 0; r < 2; ++r) {
8159           newp     = (p - cStart)*2 + r;
8160           pi[newp] = p;
8161         }
8162       }
8163       break;
8164     case REFINER_SIMPLEX_2D:
8165       for (p = cStart; p < cEnd; ++p) {
8166         for (r = 0; r < 4; ++r) {
8167           newp     = (p - cStart)*4 + r;
8168           pi[newp] = p;
8169         }
8170       }
8171       break;
8172     case REFINER_HEX_2D:
8173       for (p = cStart; p < cEnd; ++p) {
8174         for (r = 0; r < 4; ++r) {
8175           newp     = (p - cStart)*4 + r;
8176           pi[newp] = p;
8177         }
8178       }
8179       break;
8180     case REFINER_SIMPLEX_TO_HEX_2D:
8181       for (p = cStart; p < cEnd; ++p) {
8182         for (r = 0; r < 3; ++r) {
8183           newp     = (p - cStart)*3 + r;
8184           pi[newp] = p;
8185         }
8186       }
8187       break;
8188     case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
8189       for (p = cStart; p < cMax; ++p) {
8190         for (r = 0; r < 3; ++r) {
8191           newp     = (p - cStart)*3 + r;
8192           pi[newp] = p;
8193         }
8194       }
8195       for (p = cMax; p < cEnd; ++p) {
8196         for (r = 0; r < 4; ++r) {
8197           newp     = (cMax - cStart)*3 + (p - cMax)*4 + r;
8198           pi[newp] = p;
8199         }
8200       }
8201       /* The refiner needs midpoint vertices on hybrid edges and hybrid cells */
8202       cMax = cEnd;
8203       eMax = eEnd;
8204       break;
8205     case REFINER_HYBRID_SIMPLEX_2D:
8206       for (p = cStart; p < cMax; ++p) {
8207         for (r = 0; r < 4; ++r) {
8208           newp     = (p - cStart)*4 + r;
8209           pi[newp] = p;
8210         }
8211       }
8212       for (p = cMax; p < cEnd; ++p) {
8213         for (r = 0; r < 2; ++r) {
8214           newp     = (cMax - cStart)*4 + (p - cMax)*2 + r;
8215           pi[newp] = p;
8216         }
8217       }
8218       break;
8219     case REFINER_HYBRID_HEX_2D:
8220       for (p = cStart; p < cMax; ++p) {
8221         for (r = 0; r < 4; ++r) {
8222           newp     = (p - cStart)*4 + r;
8223           pi[newp] = p;
8224         }
8225       }
8226       for (p = cMax; p < cEnd; ++p) {
8227         for (r = 0; r < 2; ++r) {
8228           newp     = (cMax - cStart)*4 + (p - cMax)*2 + r;
8229           pi[newp] = p;
8230         }
8231       }
8232       break;
8233     case REFINER_SIMPLEX_3D:
8234       for (p = cStart; p < cEnd; ++p) {
8235         for (r = 0; r < 8; ++r) {
8236           newp     = (p - cStart)*8 + r;
8237           pi[newp] = p;
8238         }
8239       }
8240       break;
8241     case REFINER_HYBRID_SIMPLEX_3D:
8242       for (p = cStart; p < cMax; ++p) {
8243         for (r = 0; r < 8; ++r) {
8244           newp     = (p - cStart)*8 + r;
8245           pi[newp] = p;
8246         }
8247       }
8248       for (p = cMax; p < cEnd; ++p) {
8249         for (r = 0; r < 4; ++r) {
8250           newp     = (cMax - cStart)*8 + (p - cMax)*4 + r;
8251           pi[newp] = p;
8252         }
8253       }
8254       break;
8255     case REFINER_SIMPLEX_TO_HEX_3D:
8256       for (p = cStart; p < cEnd; ++p) {
8257         for (r = 0; r < 4; ++r) {
8258           newp     = (p - cStart)*4 + r;
8259           pi[newp] = p;
8260         }
8261       }
8262       break;
8263     case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
8264       for (p = cStart; p < cMax; ++p) {
8265         for (r = 0; r < 4; ++r) {
8266           newp     = (p - cStart)*4 + r;
8267           pi[newp] = p;
8268         }
8269       }
8270       for (p = cMax; p < cEnd; ++p) {
8271         for (r = 0; r < 3; ++r) {
8272           newp     = (cMax - cStart)*4 + (p - cMax)*3 + r;
8273           pi[newp] = p;
8274         }
8275       }
8276       break;
8277     case REFINER_HEX_3D:
8278       for (p = cStart; p < cEnd; ++p) {
8279         for (r = 0; r < 8; ++r) {
8280           newp = (p - cStart)*8 + r;
8281           pi[newp] = p;
8282         }
8283       }
8284       break;
8285     case REFINER_HYBRID_HEX_3D:
8286       for (p = cStart; p < cMax; ++p) {
8287         for (r = 0; r < 8; ++r) {
8288           newp = (p - cStart)*8 + r;
8289           pi[newp] = p;
8290         }
8291       }
8292       for (p = cMax; p < cEnd; ++p) {
8293         for (r = 0; r < 4; ++r) {
8294           newp = (cMax - cStart)*8 + (p - cMax)*4 + r;
8295           pi[newp] = p;
8296         }
8297       }
8298       break;
8299     default:
8300       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %D", refiner);
8301     }
8302     parentId = pi;
8303   } else {
8304     /* The refiner needs midpoint vertices on hybrid edges and hybrid cells */
8305     if (REFINER_HYBRID_SIMPLEX_TO_HEX_2D == refiner) { cMax = cEnd; eMax = eEnd; }
8306     ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+numVertices);CHKERRQ(ierr);
8307   }
8308 
8309   /* All vertices have the spaceDim coordinates */
8310   if (localize) {
8311     PetscInt c;
8312 
8313     for (c = cStartNew; c < cEndNew; ++c) {
8314       PetscInt *cone = NULL;
8315       PetscInt  closureSize, coneSize = 0, p, pdof;
8316 
8317       ierr = PetscSectionGetDof(coordSection, parentId[c], &pdof); CHKERRQ(ierr);
8318       if (pdof) { /* localize on all cells that are refinement of a localized parent cell */
8319         ierr = DMPlexGetTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8320         for (p = 0; p < closureSize*2; p += 2) {
8321           const PetscInt point = cone[p];
8322           if ((point >= vStartNew) && (point < vEndNew)) coneSize++;
8323         }
8324         ierr = DMPlexRestoreTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8325         ierr = PetscSectionSetDof(coordSectionNew, c, coneSize*spaceDim);CHKERRQ(ierr);
8326         ierr = PetscSectionSetFieldDof(coordSectionNew, c, 0, coneSize*spaceDim);CHKERRQ(ierr);
8327       }
8328     }
8329   }
8330   for (v = vStartNew; v < vStartNew+numVertices; ++v) {
8331     ierr = PetscSectionSetDof(coordSectionNew, v, spaceDim);CHKERRQ(ierr);
8332     ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, spaceDim);CHKERRQ(ierr);
8333   }
8334   ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
8335   ierr = DMSetCoordinateSection(rdm, PETSC_DETERMINE, coordSectionNew);CHKERRQ(ierr);
8336   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8337   ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
8338   ierr = VecCreate(PETSC_COMM_SELF, &coordinatesNew);CHKERRQ(ierr);
8339   ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
8340   ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
8341   ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr);
8342   ierr = VecSetBlockSize(coordinatesNew, bs);CHKERRQ(ierr);
8343   ierr = VecGetType(coordinates, &vtype);CHKERRQ(ierr);
8344   ierr = VecSetType(coordinatesNew, vtype);CHKERRQ(ierr);
8345   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
8346   ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
8347 
8348   switch (refiner) {
8349   case REFINER_NOOP: break;
8350   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
8351   case REFINER_SIMPLEX_TO_HEX_3D:
8352   case REFINER_HEX_3D:
8353   case REFINER_HYBRID_HEX_3D:
8354     /* Face vertices have the average of corner coordinates */
8355     for (f = fStart; f < fMax; ++f) {
8356       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
8357       PetscInt      *cone = NULL;
8358       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
8359 
8360       ierr = DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8361       for (p = 0; p < closureSize*2; p += 2) {
8362         const PetscInt point = cone[p];
8363         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
8364       }
8365       if (localize) {
8366         const PetscInt *support = NULL;
8367         PetscInt       *rStar = NULL;
8368         PetscInt        supportSize, rStarSize, coff, s, ccoff[8];
8369         PetscBool       cellfound = PETSC_FALSE;
8370 
8371         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8372         ierr = DMPlexGetSupportSize(dm,f,&supportSize);CHKERRQ(ierr);
8373         ierr = DMPlexGetSupport(dm,f,&support);CHKERRQ(ierr);
8374         /* Compute average of coordinates for each cell sharing the face */
8375         for (s = 0; s < supportSize; ++s) {
8376           PetscScalar     coordsNewAux[3] = { 0.0, 0.0, 0.0 };
8377           PetscInt       *cellCone = NULL;
8378           PetscInt        cellClosureSize, cellConeSize = 0, cdof;
8379           const PetscInt  cell = support[s];
8380           PetscBool       copyoff = PETSC_FALSE;
8381 
8382           ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
8383           for (p = 0; p < cellClosureSize*2; p += 2) {
8384             const PetscInt point = cellCone[p];
8385             if ((point >= vStart) && (point < vEnd)) cellCone[cellConeSize++] = point;
8386           }
8387           ierr = PetscSectionGetDof(coordSection, cell, &cdof);CHKERRQ(ierr);
8388           if (!cdof) { /* the parent cell does not have localized coordinates */
8389             cellfound = PETSC_TRUE;
8390             for (v = 0; v < coneSize; ++v) {
8391               ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
8392               for (d = 0; d < spaceDim; ++d) coordsNewAux[d] += coords[off[v]+d];
8393             }
8394             for (d = 0; d < spaceDim; ++d) coordsNewAux[d] /= coneSize;
8395           } else {
8396             ierr = PetscSectionGetOffset(coordSection, cell, &coff);CHKERRQ(ierr);
8397             for (p = 0; p < coneSize; ++p) {
8398               const PetscInt tv = cone[p];
8399               PetscInt       cv, voff;
8400               PetscBool      locv = PETSC_TRUE;
8401 
8402               for (cv = 0; cv < cellConeSize; ++cv) {
8403                 if (cellCone[cv] == tv) {
8404                   ccoff[p] = spaceDim*cv + coff;
8405                   break;
8406                 }
8407               }
8408               if (cv == cellConeSize) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map vertex %D",tv);
8409 
8410               ierr = PetscSectionGetOffset(coordSection, cone[p], &voff);CHKERRQ(ierr);
8411               for (d = 0; d < spaceDim; ++d) {
8412                 coordsNewAux[d] += coords[ccoff[p]+d];
8413                 if (!cellfound && coords[voff+d] != coords[ccoff[p]+d]) locv = PETSC_FALSE;
8414               }
8415               if (locv && !cellfound) {
8416                 cellfound = PETSC_TRUE;
8417                 copyoff   = PETSC_TRUE;
8418               }
8419             }
8420             for (d = 0; d < spaceDim; ++d) coordsNewAux[d] /= coneSize;
8421 
8422             /* Found a valid face for the "vertex" part of the Section (physical space)
8423                i.e., a face that has at least one corner in the physical space */
8424             if (copyoff) for (p = 0; p < coneSize; ++p) off[p] = ccoff[p];
8425           }
8426 
8427           /* Localize new coordinates on each refined cell */
8428           for (v = 0; v < rStarSize*2; v += 2) {
8429             if ((rStar[v] >= cStartNew) && (rStar[v] < cEndNew) && parentId[rStar[v]-cStartNew] == cell) {
8430               PetscInt       *rcone = NULL, rclosureSize, lid, rcdof, rcoff;
8431               const PetscInt  rcell = rStar[v];
8432 
8433               ierr = PetscSectionGetDof(coordSectionNew, rcell, &rcdof);CHKERRQ(ierr);
8434               if (!rcdof) continue;
8435               ierr = PetscSectionGetOffset(coordSectionNew, rcell, &rcoff);CHKERRQ(ierr);
8436               ierr = DMPlexGetTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
8437               for (p = 0, lid = 0; p < rclosureSize*2; p += 2) {
8438                 if (rcone[p] == newv) {
8439                   for (d = 0; d < spaceDim; d++) coordsNew[rcoff + lid*spaceDim + d] = coordsNewAux[d];
8440                   break;
8441                 }
8442                 if (rcone[p] >= vStartNew && rcone[p] < vEndNew) lid++;
8443               }
8444               ierr = DMPlexRestoreTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
8445               if (p == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D",newv);
8446             }
8447           }
8448           ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
8449         }
8450         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8451         if (!cellfound) {
8452           /* Could not find a valid face for the vertex part, we will get this vertex later (final reduction) */
8453           needcoords = PETSC_TRUE;
8454           coneSize   = 0;
8455         }
8456       } else {
8457         for (v = 0; v < coneSize; ++v) {
8458           ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
8459         }
8460       }
8461       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
8462       if (coneSize) {
8463         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
8464         for (v = 0; v < coneSize; ++v) {ierr = DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);CHKERRQ(ierr);}
8465         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
8466       } else {
8467         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = PETSC_MIN_REAL;
8468       }
8469       ierr = DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8470     }
8471   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
8472   case REFINER_SIMPLEX_TO_HEX_2D:
8473   case REFINER_HEX_2D:
8474   case REFINER_HYBRID_HEX_2D:
8475   case REFINER_SIMPLEX_1D:
8476     /* Cell vertices have the average of corner coordinates */
8477     for (c = cStart; c < cMax; ++c) {
8478       const PetscInt newv = vStartNew + (vEnd - vStart) + (dim > 1 ? (eMax - eStart) : 0) + (c - cStart) + (dim > 2 ? (fMax - fStart) : 0);
8479       PetscInt      *cone = NULL;
8480       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d, cdof = 0;
8481 
8482       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8483       for (p = 0; p < closureSize*2; p += 2) {
8484         const PetscInt point = cone[p];
8485         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
8486       }
8487       if (localize) {
8488         ierr = PetscSectionGetDof(coordSection, c, &cdof);CHKERRQ(ierr);
8489       }
8490       if (cdof) {
8491         PetscInt coff;
8492 
8493         ierr = PetscSectionGetOffset(coordSection, c, &coff);CHKERRQ(ierr);
8494         for (v = 0; v < coneSize; ++v) off[v] = spaceDim*v + coff;
8495       } else {
8496         for (v = 0; v < coneSize; ++v) {
8497           ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
8498         }
8499       }
8500       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
8501       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
8502       for (v = 0; v < coneSize; ++v) {ierr = DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);CHKERRQ(ierr);}
8503       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
8504       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8505 
8506       /* Localize new coordinates on each refined cell */
8507       if (cdof) {
8508         PetscInt *rStar = NULL, rStarSize;
8509 
8510         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8511         for (v = 0; v < rStarSize*2; v += 2) {
8512           if ((rStar[v] >= cStartNew) && (rStar[v] < cEndNew)) {
8513             PetscInt *cone = NULL, closureSize, lid, coff, rc, rcdof;
8514 
8515             rc   = rStar[v];
8516             ierr = PetscSectionGetDof(coordSectionNew, rc, &rcdof);CHKERRQ(ierr);
8517             if (!rcdof) continue;
8518             ierr = PetscSectionGetOffset(coordSectionNew, rc, &coff);CHKERRQ(ierr);
8519             ierr = DMPlexGetTransitiveClosure(rdm, rc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8520             for (p = 0, lid = 0; p < closureSize*2; p += 2) {
8521               if (cone[p] == newv) {
8522                 for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = coordsNew[offnew + d];
8523                 break;
8524               }
8525               if (cone[p] >= vStartNew && cone[p] < vEndNew) lid++;
8526             }
8527             if (p == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D",newv);
8528             ierr = DMPlexRestoreTransitiveClosure(rdm, rc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8529           }
8530         }
8531         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8532       }
8533     }
8534   case REFINER_SIMPLEX_2D:
8535   case REFINER_HYBRID_SIMPLEX_2D:
8536   case REFINER_SIMPLEX_3D:
8537   case REFINER_HYBRID_SIMPLEX_3D:
8538     /* Edge vertices have the average of endpoint coordinates */
8539     for (e = eStart; e < eMax; ++e) {
8540       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
8541       const PetscInt *cone;
8542       PetscInt        coneSize, offA, offB, offnew, d;
8543 
8544       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
8545       if (coneSize != 2) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Edge %D cone should have two vertices, not %D", e, coneSize);
8546       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
8547       if (localize) {
8548         PetscInt   coff, toffA = -1, toffB = -1, voffA, voffB;
8549         PetscInt  *eStar = NULL, eStarSize;
8550         PetscInt  *rStar = NULL, rStarSize;
8551         PetscBool  cellfound = PETSC_FALSE;
8552 
8553         offA = offB = -1;
8554         ierr = PetscSectionGetOffset(coordSection, cone[0], &voffA);CHKERRQ(ierr);
8555         ierr = PetscSectionGetOffset(coordSection, cone[1], &voffB);CHKERRQ(ierr);
8556         ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &eStarSize, &eStar);CHKERRQ(ierr);
8557         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8558         for (v = 0; v < eStarSize*2; v += 2) {
8559           if ((eStar[v] >= cStart) && (eStar[v] < cEnd)) {
8560             PetscScalar     coordsNewAux[3];
8561             PetscInt       *cellCone = NULL;
8562             PetscInt        cellClosureSize, s, cv, cdof;
8563             PetscBool       locvA = PETSC_TRUE, locvB = PETSC_TRUE;
8564             const PetscInt  cell = eStar[v];
8565 
8566             ierr = PetscSectionGetDof(coordSection, cell, &cdof);CHKERRQ(ierr);
8567             if (!cdof) {
8568               /* Found a valid edge for the "vertex" part of the Section */
8569               offA = voffA;
8570               offB = voffB;
8571               cellfound = PETSC_TRUE;
8572             } else {
8573               ierr = PetscSectionGetOffset(coordSection, cell, &coff);CHKERRQ(ierr);
8574               ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
8575               for (s = 0, cv = 0; s < cellClosureSize*2; s += 2) {
8576                 const PetscInt point = cellCone[s];
8577                 if ((point >= vStart) && (point < vEnd)) {
8578                   if (point == cone[0]) toffA = spaceDim*cv + coff;
8579                   else if (point == cone[1]) toffB = spaceDim*cv + coff;
8580                   cv++;
8581                 }
8582               }
8583               ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
8584               for (d = 0; d < spaceDim; ++d) {
8585                 coordsNewAux[d] = 0.5*(coords[toffA+d] + coords[toffB+d]);
8586                 if (coords[toffA+d] != coords[voffA+d]) locvA = PETSC_FALSE;
8587                 if (coords[toffB+d] != coords[voffB+d]) locvB = PETSC_FALSE;
8588               }
8589               /* Found a valid edge for the "vertex" part of the Section */
8590               if (!cellfound && (locvA || locvB)) {
8591                 cellfound = PETSC_TRUE;
8592                 offA = toffA;
8593                 offB = toffB;
8594               }
8595             }
8596 
8597             /* Localize new coordinates on each refined cell */
8598             for (s = 0; s < rStarSize*2; s += 2) {
8599               if ((rStar[s] >= cStartNew) && (rStar[s] < cEndNew) && parentId[rStar[s]-cStartNew] == cell) {
8600                 PetscInt       *rcone = NULL, rclosureSize, lid, p, rcdof;
8601                 const PetscInt  rcell = rStar[s];
8602 
8603                 ierr = PetscSectionGetDof(coordSectionNew, rcell, &rcdof);CHKERRQ(ierr);
8604                 if (!rcdof) continue;
8605                 ierr = PetscSectionGetOffset(coordSectionNew, rcell, &coff);CHKERRQ(ierr);
8606                 ierr = DMPlexGetTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
8607                 for (p = 0, lid = 0; p < rclosureSize*2; p += 2) {
8608                   if (rcone[p] == newv) {
8609                     for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = coordsNewAux[d];
8610                     break;
8611                   }
8612                   if (rcone[p] >= vStartNew && rcone[p] < vEndNew) lid++;
8613                 }
8614                 ierr = DMPlexRestoreTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
8615                 if (p == rclosureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D",newv);
8616               }
8617             }
8618           }
8619         }
8620         ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &eStarSize, &eStar);CHKERRQ(ierr);
8621         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8622         if (!cellfound) {
8623           /* Could not find a valid edge for the vertex part, we will get this vertex later (final reduction) */
8624           needcoords = PETSC_TRUE;
8625         }
8626       } else {
8627         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
8628         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
8629       }
8630       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
8631       if (offA != -1 && offB != -1) {
8632         ierr = DMLocalizeCoordinate_Internal(dm, spaceDim, &coords[offA], &coords[offB], &coordsNew[offnew]);CHKERRQ(ierr);
8633         for (d = 0; d < spaceDim; ++d) {
8634           coordsNew[offnew+d] = 0.5*(coords[offA+d] + coordsNew[offnew+d]);
8635         }
8636       } else {
8637         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = PETSC_MIN_REAL;
8638       }
8639     }
8640     /* Old vertices have the same coordinates */
8641     for (v = vStart; v < vEnd; ++v) {
8642       const PetscInt newv = vStartNew + (v - vStart);
8643       PetscInt       off, offnew, d;
8644 
8645       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
8646       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
8647       for (d = 0; d < spaceDim; ++d) {
8648         coordsNew[offnew+d] = coords[off+d];
8649       }
8650 
8651       /* Localize new coordinates on each refined cell */
8652       if (localize) {
8653         PetscInt  p;
8654         PetscInt *rStar = NULL, rStarSize;
8655 
8656         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8657         for (p = 0; p < rStarSize*2; p += 2) {
8658           if ((rStar[p] >= cStartNew) && (rStar[p] < cEndNew)) {
8659             PetscScalar  ocoords[3];
8660             PetscInt    *cone = NULL, closureSize, lid, coff, s, oc, cdof;
8661 
8662             c    = rStar[p];
8663             oc   = parentId[c-cStartNew];
8664             ierr = PetscSectionGetDof(coordSectionNew, c, &cdof);CHKERRQ(ierr);
8665             if (!cdof) continue;
8666             ierr = PetscSectionGetDof(coordSection, oc, &cdof);CHKERRQ(ierr);
8667             if (!cdof) continue;
8668             ierr = PetscSectionGetOffset(coordSection, oc, &coff);CHKERRQ(ierr);
8669             ierr = DMPlexGetTransitiveClosure(dm, oc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8670             for (s = 0, lid = 0; s < closureSize*2; s += 2) {
8671               if (cone[s] == v) {
8672                 for (d = 0; d < spaceDim; d++) ocoords[d] = coords[coff + lid*spaceDim + d];
8673                 break;
8674               }
8675               if (cone[s] >= vStart && cone[s] < vEnd) lid++;
8676             }
8677             if (s == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map old vertex %D",v);
8678             ierr = DMPlexRestoreTransitiveClosure(dm, oc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8679 
8680             ierr = PetscSectionGetOffset(coordSectionNew, c, &coff);CHKERRQ(ierr);
8681             ierr = DMPlexGetTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8682             for (s = 0, lid = 0; s < closureSize*2; s += 2) {
8683               if (cone[s] == newv) {
8684                 for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = ocoords[d];
8685                 break;
8686               }
8687               if (cone[s] >= vStartNew && cone[s] < vEndNew) lid++;
8688             }
8689             if (s == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D",newv);
8690             ierr = DMPlexRestoreTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
8691           }
8692         }
8693         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
8694       }
8695     }
8696     break;
8697   default:
8698     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %D", refiner);
8699   }
8700   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
8701   ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
8702   ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
8703 
8704   /* Final reduction (if needed) if we are localizing */
8705   if (localize) {
8706     PetscBool gred;
8707 
8708     ierr = MPIU_Allreduce(&needcoords, &gred, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)rdm));CHKERRQ(ierr);
8709     if (gred) {
8710       DM                 cdm;
8711       Vec                aux;
8712       PetscSF            sf;
8713       const PetscScalar *lArray;
8714       PetscScalar       *gArray;
8715 #if defined(PETSC_USE_COMPLEX)
8716       PetscInt          i, ln, gn;
8717       PetscReal         *lrArray;
8718       PetscReal         *grArray;
8719 #endif
8720 
8721       ierr = DMGetCoordinateDM(rdm, &cdm);CHKERRQ(ierr);
8722       ierr = DMCreateGlobalVector(cdm, &aux);CHKERRQ(ierr);
8723       ierr = DMGetDefaultSF(cdm, &sf);CHKERRQ(ierr);
8724       ierr = VecGetArrayRead(coordinatesNew, &lArray);CHKERRQ(ierr);
8725       ierr = VecSet(aux, PETSC_MIN_REAL);CHKERRQ(ierr);
8726       ierr = VecGetArray(aux, &gArray);CHKERRQ(ierr);
8727 #if defined(PETSC_USE_COMPLEX)
8728       ierr = VecGetLocalSize(aux, &gn);CHKERRQ(ierr);
8729       ierr = VecGetLocalSize(coordinatesNew, &ln);CHKERRQ(ierr);
8730       ierr = PetscMalloc2(ln,&lrArray,gn,&grArray);CHKERRQ(ierr);
8731       for (i=0;i<ln;i++) lrArray[i] = PetscRealPart(lArray[i]);
8732       for (i=0;i<gn;i++) grArray[i] = PetscRealPart(gArray[i]);
8733       ierr = PetscSFReduceBegin(sf, MPIU_REAL, lrArray, grArray, MPIU_MAX);CHKERRQ(ierr);
8734       ierr = PetscSFReduceEnd(sf, MPIU_REAL, lrArray, grArray, MPIU_MAX);CHKERRQ(ierr);
8735       for (i=0;i<gn;i++) gArray[i] = grArray[i];
8736       ierr = PetscFree2(lrArray,grArray);CHKERRQ(ierr);
8737 #else
8738       ierr = PetscSFReduceBegin(sf, MPIU_SCALAR, lArray, gArray, MPIU_MAX);CHKERRQ(ierr);
8739       ierr = PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_MAX);CHKERRQ(ierr);
8740 #endif
8741       ierr = VecRestoreArrayRead(coordinatesNew, &lArray);CHKERRQ(ierr);
8742       ierr = VecRestoreArray(aux, &gArray);CHKERRQ(ierr);
8743       ierr = DMGlobalToLocalBegin(cdm, aux, INSERT_VALUES, coordinatesNew);CHKERRQ(ierr);
8744       ierr = DMGlobalToLocalEnd(cdm, aux, INSERT_VALUES, coordinatesNew);CHKERRQ(ierr);
8745       ierr = VecDestroy(&aux);CHKERRQ(ierr);
8746     }
8747   }
8748   ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
8749   ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
8750   ierr = PetscFree(parentId);CHKERRQ(ierr);
8751   PetscFunctionReturn(0);
8752 }
8753 
8754 /*@
8755   DMPlexCreateProcessSF - Create an SF which just has process connectivity
8756 
8757   Collective on DM
8758 
8759   Input Parameters:
8760 + dm      - The DM
8761 - sfPoint - The PetscSF which encodes point connectivity
8762 
8763   Output Parameters:
8764 + processRanks - A list of process neighbors, or NULL
8765 - sfProcess    - An SF encoding the process connectivity, or NULL
8766 
8767   Level: developer
8768 
8769 .seealso: PetscSFCreate(), DMPlexCreateTwoSidedProcessSF()
8770 @*/
8771 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
8772 {
8773   PetscInt           numRoots, numLeaves, l;
8774   const PetscInt    *localPoints;
8775   const PetscSFNode *remotePoints;
8776   PetscInt          *localPointsNew;
8777   PetscSFNode       *remotePointsNew;
8778   PetscInt          *ranks, *ranksNew;
8779   PetscMPIInt        size;
8780   PetscErrorCode     ierr;
8781 
8782   PetscFunctionBegin;
8783   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8784   PetscValidHeaderSpecific(sfPoint, PETSCSF_CLASSID, 2);
8785   if (processRanks) {PetscValidPointer(processRanks, 3);}
8786   if (sfProcess)    {PetscValidPointer(sfProcess, 4);}
8787   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) dm), &size);CHKERRQ(ierr);
8788   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
8789   ierr = PetscMalloc1(numLeaves, &ranks);CHKERRQ(ierr);
8790   for (l = 0; l < numLeaves; ++l) {
8791     ranks[l] = remotePoints[l].rank;
8792   }
8793   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
8794   ierr = PetscMalloc1(numLeaves, &ranksNew);CHKERRQ(ierr);
8795   ierr = PetscMalloc1(numLeaves, &localPointsNew);CHKERRQ(ierr);
8796   ierr = PetscMalloc1(numLeaves, &remotePointsNew);CHKERRQ(ierr);
8797   for (l = 0; l < numLeaves; ++l) {
8798     ranksNew[l]              = ranks[l];
8799     localPointsNew[l]        = l;
8800     remotePointsNew[l].index = 0;
8801     remotePointsNew[l].rank  = ranksNew[l];
8802   }
8803   ierr = PetscFree(ranks);CHKERRQ(ierr);
8804   if (processRanks) {ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);}
8805   else              {ierr = PetscFree(ranksNew);CHKERRQ(ierr);}
8806   if (sfProcess) {
8807     ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
8808     ierr = PetscObjectSetName((PetscObject) *sfProcess, "Process SF");CHKERRQ(ierr);
8809     ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
8810     ierr = PetscSFSetGraph(*sfProcess, size, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
8811   }
8812   PetscFunctionReturn(0);
8813 }
8814 
8815 static PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
8816 {
8817   PetscSF            sf, sfNew, sfProcess;
8818   IS                 processRanks;
8819   MPI_Datatype       depthType;
8820   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
8821   const PetscInt    *localPoints, *neighbors;
8822   const PetscSFNode *remotePoints;
8823   PetscInt          *localPointsNew;
8824   PetscSFNode       *remotePointsNew;
8825   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
8826   PetscInt           ldepth, depth, numNeighbors, pStartNew, pEndNew, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r, n;
8827   PetscInt           cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
8828   PetscErrorCode     ierr;
8829 
8830   PetscFunctionBegin;
8831   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
8832   ierr = DMPlexGetDepth(dm, &ldepth);CHKERRQ(ierr);
8833   ierr = MPIU_Allreduce(&ldepth, &depth, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
8834   if ((ldepth >= 0) && (depth != ldepth)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent Plex depth %D != %D", ldepth, depth);
8835   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8836   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
8837   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8838   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
8839   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
8840   cMax = cMax < 0 ? cEnd : cMax;
8841   fMax = fMax < 0 ? fEnd : fMax;
8842   eMax = eMax < 0 ? eEnd : eMax;
8843   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
8844   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
8845   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
8846   /* Calculate size of new SF */
8847   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
8848   if (numRoots < 0) PetscFunctionReturn(0);
8849   for (l = 0; l < numLeaves; ++l) {
8850     const PetscInt p = localPoints[l];
8851 
8852     switch (refiner) {
8853     case REFINER_SIMPLEX_1D:
8854       if ((p >= vStart) && (p < vEnd)) {
8855         /* Interior vertices stay the same */
8856         ++numLeavesNew;
8857       } else if ((p >= cStart && p < cMax)) {
8858         /* Interior cells add new cells and interior vertices */
8859         numLeavesNew += 2 + 1;
8860       }
8861       break;
8862     case REFINER_SIMPLEX_2D:
8863     case REFINER_HYBRID_SIMPLEX_2D:
8864       if ((p >= vStart) && (p < vEnd)) {
8865         /* Interior vertices stay the same */
8866         ++numLeavesNew;
8867       } else if ((p >= fStart) && (p < fMax)) {
8868         /* Interior faces add new faces and vertex */
8869         numLeavesNew += 2 + 1;
8870       } else if ((p >= fMax) && (p < fEnd)) {
8871         /* Hybrid faces stay the same */
8872         ++numLeavesNew;
8873       } else if ((p >= cStart) && (p < cMax)) {
8874         /* Interior cells add new cells and interior faces */
8875         numLeavesNew += 4 + 3;
8876       } else if ((p >= cMax) && (p < cEnd)) {
8877         /* Hybrid cells add new cells and hybrid face */
8878         numLeavesNew += 2 + 1;
8879       }
8880       break;
8881     case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
8882     case REFINER_SIMPLEX_TO_HEX_2D:
8883       if ((p >= vStart) && (p < vEnd)) {
8884         /* Interior vertices stay the same */
8885         ++numLeavesNew;
8886       } else if ((p >= fStart) && (p < fEnd)) {
8887         /* Interior faces add new faces and vertex */
8888         numLeavesNew += 2 + 1;
8889       } else if ((p >= cStart) && (p < cMax)) {
8890         /* Interior cells add new cells, interior faces, and vertex */
8891         numLeavesNew += 3 + 3 + 1;
8892       } else if ((p >= cMax) && (p < cEnd)) {
8893         /* Hybrid cells add new cells, interior faces, and vertex */
8894         numLeavesNew += 4 + 4 + 1;
8895       }
8896       break;
8897     case REFINER_HEX_2D:
8898     case REFINER_HYBRID_HEX_2D:
8899       if ((p >= vStart) && (p < vEnd)) {
8900         /* Interior vertices stay the same */
8901         ++numLeavesNew;
8902       } else if ((p >= fStart) && (p < fMax)) {
8903         /* Interior faces add new faces and vertex */
8904         numLeavesNew += 2 + 1;
8905       } else if ((p >= fMax) && (p < fEnd)) {
8906         /* Hybrid faces stay the same */
8907         ++numLeavesNew;
8908       } else if ((p >= cStart) && (p < cMax)) {
8909         /* Interior cells add new cells, interior faces, and vertex */
8910         numLeavesNew += 4 + 4 + 1;
8911       } else if ((p >= cMax) && (p < cEnd)) {
8912         /* Hybrid cells add new cells and hybrid face */
8913         numLeavesNew += 2 + 1;
8914       }
8915       break;
8916     case REFINER_SIMPLEX_3D:
8917     case REFINER_HYBRID_SIMPLEX_3D:
8918       if ((p >= vStart) && (p < vEnd)) {
8919         /* Interior vertices stay the same */
8920         ++numLeavesNew;
8921       } else if ((p >= eStart) && (p < eMax)) {
8922         /* Interior edges add new edges and vertex */
8923         numLeavesNew += 2 + 1;
8924       } else if ((p >= eMax) && (p < eEnd)) {
8925         /* Hybrid edges stay the same */
8926         ++numLeavesNew;
8927       } else if ((p >= fStart) && (p < fMax)) {
8928         /* Interior faces add new faces and edges */
8929         numLeavesNew += 4 + 3;
8930       } else if ((p >= fMax) && (p < fEnd)) {
8931         /* Hybrid faces add new faces and edges */
8932         numLeavesNew += 2 + 1;
8933       } else if ((p >= cStart) && (p < cMax)) {
8934         /* Interior cells add new cells, faces, and edges */
8935         numLeavesNew += 8 + 8 + 1;
8936       } else if ((p >= cMax) && (p < cEnd)) {
8937         /* Hybrid cells add new cells and faces */
8938         numLeavesNew += 4 + 3;
8939       }
8940       break;
8941     case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
8942     case REFINER_SIMPLEX_TO_HEX_3D:
8943       if ((p >= vStart) && (p < vEnd)) {
8944         /* Interior vertices stay the same */
8945         ++numLeavesNew;
8946       } else if ((p >= eStart) && (p < eMax)) {
8947         /* Interior edges add new edges and vertex */
8948         numLeavesNew += 2 + 1;
8949       } else if ((p >= eMax) && (p < eEnd)) {
8950         /* Hybrid edges stay the same */
8951         ++numLeavesNew;
8952       } else if ((p >= fStart) && (p < fMax)) {
8953         /* Interior faces add new faces, edges and a vertex */
8954         numLeavesNew += 3 + 3 + 1;
8955       } else if ((p >= fMax) && (p < fEnd)) {
8956         /* Hybrid faces add new faces and an edge */
8957         numLeavesNew += 2 + 1;
8958       } else if ((p >= cStart) && (p < cMax)) {
8959         /* Interior cells add new cells, faces, edges and a vertex */
8960         numLeavesNew += 4 + 6 + 4 + 1;
8961       } else if ((p >= cMax) && (p < cEnd)) {
8962         /* Hybrid cells add new cells, faces and an edge */
8963         numLeavesNew += 3 + 3 + 1;
8964       }
8965       break;
8966     case REFINER_HEX_3D:
8967     case REFINER_HYBRID_HEX_3D:
8968       if ((p >= vStart) && (p < vEnd)) {
8969         /* Old vertices stay the same */
8970         ++numLeavesNew;
8971       } else if ((p >= eStart) && (p < eMax)) {
8972         /* Interior edges add new edges, and vertex */
8973         numLeavesNew += 2 + 1;
8974       } else if ((p >= eMax) && (p < eEnd)) {
8975         /* Hybrid edges stay the same */
8976         ++numLeavesNew;
8977       } else if ((p >= fStart) && (p < fMax)) {
8978         /* Interior faces add new faces, edges, and vertex */
8979         numLeavesNew += 4 + 4 + 1;
8980       } else if ((p >= fMax) && (p < fEnd)) {
8981         /* Hybrid faces add new faces and edges */
8982         numLeavesNew += 2 + 1;
8983       } else if ((p >= cStart) && (p < cMax)) {
8984         /* Interior cells add new cells, faces, edges, and vertex */
8985         numLeavesNew += 8 + 12 + 6 + 1;
8986       } else if ((p >= cStart) && (p < cEnd)) {
8987         /* Hybrid cells add new cells, faces, and edges */
8988         numLeavesNew += 4 + 4 + 1;
8989       }
8990       break;
8991     default:
8992       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %D", refiner);
8993     }
8994   }
8995   /* Communicate depthSizes for each remote rank */
8996   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
8997   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
8998   ierr = PetscMalloc5((depth+1)*numNeighbors,&rdepthSize,numNeighbors,&rvStartNew,numNeighbors,&reStartNew,numNeighbors,&rfStartNew,numNeighbors,&rcStartNew);CHKERRQ(ierr);
8999   ierr = PetscMalloc7(depth+1,&depthSizeOld,(depth+1)*numNeighbors,&rdepthSizeOld,(depth+1)*numNeighbors,&rdepthMaxOld,numNeighbors,&rvStart,numNeighbors,&reStart,numNeighbors,&rfStart,numNeighbors,&rcStart);CHKERRQ(ierr);
9000   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
9001   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
9002   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
9003   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
9004   for (n = 0; n < numNeighbors; ++n) {
9005     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
9006   }
9007   depthSizeOld[depth]   = cMax;
9008   depthSizeOld[0]       = vMax;
9009   depthSizeOld[depth-1] = fMax;
9010   depthSizeOld[1]       = eMax;
9011 
9012   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
9013   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
9014 
9015   depthSizeOld[depth]   = cEnd - cStart;
9016   depthSizeOld[0]       = vEnd - vStart;
9017   depthSizeOld[depth-1] = fEnd - fStart;
9018   depthSizeOld[1]       = eEnd - eStart;
9019 
9020   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
9021   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
9022   for (n = 0; n < numNeighbors; ++n) {
9023     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
9024     rdepthMaxOld[n*(depth+1)+depth]   = rdepthMaxOld[n*(depth+1)+depth]   < 0 ? rdepthSizeOld[n*(depth+1)+depth]  +rcStart[n]: rdepthMaxOld[n*(depth+1)+depth];
9025     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];
9026     rdepthMaxOld[n*(depth+1)+1]       = rdepthMaxOld[n*(depth+1)+1]       < 0 ? rdepthSizeOld[n*(depth+1)+1]      +reStart[n]: rdepthMaxOld[n*(depth+1)+1];
9027   }
9028   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
9029   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
9030   /* Calculate new point SF */
9031   ierr = PetscMalloc1(numLeavesNew, &localPointsNew);CHKERRQ(ierr);
9032   ierr = PetscMalloc1(numLeavesNew, &remotePointsNew);CHKERRQ(ierr);
9033   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
9034   for (l = 0, m = 0; l < numLeaves; ++l) {
9035     PetscInt    p     = localPoints[l];
9036     PetscInt    rp    = remotePoints[l].index, n;
9037     PetscMPIInt rrank = remotePoints[l].rank;
9038 
9039     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
9040     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %D", rrank);
9041     switch (refiner) {
9042     case REFINER_SIMPLEX_1D:
9043       if ((p >= vStart) && (p < vEnd)) {
9044         /* Old vertices stay the same */
9045         localPointsNew[m]        = vStartNew     + (p  - vStart);
9046         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9047         remotePointsNew[m].rank  = rrank;
9048         ++m;
9049       } else if ((p >= cStart) && (p < cMax)) {
9050         /* Old interior cells add new cells and vertex */
9051         for (r = 0; r < 2; ++r, ++m) {
9052           localPointsNew[m]        = cStartNew     + (p  - cStart)*2     + r;
9053           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*2 + r;
9054           remotePointsNew[m].rank  = rrank;
9055         }
9056         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - cStart);
9057         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rcStart[n]);
9058         remotePointsNew[m].rank  = rrank;
9059         ++m;
9060       }
9061       break;
9062     case REFINER_SIMPLEX_2D:
9063     case REFINER_HYBRID_SIMPLEX_2D:
9064       if ((p >= vStart) && (p < vEnd)) {
9065         /* Old vertices stay the same */
9066         localPointsNew[m]        = vStartNew     + (p  - vStart);
9067         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9068         remotePointsNew[m].rank  = rrank;
9069         ++m;
9070       } else if ((p >= fStart) && (p < fMax)) {
9071         /* Old interior faces add new faces and vertex */
9072         for (r = 0; r < 2; ++r, ++m) {
9073           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
9074           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
9075           remotePointsNew[m].rank  = rrank;
9076         }
9077         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
9078         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
9079         remotePointsNew[m].rank  = rrank;
9080         ++m;
9081       } else if ((p >= fMax) && (p < fEnd)) {
9082         /* Old hybrid faces stay the same */
9083         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
9084         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
9085         remotePointsNew[m].rank  = rrank;
9086         ++m;
9087       } else if ((p >= cStart) && (p < cMax)) {
9088         /* Old interior cells add new cells and interior faces */
9089         for (r = 0; r < 4; ++r, ++m) {
9090           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
9091           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
9092           remotePointsNew[m].rank  = rrank;
9093         }
9094         for (r = 0; r < 3; ++r, ++m) {
9095           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
9096           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
9097           remotePointsNew[m].rank  = rrank;
9098         }
9099       } else if ((p >= cMax) && (p < cEnd)) {
9100         /* Old hybrid cells add new cells and hybrid face */
9101         for (r = 0; r < 2; ++r, ++m) {
9102           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
9103           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
9104           remotePointsNew[m].rank  = rrank;
9105         }
9106         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
9107         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]);
9108         remotePointsNew[m].rank  = rrank;
9109         ++m;
9110       }
9111       break;
9112     case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
9113     case REFINER_SIMPLEX_TO_HEX_2D:
9114       if ((p >= vStart) && (p < vEnd)) {
9115         /* Old vertices stay the same */
9116         localPointsNew[m]        = vStartNew     + (p  - vStart);
9117         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9118         remotePointsNew[m].rank  = rrank;
9119         ++m;
9120       } else if ((p >= fStart) && (p < fEnd)) {
9121         /* Old interior faces add new faces and vertex */
9122         for (r = 0; r < 2; ++r, ++m) {
9123           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
9124           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
9125           remotePointsNew[m].rank  = rrank;
9126         }
9127         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
9128         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
9129         remotePointsNew[m].rank  = rrank;
9130         ++m;
9131       } else if ((p >= cStart) && (p < cMax)) {
9132         /* Old interior cells add new cells, interior faces, and a vertex */
9133         for (r = 0; r < 3; ++r, ++m) {
9134           localPointsNew[m]        = cStartNew     + (p  - cStart)*3     + r;
9135           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*3 + r;
9136           remotePointsNew[m].rank  = rrank;
9137         }
9138         for (r = 0; r < 3; ++r, ++m) {
9139           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
9140           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
9141           remotePointsNew[m].rank  = rrank;
9142         }
9143         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (fEnd - fStart)                    + (p  - cStart);
9144         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
9145         remotePointsNew[m].rank  = rrank;
9146         ++m;
9147       } else if ((p >= cMax) && (p < cEnd)) {
9148         /* Old interior hybrid cells add new cells, interior faces, and a vertex */
9149         for (r = 0; r < 4; ++r, ++m) {
9150           localPointsNew[m]        = cStartNew     + (cMax  - cStart)*3                               + (p  - cMax)*4 + r;
9151           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*3 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
9152           remotePointsNew[m].rank  = rrank;
9153         }
9154         for (r = 0; r < 4; ++r, ++m) {
9155           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (cMax  - cStart)*3                               + (p - cMax)*4 + r;
9156           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;
9157           remotePointsNew[m].rank  = rrank;
9158         }
9159         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (fEnd - fStart)                    + (p  - cStart);
9160         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
9161         remotePointsNew[m].rank  = rrank;
9162         ++m;
9163       }
9164       break;
9165     case REFINER_HEX_2D:
9166     case REFINER_HYBRID_HEX_2D:
9167       if ((p >= vStart) && (p < vEnd)) {
9168         /* Old vertices stay the same */
9169         localPointsNew[m]        = vStartNew     + (p  - vStart);
9170         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9171         remotePointsNew[m].rank  = rrank;
9172         ++m;
9173       } else if ((p >= fStart) && (p < fMax)) {
9174         /* Old interior faces add new faces and vertex */
9175         for (r = 0; r < 2; ++r, ++m) {
9176           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
9177           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
9178           remotePointsNew[m].rank  = rrank;
9179         }
9180         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
9181         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
9182         remotePointsNew[m].rank  = rrank;
9183         ++m;
9184       } else if ((p >= fMax) && (p < fEnd)) {
9185         /* Old hybrid faces stay the same */
9186         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
9187         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
9188         remotePointsNew[m].rank  = rrank;
9189         ++m;
9190       } else if ((p >= cStart) && (p < cMax)) {
9191         /* Old interior cells add new cells, interior faces, and vertex */
9192         for (r = 0; r < 4; ++r, ++m) {
9193           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
9194           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
9195           remotePointsNew[m].rank  = rrank;
9196         }
9197         for (r = 0; r < 4; ++r, ++m) {
9198           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*4     + r;
9199           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*4 + r;
9200           remotePointsNew[m].rank  = rrank;
9201         }
9202         localPointsNew[m]        = vStartNew     + (vEnd - vStart)               + (fMax                              - fStart)     + (p  - cStart);
9203         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0]  + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]);
9204         remotePointsNew[m].rank  = rrank;
9205         ++m;
9206       } else if ((p >= cStart) && (p < cMax)) {
9207         /* Old hybrid cells add new cells and hybrid face */
9208         for (r = 0; r < 2; ++r, ++m) {
9209           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r; /* TODO: is this a bug? */
9210           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r; /* TODO: is this a bug? */
9211           remotePointsNew[m].rank  = rrank;
9212         }
9213         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*4     + (p  - cMax);
9214         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]);
9215         remotePointsNew[m].rank  = rrank;
9216         ++m;
9217       }
9218       break;
9219     case REFINER_SIMPLEX_3D:
9220     case REFINER_HYBRID_SIMPLEX_3D:
9221       if ((p >= vStart) && (p < vEnd)) {
9222         /* Interior vertices stay the same */
9223         localPointsNew[m]        = vStartNew     + (p  - vStart);
9224         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9225         remotePointsNew[m].rank  = rrank;
9226         ++m;
9227       } else if ((p >= eStart) && (p < eMax)) {
9228         /* Interior edges add new edges and vertex */
9229         for (r = 0; r < 2; ++r, ++m) {
9230           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
9231           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
9232           remotePointsNew[m].rank  = rrank;
9233         }
9234         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
9235         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
9236         remotePointsNew[m].rank  = rrank;
9237         ++m;
9238       } else if ((p >= eMax) && (p < eEnd)) {
9239         /* Hybrid edges stay the same */
9240         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - eMax);
9241         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]);
9242         remotePointsNew[m].rank  = rrank;
9243         ++m;
9244       } else if ((p >= fStart) && (p < fMax)) {
9245         /* Interior faces add new faces and edges */
9246         for (r = 0; r < 4; ++r, ++m) {
9247           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
9248           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
9249           remotePointsNew[m].rank  = rrank;
9250         }
9251         for (r = 0; r < 3; ++r, ++m) {
9252           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*3     + r;
9253           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
9254           remotePointsNew[m].rank  = rrank;
9255         }
9256       } else if ((p >= fMax) && (p < fEnd)) {
9257         /* Hybrid faces add new faces and edges */
9258         for (r = 0; r < 2; ++r, ++m) {
9259           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fMax)*2                              + r;
9260           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;
9261           remotePointsNew[m].rank  = rrank;
9262         }
9263         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (eEnd                                    - eMax)                        + (p  - fMax);
9264         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]);
9265         remotePointsNew[m].rank  = rrank;
9266         ++m;
9267       } else if ((p >= cStart) && (p < cMax)) {
9268         /* Interior cells add new cells, faces, and edges */
9269         for (r = 0; r < 8; ++r, ++m) {
9270           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
9271           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
9272           remotePointsNew[m].rank  = rrank;
9273         }
9274         for (r = 0; r < 8; ++r, ++m) {
9275           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*8     + r;
9276           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*8 + r;
9277           remotePointsNew[m].rank  = rrank;
9278         }
9279         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (p  - cStart)*1     + 0;
9280         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;
9281         remotePointsNew[m].rank  = rrank;
9282         ++m;
9283       } else if ((p >= cMax) && (p < cEnd)) {
9284         /* Hybrid cells add new cells and faces */
9285         for (r = 0; r < 4; ++r, ++m) {
9286           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
9287           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
9288           remotePointsNew[m].rank  = rrank;
9289         }
9290         for (r = 0; r < 3; ++r, ++m) {
9291           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*2                              + (p  - cMax)*3                            + r;
9292           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;
9293           remotePointsNew[m].rank  = rrank;
9294         }
9295       }
9296       break;
9297     case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
9298     case REFINER_SIMPLEX_TO_HEX_3D:
9299       if ((p >= vStart) && (p < vEnd)) {
9300         /* Interior vertices stay the same */
9301         localPointsNew[m]        = vStartNew     + (p  - vStart);
9302         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9303         remotePointsNew[m].rank  = rrank;
9304         ++m;
9305       } else if ((p >= eStart) && (p < eMax)) {
9306         /* Interior edges add new edges and vertex */
9307         for (r = 0; r < 2; ++r, ++m) {
9308           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
9309           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
9310           remotePointsNew[m].rank  = rrank;
9311         }
9312         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
9313         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
9314         remotePointsNew[m].rank  = rrank;
9315         ++m;
9316       } else if ((p >= eMax) && (p < eEnd)) {
9317         /* Hybrid edges stay the same */
9318         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)*4     + (p  - eMax);
9319         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]);
9320         remotePointsNew[m].rank  = rrank;
9321         ++m;
9322       } else if ((p >= fStart) && (p < fMax)) {
9323         /* Interior faces add new faces, edges and a vertex */
9324         for (r = 0; r < 3; ++r, ++m) {
9325           localPointsNew[m]        = fStartNew     + (p  - fStart)*3     + r;
9326           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*3 + r;
9327           remotePointsNew[m].rank  = rrank;
9328         }
9329         for (r = 0; r < 3; ++r, ++m) {
9330           localPointsNew[m]        = eStartNew     + (eMax - eStart)*2                            + (p  - fStart)*3     + r;
9331           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
9332           remotePointsNew[m].rank  = rrank;
9333         }
9334         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax - eStart)                            + (p - fStart);
9335         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
9336         remotePointsNew[m].rank  = rrank;
9337         ++m;
9338       } else if ((p >= fMax) && (p < fEnd)) {
9339         /* Interior hybrid faces add new faces and an edge */
9340         for (r = 0; r < 2; ++r, ++m) {
9341           localPointsNew[m]        = fStartNew     + (fMax - fStart)*3                                 + (cMax - cStart)*6                                + (p  - fMax)*2 + r;
9342           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;
9343           remotePointsNew[m].rank  = rrank;
9344         }
9345         localPointsNew[m]        = eStartNew     + (eMax - eStart)*2                            + (fMax - fStart)*3                                 + (cMax - cStart)*4                                + (eEnd - eMax)                                                           + (p  - fMax);
9346         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]);
9347         remotePointsNew[m].rank  = rrank;
9348         ++m;
9349       } else if ((p >= cStart) && (p < cMax)) {
9350         /* Interior cells add new cells, faces, edges, and a vertex */
9351         for (r = 0; r < 4; ++r, ++m) {
9352           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
9353           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
9354           remotePointsNew[m].rank  = rrank;
9355         }
9356         for (r = 0; r < 6; ++r, ++m) {
9357           localPointsNew[m]        = fStartNew     + (fMax - fStart)*3                                 + (p  - cStart)*6     + r;
9358           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1]- rfStart[n])*3 + (rp - rcStart[n])*6 + r;
9359           remotePointsNew[m].rank  = rrank;
9360         }
9361         for (r = 0; r < 4; ++r, ++m) {
9362           localPointsNew[m]        = eStartNew     + (eMax - eStart)*2                           + (fMax - fStart)*3                                 + (p  - cStart)*4 + r;
9363           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;
9364           remotePointsNew[m].rank  = rrank;
9365         }
9366         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax - eStart)                           + (fMax - fStart)                                 + (p  - cStart);
9367         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]);
9368         remotePointsNew[m].rank  = rrank;
9369         ++m;
9370       } else if ((p >= cMax) && (p < cEnd)) {
9371         /* Interior hybrid cells add new cells, faces and an edge */
9372         for (r = 0; r < 3; ++r, ++m) {
9373           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*4     + (p  - cMax)*3                            + r;
9374           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*4 + (rp - rdepthMaxOld[n*(depth+1)+depth])*3 + r;
9375           remotePointsNew[m].rank  = rrank;
9376         }
9377         for (r = 0; r < 3; ++r, ++m) {
9378           localPointsNew[m]        = fStartNew     + (fMax - fStart)*3                                 + (cMax - cStart)*6                                + (fEnd  - fMax)*2                                                                      + (p  - cMax)*3 + r;
9379           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;
9380           remotePointsNew[m].rank  = rrank;
9381         }
9382         localPointsNew[m]        = eStartNew     + (eMax - eStart)*2                           + (fMax - fStart)*3                                 + (cMax - cStart)*4                                + (eEnd  - eMax)                                                          + (fEnd  - fMax)                                                                      + (p  - cMax);
9383         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]);
9384         remotePointsNew[m].rank  = rrank;
9385         ++m;
9386       }
9387       break;
9388     case REFINER_HEX_3D:
9389     case REFINER_HYBRID_HEX_3D:
9390       if ((p >= vStart) && (p < vEnd)) {
9391         /* Interior vertices stay the same */
9392         localPointsNew[m]        = vStartNew     + (p  - vStart);
9393         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
9394         remotePointsNew[m].rank  = rrank;
9395         ++m;
9396       } else if ((p >= eStart) && (p < eMax)) {
9397         /* Interior edges add new edges and vertex */
9398         for (r = 0; r < 2; ++r, ++m) {
9399           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
9400           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
9401           remotePointsNew[m].rank  = rrank;
9402         }
9403         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
9404         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
9405         remotePointsNew[m].rank  = rrank;
9406         ++m;
9407       } else if ((p >= eMax) && (p < eEnd)) {
9408         /* Hybrid edges stay the same */
9409         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (p  - eMax);
9410         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]);
9411         remotePointsNew[m].rank  = rrank;
9412         ++m;
9413       } else if ((p >= fStart) && (p < fMax)) {
9414         /* Interior faces add new faces, edges, and vertex */
9415         for (r = 0; r < 4; ++r, ++m) {
9416           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
9417           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
9418           remotePointsNew[m].rank  = rrank;
9419         }
9420         for (r = 0; r < 4; ++r, ++m) {
9421           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*4     + r;
9422           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*4 + r;
9423           remotePointsNew[m].rank  = rrank;
9424         }
9425         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax                        - eStart)     + (p  - fStart);
9426         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
9427         remotePointsNew[m].rank  = rrank;
9428         ++m;
9429       } else if ((p >= fMax) && (p < fEnd)) {
9430         /* Hybrid faces add new faces and edges */
9431         for (r = 0; r < 2; ++r, ++m) {
9432           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (p  - fMax)*2                              + r;
9433           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;
9434           remotePointsNew[m].rank  = rrank;
9435         }
9436         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (p  - fMax);
9437         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]);
9438         remotePointsNew[m].rank  = rrank;
9439         ++m;
9440       } else if ((p >= cStart) && (p < cMax)) {
9441         /* Interior cells add new cells, faces, edges, and vertex */
9442         for (r = 0; r < 8; ++r, ++m) {
9443           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
9444           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
9445           remotePointsNew[m].rank  = rrank;
9446         }
9447         for (r = 0; r < 12; ++r, ++m) {
9448           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*12     + r;
9449           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*12 + r;
9450           remotePointsNew[m].rank  = rrank;
9451         }
9452         for (r = 0; r < 6; ++r, ++m) {
9453           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (p  - cStart)*6     + r;
9454           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;
9455           remotePointsNew[m].rank  = rrank;
9456         }
9457         for (r = 0; r < 1; ++r, ++m) {
9458           localPointsNew[m]        = vStartNew     + (eMax                        - eStart)     + (fMax                              - fStart)     + (p  - cStart)     + r;
9459           remotePointsNew[m].index = rvStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]) + r;
9460           remotePointsNew[m].rank  = rrank;
9461         }
9462       } else if ((p >= cMax) && (p < cEnd)) {
9463         /* Hybrid cells add new cells, faces, and edges */
9464         for (r = 0; r < 4; ++r, ++m) {
9465           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
9466           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
9467           remotePointsNew[m].rank  = rrank;
9468         }
9469         for (r = 0; r < 4; ++r, ++m) {
9470           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (fEnd                                          - fMax)*2                              + (p  - cMax)*4                            + r;
9471           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;
9472           remotePointsNew[m].rank  = rrank;
9473         }
9474         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (fEnd                                          - fMax)                              + (p  - cMax);
9475         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]);
9476         remotePointsNew[m].rank  = rrank;
9477         ++m;
9478       }
9479       break;
9480     default:
9481       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %D", refiner);
9482     }
9483   }
9484   if (m != numLeavesNew) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of leaf point %D should be %D", m, numLeavesNew);
9485   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
9486   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
9487   {
9488     PetscSFNode *rp, *rtmp;
9489     PetscInt    *lp, *idx, *ltmp, i;
9490 
9491     /* SF needs sorted leaves to correct calculate Gather */
9492     ierr = PetscMalloc1(numLeavesNew,&idx);CHKERRQ(ierr);
9493     ierr = PetscMalloc1(numLeavesNew, &lp);CHKERRQ(ierr);
9494     ierr = PetscMalloc1(numLeavesNew, &rp);CHKERRQ(ierr);
9495     for (i = 0; i < numLeavesNew; ++i) {
9496       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);
9497       idx[i] = i;
9498     }
9499     ierr = PetscSortIntWithPermutation(numLeavesNew, localPointsNew, idx);CHKERRQ(ierr);
9500     for (i = 0; i < numLeavesNew; ++i) {
9501       lp[i] = localPointsNew[idx[i]];
9502       rp[i] = remotePointsNew[idx[i]];
9503     }
9504     ltmp            = localPointsNew;
9505     localPointsNew  = lp;
9506     rtmp            = remotePointsNew;
9507     remotePointsNew = rp;
9508     ierr = PetscFree(idx);CHKERRQ(ierr);
9509     ierr = PetscFree(ltmp);CHKERRQ(ierr);
9510     ierr = PetscFree(rtmp);CHKERRQ(ierr);
9511   }
9512   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
9513   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
9514   ierr = PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
9515   PetscFunctionReturn(0);
9516 }
9517 
9518 static PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
9519 {
9520   PetscInt       numLabels, l;
9521   PetscInt       depth, newp, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r;
9522   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
9523   PetscErrorCode ierr;
9524 
9525   PetscFunctionBegin;
9526   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9527   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
9528   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9529   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
9530   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
9531   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
9532   ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
9533   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
9534   switch (refiner) {
9535   case REFINER_NOOP:
9536   case REFINER_SIMPLEX_1D:
9537   case REFINER_SIMPLEX_2D:
9538   case REFINER_SIMPLEX_TO_HEX_2D:
9539   case REFINER_HEX_2D:
9540   case REFINER_SIMPLEX_3D:
9541   case REFINER_HEX_3D:
9542   case REFINER_SIMPLEX_TO_HEX_3D:
9543     break;
9544   case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
9545   case REFINER_HYBRID_SIMPLEX_3D:
9546   case REFINER_HYBRID_HEX_3D:
9547     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
9548   case REFINER_HYBRID_SIMPLEX_2D:
9549   case REFINER_HYBRID_HEX_2D:
9550     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
9551   case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
9552     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
9553     break;
9554   default:
9555     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %D", refiner);
9556   }
9557   cMax = cMax < 0 ? cEnd : cMax;
9558   fMax = fMax < 0 ? fEnd : fMax;
9559   eMax = eMax < 0 ? eEnd : eMax;
9560   for (l = 0; l < numLabels; ++l) {
9561     DMLabel         label, labelNew;
9562     const char     *lname;
9563     PetscBool       isDepth;
9564     IS              valueIS;
9565     const PetscInt *values;
9566     PetscInt        defVal;
9567     PetscInt        numValues, val;
9568 
9569     ierr = DMGetLabelName(dm, l, &lname);CHKERRQ(ierr);
9570     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
9571     if (isDepth) continue;
9572     ierr = DMCreateLabel(rdm, lname);CHKERRQ(ierr);
9573     ierr = DMGetLabel(dm, lname, &label);CHKERRQ(ierr);
9574     ierr = DMGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
9575     ierr = DMLabelGetDefaultValue(label,&defVal);CHKERRQ(ierr);
9576     ierr = DMLabelSetDefaultValue(labelNew,defVal);CHKERRQ(ierr);
9577     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
9578     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
9579     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
9580     for (val = 0; val < numValues; ++val) {
9581       IS              pointIS;
9582       const PetscInt *points;
9583       PetscInt        numPoints, n;
9584 
9585       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
9586       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
9587       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
9588       /* Ensure refined label is created with same number of strata as
9589        * original (even if no entries here). */
9590       ierr = DMLabelAddStratum(labelNew, values[val]);CHKERRQ(ierr);
9591       for (n = 0; n < numPoints; ++n) {
9592         const PetscInt p = points[n];
9593         switch (refiner) {
9594         case REFINER_SIMPLEX_1D:
9595           if ((p >= vStart) && (p < vEnd)) {
9596             /* Old vertices stay the same */
9597             newp = vStartNew + (p - vStart);
9598             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9599           } else if ((p >= cStart) && (p < cEnd)) {
9600             /* Old cells add new cells and vertex */
9601             newp = vStartNew + (vEnd - vStart) + (p - cStart);
9602             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9603             for (r = 0; r < 2; ++r) {
9604               newp = cStartNew + (p - cStart)*2 + r;
9605               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9606             }
9607           }
9608           break;
9609         case REFINER_SIMPLEX_2D:
9610           if ((p >= vStart) && (p < vEnd)) {
9611             /* Old vertices stay the same */
9612             newp = vStartNew + (p - vStart);
9613             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9614           } else if ((p >= fStart) && (p < fEnd)) {
9615             /* Old faces add new faces and vertex */
9616             newp = vStartNew + (vEnd - vStart) + (p - fStart);
9617             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9618             for (r = 0; r < 2; ++r) {
9619               newp = fStartNew + (p - fStart)*2 + r;
9620               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9621             }
9622           } else if ((p >= cStart) && (p < cEnd)) {
9623             /* Old cells add new cells and interior faces */
9624             for (r = 0; r < 4; ++r) {
9625               newp = cStartNew + (p - cStart)*4 + r;
9626               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9627             }
9628             for (r = 0; r < 3; ++r) {
9629               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
9630               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9631             }
9632           }
9633           break;
9634         case REFINER_HYBRID_SIMPLEX_TO_HEX_2D:
9635         case REFINER_SIMPLEX_TO_HEX_2D:
9636           if ((p >= vStart) && (p < vEnd)) {
9637             /* Old vertices stay the same */
9638             newp = vStartNew + (p - vStart);
9639             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9640           } else if ((p >= fStart) && (p < fEnd)) {
9641             /* Old faces add new faces and vertex */
9642             newp = vStartNew + (vEnd - vStart) + (p - fStart);
9643             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9644             for (r = 0; r < 2; ++r) {
9645               newp = fStartNew + (p - fStart)*2 + r;
9646               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9647             }
9648           } else if ((p >= cStart) && (p < cMax)) {
9649             /* Old cells add new cells, interior faces, and a vertex */
9650             for (r = 0; r < 3; ++r) {
9651               newp = cStartNew + (p - cStart)*3 + r;
9652               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9653             }
9654             for (r = 0; r < 3; ++r) {
9655               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
9656               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9657             }
9658             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + p;
9659             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9660           } else if ((p >= cMax) && (p < cEnd)) {
9661             /* Old hybrid cells add new cells, interior faces, and a vertex */
9662             for (r = 0; r < 4; ++r) {
9663               newp = cStartNew + (cMax - cStart)*3 + (p - cMax)*4 + r;
9664               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9665             }
9666             for (r = 0; r < 4; ++r) {
9667               newp = fStartNew + (fEnd - fStart)*2 + (cMax - cStart)*3 + (p - cMax)*4 + r;
9668               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9669             }
9670             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + p;
9671             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9672           }
9673           break;
9674         case REFINER_HEX_2D:
9675           if ((p >= vStart) && (p < vEnd)) {
9676             /* Old vertices stay the same */
9677             newp = vStartNew + (p - vStart);
9678             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9679           } else if ((p >= fStart) && (p < fEnd)) {
9680             /* Old faces add new faces and vertex */
9681             newp = vStartNew + (vEnd - vStart) + (p - fStart);
9682             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9683             for (r = 0; r < 2; ++r) {
9684               newp = fStartNew + (p - fStart)*2 + r;
9685               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9686             }
9687           } else if ((p >= cStart) && (p < cEnd)) {
9688             /* Old cells add new cells and interior faces and vertex */
9689             for (r = 0; r < 4; ++r) {
9690               newp = cStartNew + (p - cStart)*4 + r;
9691               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9692             }
9693             for (r = 0; r < 4; ++r) {
9694               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
9695               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9696             }
9697             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
9698             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9699           }
9700           break;
9701         case REFINER_HYBRID_SIMPLEX_2D:
9702           if ((p >= vStart) && (p < vEnd)) {
9703             /* Old vertices stay the same */
9704             newp = vStartNew + (p - vStart);
9705             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9706           } else if ((p >= fStart) && (p < fMax)) {
9707             /* Old interior faces add new faces and vertex */
9708             newp = vStartNew + (vEnd - vStart) + (p - fStart);
9709             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9710             for (r = 0; r < 2; ++r) {
9711               newp = fStartNew + (p - fStart)*2 + r;
9712               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9713             }
9714           } else if ((p >= fMax) && (p < fEnd)) {
9715             /* Old hybrid faces stay the same */
9716             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
9717             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9718           } else if ((p >= cStart) && (p < cMax)) {
9719             /* Old interior cells add new cells and interior faces */
9720             for (r = 0; r < 4; ++r) {
9721               newp = cStartNew + (p - cStart)*4 + r;
9722               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9723             }
9724             for (r = 0; r < 3; ++r) {
9725               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
9726               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9727             }
9728           } else if ((p >= cMax) && (p < cEnd)) {
9729             /* Old hybrid cells add new cells and hybrid face */
9730             for (r = 0; r < 2; ++r) {
9731               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
9732               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9733             }
9734             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
9735             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9736           }
9737           break;
9738         case REFINER_HYBRID_HEX_2D:
9739           if ((p >= vStart) && (p < vEnd)) {
9740             /* Old vertices stay the same */
9741             newp = vStartNew + (p - vStart);
9742             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9743           } else if ((p >= fStart) && (p < fMax)) {
9744             /* Old interior faces add new faces and vertex */
9745             newp = vStartNew + (vEnd - vStart) + (p - fStart);
9746             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9747             for (r = 0; r < 2; ++r) {
9748               newp = fStartNew + (p - fStart)*2 + r;
9749               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9750             }
9751           } else if ((p >= fMax) && (p < fEnd)) {
9752             /* Old hybrid faces stay the same */
9753             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
9754             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9755           } else if ((p >= cStart) && (p < cMax)) {
9756             /* Old interior cells add new cells, interior faces, and vertex */
9757             for (r = 0; r < 4; ++r) {
9758               newp = cStartNew + (p - cStart)*4 + r;
9759               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9760             }
9761             for (r = 0; r < 4; ++r) {
9762               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
9763               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9764             }
9765             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
9766             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9767           } else if ((p >= cMax) && (p < cEnd)) {
9768             /* Old hybrid cells add new cells and hybrid face */
9769             for (r = 0; r < 2; ++r) {
9770               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
9771               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9772             }
9773             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (p - cMax);
9774             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9775           }
9776           break;
9777         case REFINER_SIMPLEX_3D:
9778           if ((p >= vStart) && (p < vEnd)) {
9779             /* Old vertices stay the same */
9780             newp = vStartNew + (p - vStart);
9781             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9782           } else if ((p >= eStart) && (p < eEnd)) {
9783             /* Old edges add new edges and vertex */
9784             for (r = 0; r < 2; ++r) {
9785               newp = eStartNew + (p - eStart)*2 + r;
9786               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9787             }
9788             newp = vStartNew + (vEnd - vStart) + (p - eStart);
9789             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9790           } else if ((p >= fStart) && (p < fEnd)) {
9791             /* Old faces add new faces and edges */
9792             for (r = 0; r < 4; ++r) {
9793               newp = fStartNew + (p - fStart)*4 + r;
9794               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9795             }
9796             for (r = 0; r < 3; ++r) {
9797               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
9798               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9799             }
9800           } else if ((p >= cStart) && (p < cEnd)) {
9801             /* Old cells add new cells and interior faces and edges */
9802             for (r = 0; r < 8; ++r) {
9803               newp = cStartNew + (p - cStart)*8 + r;
9804               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9805             }
9806             for (r = 0; r < 8; ++r) {
9807               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*8 + r;
9808               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9809             }
9810             for (r = 0; r < 1; ++r) {
9811               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*1 + r;
9812               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9813             }
9814           }
9815           break;
9816         case REFINER_HYBRID_SIMPLEX_TO_HEX_3D:
9817         case REFINER_SIMPLEX_TO_HEX_3D:
9818           if ((p >= vStart) && (p < vEnd)) {
9819             /* Old vertices stay the same */
9820             newp = vStartNew + (p - vStart);
9821             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9822           } else if ((p >= eStart) && (p < eMax)) {
9823             /* Interior edges add new edges and vertex */
9824             for (r = 0; r < 2; ++r) {
9825               newp = eStartNew + (p - eStart)*2 + r;
9826               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9827             }
9828             newp = vStartNew + (vEnd - vStart) + (p - eStart);
9829             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9830           } else if ((p >= eMax) && (p < eEnd)) {
9831             /* Hybrid edges stay the same */
9832             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + p - eMax;
9833             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9834           } else if ((p >= fStart) && (p < fMax)) {
9835             /* Old faces add new faces, edges and a vertex */
9836             for (r = 0; r < 3; ++r) {
9837               newp = fStartNew + (p - fStart)*3 + r;
9838               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9839             }
9840             for (r = 0; r < 3; ++r) {
9841               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
9842               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9843             }
9844           } else if ((p >= fMax) && (p < fEnd)) {
9845             /* Old hybrid faces add new faces and an edge */
9846             for (r = 0; r < 2; ++r) {
9847               newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (p - fMax)*2 + r;
9848               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9849             }
9850             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (p - fMax);
9851             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9852           } else if ((p >= cStart) && (p < cMax)) {
9853             /* Old cells add new cells and interior faces and edges and a vertex */
9854             for (r = 0; r < 4; ++r) {
9855               newp = cStartNew + (p - cStart)*4 + r;
9856               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9857             }
9858             for (r = 0; r < 6; ++r) {
9859               newp = fStartNew + (fMax - fStart)*3 + (p - cStart)*6 + r;
9860               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9861             }
9862             for (r = 0; r < 4; ++r) {
9863               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart)*4 + r;
9864               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9865             }
9866             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + p - cStart;
9867             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9868           } else if ((p >= cMax) && (p < cEnd)) {
9869             /* Old hybrid cells add new cells and interior faces and an edge */
9870             for (r = 0; r < 3; ++r) {
9871               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*3 + r;
9872               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9873             }
9874             for (r = 0; r < 3; ++r) {
9875               newp = fStartNew + (fMax - fStart)*3 + (cMax - cStart)*6 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
9876               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9877             }
9878             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart)*4 + (eEnd - eMax) + (fEnd - fMax) + p - cMax;
9879             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9880           }
9881           break;
9882         case REFINER_HYBRID_SIMPLEX_3D:
9883           if ((p >= vStart) && (p < vEnd)) {
9884             /* Interior vertices stay the same */
9885             newp = vStartNew + (p - vStart);
9886             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9887           } else if ((p >= eStart) && (p < eMax)) {
9888             /* Interior edges add new edges and vertex */
9889             for (r = 0; r < 2; ++r) {
9890               newp = eStartNew + (p - eStart)*2 + r;
9891               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9892             }
9893             newp = vStartNew + (vEnd - vStart) + (p - eStart);
9894             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9895           } else if ((p >= eMax) && (p < eEnd)) {
9896             /* Hybrid edges stay the same */
9897             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - eMax);
9898             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9899           } else if ((p >= fStart) && (p < fMax)) {
9900             /* Interior faces add new faces and edges */
9901             for (r = 0; r < 4; ++r) {
9902               newp = fStartNew + (p - fStart)*4 + r;
9903               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9904             }
9905             for (r = 0; r < 3; ++r) {
9906               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
9907               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9908             }
9909           } else if ((p >= fMax) && (p < fEnd)) {
9910             /* Hybrid faces add new faces and edges */
9911             for (r = 0; r < 2; ++r) {
9912               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (p - fMax)*2 + r;
9913               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9914             }
9915             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - fMax);
9916             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9917           } else if ((p >= cStart) && (p < cMax)) {
9918             /* Interior cells add new cells, faces, and edges */
9919             for (r = 0; r < 8; ++r) {
9920               newp = cStartNew + (p - cStart)*8 + r;
9921               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9922             }
9923             for (r = 0; r < 8; ++r) {
9924               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*8 + r;
9925               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9926             }
9927             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart);
9928             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9929           } else if ((p >= cMax) && (p < cEnd)) {
9930             /* Hybrid cells add new cells and faces */
9931             for (r = 0; r < 4; ++r) {
9932               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
9933               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9934             }
9935             for (r = 0; r < 3; ++r) {
9936               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
9937               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9938             }
9939           }
9940           break;
9941         case REFINER_HEX_3D:
9942           if ((p >= vStart) && (p < vEnd)) {
9943             /* Old vertices stay the same */
9944             newp = vStartNew + (p - vStart);
9945             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9946           } else if ((p >= eStart) && (p < eEnd)) {
9947             /* Old edges add new edges and vertex */
9948             for (r = 0; r < 2; ++r) {
9949               newp = eStartNew + (p - eStart)*2 + r;
9950               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9951             }
9952             newp = vStartNew + (vEnd - vStart) + (p - eStart);
9953             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9954           } else if ((p >= fStart) && (p < fEnd)) {
9955             /* Old faces add new faces, edges, and vertex */
9956             for (r = 0; r < 4; ++r) {
9957               newp = fStartNew + (p - fStart)*4 + r;
9958               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9959             }
9960             for (r = 0; r < 4; ++r) {
9961               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*4 + r;
9962               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9963             }
9964             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (p - fStart);
9965             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9966           } else if ((p >= cStart) && (p < cEnd)) {
9967             /* Old cells add new cells, faces, edges, and vertex */
9968             for (r = 0; r < 8; ++r) {
9969               newp = cStartNew + (p - cStart)*8 + r;
9970               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9971             }
9972             for (r = 0; r < 12; ++r) {
9973               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*12 + r;
9974               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9975             }
9976             for (r = 0; r < 6; ++r) {
9977               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (p - cStart)*6 + r;
9978               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9979             }
9980             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (p - cStart);
9981             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9982           }
9983           break;
9984         case REFINER_HYBRID_HEX_3D:
9985           if ((p >= vStart) && (p < vEnd)) {
9986             /* Interior vertices stay the same */
9987             newp = vStartNew + (p - vStart);
9988             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9989           } else if ((p >= eStart) && (p < eMax)) {
9990             /* Interior edges add new edges and vertex */
9991             for (r = 0; r < 2; ++r) {
9992               newp = eStartNew + (p - eStart)*2 + r;
9993               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9994             }
9995             newp = vStartNew + (vEnd - vStart) + (p - eStart);
9996             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
9997           } else if ((p >= eMax) && (p < eEnd)) {
9998             /* Hybrid edges stay the same */
9999             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - eMax);
10000             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10001           } else if ((p >= fStart) && (p < fMax)) {
10002             /* Interior faces add new faces, edges, and vertex */
10003             for (r = 0; r < 4; ++r) {
10004               newp = fStartNew + (p - fStart)*4 + r;
10005               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10006             }
10007             for (r = 0; r < 4; ++r) {
10008               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*4 + r;
10009               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10010             }
10011             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (p - fStart);
10012             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10013           } else if ((p >= fMax) && (p < fEnd)) {
10014             /* Hybrid faces add new faces and edges */
10015             for (r = 0; r < 2; ++r) {
10016               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (p - fMax)*2 + r;
10017               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10018             }
10019             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - fMax);
10020             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10021           } else if ((p >= cStart) && (p < cMax)) {
10022             /* Interior cells add new cells, faces, edges, and vertex */
10023             for (r = 0; r < 8; ++r) {
10024               newp = cStartNew + (p - cStart)*8 + r;
10025               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10026             }
10027             for (r = 0; r < 12; ++r) {
10028               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*12 + r;
10029               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10030             }
10031             for (r = 0; r < 6; ++r) {
10032               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (p - cStart)*6 + r;
10033               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10034             }
10035             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (p - cStart);
10036             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10037           } else if ((p >= cMax) && (p < cEnd)) {
10038             /* Hybrid cells add new cells, faces, and edges */
10039             for (r = 0; r < 4; ++r) {
10040               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
10041               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10042             }
10043             for (r = 0; r < 4; ++r) {
10044               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (p - cMax)*4 + r;
10045               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10046             }
10047             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (fEnd - fMax) + (p - cMax);
10048             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
10049           }
10050           break;
10051         default:
10052           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %D", refiner);
10053         }
10054       }
10055       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
10056       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
10057     }
10058     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
10059     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
10060     if (0) {
10061       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
10062     }
10063   }
10064   PetscFunctionReturn(0);
10065 }
10066 
10067 /* This will only work for interpolated meshes */
10068 PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
10069 {
10070   DM             rdm;
10071   PetscInt      *depthSize;
10072   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
10073   PetscErrorCode ierr;
10074 
10075   PetscFunctionBegin;
10076   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
10077   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
10078   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
10079   ierr = DMSetDimension(rdm, dim);CHKERRQ(ierr);
10080   /* Calculate number of new points of each depth */
10081   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
10082   if (depth >= 0 && dim != depth) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Mesh must be interpolated for regular refinement");
10083   ierr = PetscMalloc1(depth+1, &depthSize);CHKERRQ(ierr);
10084   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
10085   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
10086   /* Step 1: Set chart */
10087   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
10088   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
10089   /* Step 2: Set cone/support sizes (automatically stratifies) */
10090   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
10091   /* Step 3: Setup refined DM */
10092   ierr = DMSetUp(rdm);CHKERRQ(ierr);
10093   /* Step 4: Set cones and supports (automatically symmetrizes) */
10094   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
10095   /* Step 5: Create pointSF */
10096   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
10097   /* Step 6: Create labels */
10098   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
10099   /* Step 7: Set coordinates */
10100   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
10101   ierr = PetscFree(depthSize);CHKERRQ(ierr);
10102 
10103   *dmRefined = rdm;
10104   PetscFunctionReturn(0);
10105 }
10106 
10107 /*@
10108   DMPlexCreateCoarsePointIS - Creates an IS covering the coarse DM chart with the fine points as data
10109 
10110   Input Parameter:
10111 . dm - The coarse DM
10112 
10113   Output Parameter:
10114 . fpointIS - The IS of all the fine points which exist in the original coarse mesh
10115 
10116   Level: developer
10117 
10118 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexCreateSubpointIS()
10119 @*/
10120 PetscErrorCode DMPlexCreateCoarsePointIS(DM dm, IS *fpointIS)
10121 {
10122   CellRefiner    cellRefiner;
10123   PetscInt      *depthSize, *fpoints;
10124   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
10125   PetscInt       depth, pStart, pEnd, p, vStart, vEnd, v;
10126   PetscErrorCode ierr;
10127 
10128   PetscFunctionBegin;
10129   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
10130   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
10131   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10132   ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr);
10133   ierr = PetscMalloc1(depth+1, &depthSize);CHKERRQ(ierr);
10134   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
10135   if (cellRefiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
10136   ierr = PetscMalloc1(pEnd-pStart,&fpoints);CHKERRQ(ierr);
10137   for (p = 0; p < pEnd-pStart; ++p) fpoints[p] = -1;
10138   switch (cellRefiner) {
10139   case REFINER_SIMPLEX_1D:
10140   case REFINER_SIMPLEX_2D:
10141   case REFINER_HYBRID_SIMPLEX_2D:
10142   case REFINER_HEX_2D:
10143   case REFINER_HYBRID_HEX_2D:
10144   case REFINER_SIMPLEX_3D:
10145   case REFINER_HYBRID_SIMPLEX_3D:
10146   case REFINER_HEX_3D:
10147   case REFINER_HYBRID_HEX_3D:
10148     for (v = vStart; v < vEnd; ++v) fpoints[v-pStart] = vStartNew + (v - vStart);
10149     break;
10150   default:
10151     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %D", cellRefiner);
10152   }
10153   ierr = ISCreateGeneral(PETSC_COMM_SELF, pEnd-pStart, fpoints, PETSC_OWN_POINTER, fpointIS);CHKERRQ(ierr);
10154   ierr = PetscFree(depthSize);CHKERRQ(ierr);
10155   PetscFunctionReturn(0);
10156 }
10157 
10158 /*@
10159   DMPlexSetRefinementUniform - Set the flag for uniform refinement
10160 
10161   Input Parameters:
10162 + dm - The DM
10163 - refinementUniform - The flag for uniform refinement
10164 
10165   Level: developer
10166 
10167 .seealso: DMRefine(), DMPlexGetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
10168 @*/
10169 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
10170 {
10171   DM_Plex *mesh = (DM_Plex*) dm->data;
10172 
10173   PetscFunctionBegin;
10174   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10175   mesh->refinementUniform = refinementUniform;
10176   PetscFunctionReturn(0);
10177 }
10178 
10179 /*@
10180   DMPlexGetRefinementUniform - Retrieve the flag for uniform refinement
10181 
10182   Input Parameter:
10183 . dm - The DM
10184 
10185   Output Parameter:
10186 . refinementUniform - The flag for uniform refinement
10187 
10188   Level: developer
10189 
10190 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
10191 @*/
10192 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
10193 {
10194   DM_Plex *mesh = (DM_Plex*) dm->data;
10195 
10196   PetscFunctionBegin;
10197   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10198   PetscValidPointer(refinementUniform,  2);
10199   *refinementUniform = mesh->refinementUniform;
10200   PetscFunctionReturn(0);
10201 }
10202 
10203 /*@
10204   DMPlexSetRefinementLimit - Set the maximum cell volume for refinement
10205 
10206   Input Parameters:
10207 + dm - The DM
10208 - refinementLimit - The maximum cell volume in the refined mesh
10209 
10210   Level: developer
10211 
10212 .seealso: DMRefine(), DMPlexGetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
10213 @*/
10214 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
10215 {
10216   DM_Plex *mesh = (DM_Plex*) dm->data;
10217 
10218   PetscFunctionBegin;
10219   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10220   mesh->refinementLimit = refinementLimit;
10221   PetscFunctionReturn(0);
10222 }
10223 
10224 /*@
10225   DMPlexGetRefinementLimit - Retrieve the maximum cell volume for refinement
10226 
10227   Input Parameter:
10228 . dm - The DM
10229 
10230   Output Parameter:
10231 . refinementLimit - The maximum cell volume in the refined mesh
10232 
10233   Level: developer
10234 
10235 .seealso: DMRefine(), DMPlexSetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
10236 @*/
10237 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
10238 {
10239   DM_Plex *mesh = (DM_Plex*) dm->data;
10240 
10241   PetscFunctionBegin;
10242   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10243   PetscValidPointer(refinementLimit,  2);
10244   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
10245   *refinementLimit = mesh->refinementLimit;
10246   PetscFunctionReturn(0);
10247 }
10248 
10249 /*@
10250   DMPlexSetRefinementFunction - Set the function giving the maximum cell volume for refinement
10251 
10252   Input Parameters:
10253 + dm - The DM
10254 - refinementFunc - Function giving the maximum cell volume in the refined mesh
10255 
10256   Note: The calling sequence is refinementFunc(coords, limit)
10257 $ coords - Coordinates of the current point, usually a cell centroid
10258 $ limit  - The maximum cell volume for a cell containing this point
10259 
10260   Level: developer
10261 
10262 .seealso: DMRefine(), DMPlexGetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
10263 @*/
10264 PetscErrorCode DMPlexSetRefinementFunction(DM dm, PetscErrorCode (*refinementFunc)(const PetscReal [], PetscReal *))
10265 {
10266   DM_Plex *mesh = (DM_Plex*) dm->data;
10267 
10268   PetscFunctionBegin;
10269   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10270   mesh->refinementFunc = refinementFunc;
10271   PetscFunctionReturn(0);
10272 }
10273 
10274 /*@
10275   DMPlexGetRefinementFunction - Get the function giving the maximum cell volume for refinement
10276 
10277   Input Parameter:
10278 . dm - The DM
10279 
10280   Output Parameter:
10281 . refinementFunc - Function giving the maximum cell volume in the refined mesh
10282 
10283   Note: The calling sequence is refinementFunc(coords, limit)
10284 $ coords - Coordinates of the current point, usually a cell centroid
10285 $ limit  - The maximum cell volume for a cell containing this point
10286 
10287   Level: developer
10288 
10289 .seealso: DMRefine(), DMPlexSetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
10290 @*/
10291 PetscErrorCode DMPlexGetRefinementFunction(DM dm, PetscErrorCode (**refinementFunc)(const PetscReal [], PetscReal *))
10292 {
10293   DM_Plex *mesh = (DM_Plex*) dm->data;
10294 
10295   PetscFunctionBegin;
10296   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10297   PetscValidPointer(refinementFunc,  2);
10298   *refinementFunc = mesh->refinementFunc;
10299   PetscFunctionReturn(0);
10300 }
10301 
10302 PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
10303 {
10304   PetscInt       dim, cStart, cEnd, coneSize, cMax, fMax;
10305   PetscErrorCode ierr;
10306 
10307   PetscFunctionBegin;
10308   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
10309   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10310   if (cEnd <= cStart) {*cellRefiner = REFINER_NOOP; PetscFunctionReturn(0);}
10311   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
10312   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, NULL, NULL);CHKERRQ(ierr);
10313   switch (dim) {
10314   case 1:
10315     switch (coneSize) {
10316     case 2:
10317       *cellRefiner = REFINER_SIMPLEX_1D;
10318       break;
10319     default:
10320       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %D in dimension %D for cell refiner", coneSize, dim);
10321     }
10322     break;
10323   case 2:
10324     switch (coneSize) {
10325     case 3:
10326       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_2D;
10327       else *cellRefiner = REFINER_SIMPLEX_2D;
10328       break;
10329     case 4:
10330       if (cMax >= 0 && fMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_2D;
10331       else *cellRefiner = REFINER_HEX_2D;
10332       break;
10333     default:
10334       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %D in dimension %D for cell refiner", coneSize, dim);
10335     }
10336     break;
10337   case 3:
10338     switch (coneSize) {
10339     case 4:
10340       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_3D;
10341       else *cellRefiner = REFINER_SIMPLEX_3D;
10342       break;
10343     case 5:
10344       if (cMax == 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_3D;
10345       else SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %D in dimension %D for cell refiner", coneSize, dim);
10346       break;
10347     case 6:
10348       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_3D;
10349       else *cellRefiner = REFINER_HEX_3D;
10350       break;
10351     default:
10352       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %D in dimension %D for cell refiner", coneSize, dim);
10353     }
10354     break;
10355   default:
10356     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %D for cell refiner", dim);
10357   }
10358   PetscFunctionReturn(0);
10359 }
10360 
10361 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
10362 {
10363   PetscBool      isUniform;
10364   PetscErrorCode ierr;
10365 
10366   PetscFunctionBegin;
10367   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
10368   if (isUniform) {
10369     CellRefiner cellRefiner;
10370     PetscBool   localized;
10371 
10372     ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
10373     ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr);
10374     ierr = DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
10375     ierr = DMCopyBoundary(dm, *dmRefined);CHKERRQ(ierr);
10376     if (localized) {ierr = DMLocalizeCoordinates(*dmRefined);CHKERRQ(ierr);}
10377   } else {
10378     ierr = DMPlexRefine_Internal(dm, NULL, dmRefined);CHKERRQ(ierr);
10379   }
10380   PetscFunctionReturn(0);
10381 }
10382 
10383 PetscErrorCode DMRefineHierarchy_Plex(DM dm, PetscInt nlevels, DM dmRefined[])
10384 {
10385   DM             cdm = dm;
10386   PetscInt       r;
10387   PetscBool      isUniform, localized;
10388   PetscErrorCode ierr;
10389 
10390   PetscFunctionBegin;
10391   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
10392   ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
10393   if (isUniform) {
10394     for (r = 0; r < nlevels; ++r) {
10395       CellRefiner cellRefiner;
10396 
10397       ierr = DMPlexGetCellRefiner_Internal(cdm, &cellRefiner);CHKERRQ(ierr);
10398       ierr = DMPlexRefineUniform_Internal(cdm, cellRefiner, &dmRefined[r]);CHKERRQ(ierr);
10399       ierr = DMCopyBoundary(cdm, dmRefined[r]);CHKERRQ(ierr);
10400       if (localized) {ierr = DMLocalizeCoordinates(dmRefined[r]);CHKERRQ(ierr);}
10401       ierr = DMSetCoarseDM(dmRefined[r], cdm);CHKERRQ(ierr);
10402       ierr = DMPlexSetRegularRefinement(dmRefined[r], PETSC_TRUE);CHKERRQ(ierr);
10403       cdm  = dmRefined[r];
10404     }
10405   } else {
10406     for (r = 0; r < nlevels; ++r) {
10407       ierr = DMRefine(cdm, PetscObjectComm((PetscObject) dm), &dmRefined[r]);CHKERRQ(ierr);
10408       ierr = DMCopyBoundary(cdm, dmRefined[r]);CHKERRQ(ierr);
10409       if (localized) {ierr = DMLocalizeCoordinates(dmRefined[r]);CHKERRQ(ierr);}
10410       ierr = DMSetCoarseDM(dmRefined[r], cdm);CHKERRQ(ierr);
10411       cdm  = dmRefined[r];
10412     }
10413   }
10414   PetscFunctionReturn(0);
10415 }
10416