xref: /petsc/src/dm/impls/plex/plexrefine.c (revision 5789d1f5dcd14af9aabfc1f6790ca7b6d7aa2307)
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   default:
115     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
116   }
117   if (v0) {*v0 = v; *jac = j; *invjac = invj;}
118   PetscFunctionReturn(0);
119 }
120 
121 PetscErrorCode CellRefinerRestoreAffineTransforms_Internal(CellRefiner refiner, PetscInt *numSubcells, PetscReal *v0[], PetscReal *jac[], PetscReal *invjac[])
122 {
123   PetscErrorCode ierr;
124 
125   PetscFunctionBegin;
126   ierr = PetscFree3(*v0,*jac,*invjac);CHKERRQ(ierr);
127   PetscFunctionReturn(0);
128 }
129 
130 /* Should this be here or in the DualSpace somehow? */
131 PetscErrorCode CellRefinerInCellTest_Internal(CellRefiner refiner, const PetscReal point[], PetscBool *inside)
132 {
133   PetscReal sum = 0.0;
134   PetscInt  d;
135 
136   PetscFunctionBegin;
137   *inside = PETSC_TRUE;
138   switch (refiner) {
139   case REFINER_NOOP: break;
140   case REFINER_SIMPLEX_2D:
141     for (d = 0; d < 2; ++d) {
142       if (point[d] < -1.0) {*inside = PETSC_FALSE; break;}
143       sum += point[d];
144     }
145     if (sum > 1.0e-10) {*inside = PETSC_FALSE; break;}
146     break;
147   case REFINER_HEX_2D:
148     for (d = 0; d < 2; ++d) if ((point[d] < -1.00000000001) || (point[d] > 1.000000000001)) {*inside = PETSC_FALSE; break;}
149     break;
150   default:
151     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
152   }
153   PetscFunctionReturn(0);
154 }
155 
156 static PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
157 {
158   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
159   PetscErrorCode ierr;
160 
161   PetscFunctionBegin;
162   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
163   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
164   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
165   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
166   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
167   switch (refiner) {
168   case REFINER_NOOP:
169     break;
170   case REFINER_SIMPLEX_1D:
171     depthSize[0] = vEnd - vStart + cEnd - cStart;         /* Add a vertex on every cell. */
172     depthSize[1] = 2*(cEnd - cStart);                     /* Split every cell in 2. */
173     break;
174   case REFINER_SIMPLEX_2D:
175     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
176     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
177     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
178     break;
179   case REFINER_HYBRID_SIMPLEX_2D:
180     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
181     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
182     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
183     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 */
184     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
185     break;
186   case REFINER_SIMPLEX_TO_HEX_2D:
187     depthSize[0] = vEnd - vStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every face and cell */
188     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart);         /* Every face is split into 2 faces and 3 faces are added for each cell */
189     depthSize[2] = 3*(cEnd - cStart);                             /* Every cell split into 3 cells */
190     break;
191   case REFINER_HEX_2D:
192     depthSize[0] = vEnd - vStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every face and cell */
193     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
194     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
195     break;
196   case REFINER_HYBRID_HEX_2D:
197     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
198     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
199     /* Quadrilateral */
200     depthSize[0] = vEnd - vStart + fMax - fStart + cMax - cStart;                 /* Add a vertex on every face and cell */
201     depthSize[1] = 2*(fMax - fStart) + 4*(cMax - cStart);                         /* Every face is split into 2 faces, and 4 faces are added for each cell */
202     depthSize[2] = 4*(cMax - cStart);                                             /* Every cell split into 4 cells */
203     /* Segment Prisms */
204     depthSize[0] += 0;                                                            /* No hybrid vertices */
205     depthSize[1] +=   (fEnd - fMax)  +   (cEnd - cMax);                           /* Every hybrid face remains and 1 faces is added for each hybrid cell */
206     depthSize[2] += 2*(cEnd - cMax);                                              /* Every hybrid cell split into 2 cells */
207     break;
208   case REFINER_SIMPLEX_3D:
209     depthSize[0] =    vEnd - vStart  +    eEnd - eStart;                    /* Add a vertex on every edge */
210     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 */
211     depthSize[2] = 4*(fEnd - fStart) + 8*(cEnd - cStart);                   /* Every face split into 4 faces and 8 faces are added for each cell */
212     depthSize[3] = 8*(cEnd - cStart);                                       /* Every cell split into 8 cells */
213     break;
214   case REFINER_HYBRID_SIMPLEX_3D:
215     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
216     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
217     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
218     /* Tetrahedra */
219     depthSize[0]  =    vEnd - vStart  +    eMax - eStart;                    /* Add a vertex on every interior edge */
220     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 */
221     depthSize[2]  = 4*(fMax - fStart) + 8*(cMax - cStart);                   /* Every interior face split into 4 faces, 8 faces added for each interior cell */
222     depthSize[3]  = 8*(cMax - cStart);                                       /* Every interior cell split into 8 cells */
223     /* Triangular Prisms */
224     depthSize[0] += 0;                                                       /* No hybrid vertices */
225     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax);                     /* Every hybrid edge remains, 1 edge for every hybrid face */
226     depthSize[2] += 2*(fEnd - fMax)   + 3*(cEnd - cMax);                     /* Every hybrid face split into 2 faces and 3 faces are added for each hybrid cell */
227     depthSize[3] += 4*(cEnd - cMax);                                         /* Every hybrid cell split into 4 cells */
228     break;
229   case REFINER_SIMPLEX_TO_HEX_3D:
230     depthSize[0] = vEnd - vStart + fEnd - fStart + eEnd - eStart + cEnd - cStart; /* Add a vertex on every face, edge and cell */
231     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 */
232     depthSize[2] = 3*(fEnd - fStart) + 6*(cEnd - cStart);                         /* Every face is split into 3 faces and 6 faces are added for each cell */
233     depthSize[3] = 4*(cEnd - cStart);                                             /* Every cell split into 4 cells */
234     break;
235   case REFINER_HEX_3D:
236     depthSize[0] = vEnd - vStart + eEnd - eStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every edge, face and cell */
237     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 */
238     depthSize[2] = 4*(fEnd - fStart) + 12*(cEnd - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
239     depthSize[3] = 8*(cEnd - cStart);                                             /* Every cell split into 8 cells */
240     break;
241   case REFINER_HYBRID_HEX_3D:
242     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
243     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
244     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
245     /* Hexahedra */
246     depthSize[0] = vEnd - vStart + eMax - eStart + fMax - fStart + cMax - cStart; /* Add a vertex on every edge, face and cell */
247     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 */
248     depthSize[2] = 4*(fMax - fStart) + 12*(cMax - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
249     depthSize[3] = 8*(cMax - cStart);                                             /* Every cell split into 8 cells */
250     /* Quadrilateral Prisms */
251     depthSize[0] += 0;                                                            /* No hybrid vertices */
252     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax)   +   (cEnd - cMax);      /* Every hybrid edge remains, 1 edge for every hybrid face and hybrid cell */
253     depthSize[2] += 2*(fEnd - fMax)   + 4*(cEnd - cMax);                          /* Every hybrid face split into 2 faces and 4 faces are added for each hybrid cell */
254     depthSize[3] += 4*(cEnd - cMax);                                              /* Every hybrid cell split into 4 cells */
255     break;
256   default:
257     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
258   }
259   PetscFunctionReturn(0);
260 }
261 
262 /* Return triangle edge for orientation o, if it is r for o == 0 */
263 PETSC_STATIC_INLINE PetscInt GetTriEdge_Static(PetscInt o, PetscInt r) {
264   return (o < 0 ? 2-(o+r) : o+r)%3;
265 }
266 PETSC_STATIC_INLINE PetscInt GetTriEdgeInverse_Static(PetscInt o, PetscInt s) {
267   return (o < 0 ? 2-(o+s) : 3+s-o)%3;
268 }
269 
270 /* Return triangle subface for orientation o, if it is r for o == 0 */
271 PETSC_STATIC_INLINE PetscInt GetTriSubface_Static(PetscInt o, PetscInt r) {
272   return (o < 0 ? 3-(o+r) : o+r)%3;
273 }
274 PETSC_STATIC_INLINE PetscInt GetTriSubfaceInverse_Static(PetscInt o, PetscInt s) {
275   return (o < 0 ? 3-(o+s) : 3+s-o)%3;
276 }
277 
278 /* Return the interior edge number connecting the midpoints of the triangle edges r
279    and r+1 in the transitive closure for triangle orientation o */
280 PETSC_STATIC_INLINE PetscInt GetTriMidEdge_Static(PetscInt o, PetscInt r) {
281   return (o < 0 ? 1-(o+r) : o+r)%3;
282 }
283 PETSC_STATIC_INLINE PetscInt GetTriMidEdgeInverse_Static(PetscInt o, PetscInt s) {
284   return (o < 0 ? 1-(o+s) : 3+s-o)%3;
285 }
286 
287 /* Return the interior edge number connecting the midpoint of the triangle edge r
288    (in the transitive closure) and the vertex in the interior of the face for triangle orientation o */
289 PETSC_STATIC_INLINE PetscInt GetTriInteriorEdge_Static(PetscInt o, PetscInt r) {
290   return (o < 0 ? 2-(o+r) : o+r)%3;
291 }
292 PETSC_STATIC_INLINE PetscInt GetTriInteriorEdgeInverse_Static(PetscInt o, PetscInt s) {
293   return (o < 0 ? 2-(o+s) : 3+s-o)%3;
294 }
295 
296 /* Return quad edge for orientation o, if it is r for o == 0 */
297 PETSC_STATIC_INLINE PetscInt GetQuadEdge_Static(PetscInt o, PetscInt r) {
298   return (o < 0 ? 3-(o+r) : o+r)%4;
299 }
300 PETSC_STATIC_INLINE PetscInt GetQuadEdgeInverse_Static(PetscInt o, PetscInt s) {
301   return (o < 0 ? 3-(o+s) : 4+s-o)%4;
302 }
303 
304 /* Return quad subface for orientation o, if it is r for o == 0 */
305 PETSC_STATIC_INLINE PetscInt GetQuadSubface_Static(PetscInt o, PetscInt r) {
306   return (o < 0 ? 4-(o+r) : o+r)%4;
307 }
308 PETSC_STATIC_INLINE PetscInt GetQuadSubfaceInverse_Static(PetscInt o, PetscInt s) {
309   return (o < 0 ? 4-(o+s) : 4+s-o)%4;
310 }
311 
312 static PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
313 {
314   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, e, r;
315   PetscErrorCode ierr;
316 
317   PetscFunctionBegin;
318   if (!refiner) PetscFunctionReturn(0);
319   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
320   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
321   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
322   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
323   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
324   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
325   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
326   switch (refiner) {
327   case REFINER_SIMPLEX_1D:
328     /* All cells have 2 vertices */
329     for (c = cStart; c < cEnd; ++c) {
330       for (r = 0; r < 2; ++r) {
331         const PetscInt newp = cStartNew + (c - cStart)*2 + r;
332 
333         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
334       }
335     }
336     /* Old vertices have identical supports */
337     for (v = vStart; v < vEnd; ++v) {
338       const PetscInt newp = vStartNew + (v - vStart);
339       PetscInt       size;
340 
341       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
342       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
343     }
344     /* Cell vertices have support 2 */
345     for (c = cStart; c < cEnd; ++c) {
346       const PetscInt newp = vStartNew + (vEnd - vStart) + (c - cStart);
347 
348       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
349     }
350     break;
351   case REFINER_SIMPLEX_2D:
352     /* All cells have 3 faces */
353     for (c = cStart; c < cEnd; ++c) {
354       for (r = 0; r < 4; ++r) {
355         const PetscInt newp = (c - cStart)*4 + r;
356 
357         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
358       }
359     }
360     /* Split faces have 2 vertices and the same cells as the parent */
361     for (f = fStart; f < fEnd; ++f) {
362       for (r = 0; r < 2; ++r) {
363         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
364         PetscInt       size;
365 
366         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
367         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
368         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
369       }
370     }
371     /* Interior faces have 2 vertices and 2 cells */
372     for (c = cStart; c < cEnd; ++c) {
373       for (r = 0; r < 3; ++r) {
374         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
375 
376         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
377         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
378       }
379     }
380     /* Old vertices have identical supports */
381     for (v = vStart; v < vEnd; ++v) {
382       const PetscInt newp = vStartNew + (v - vStart);
383       PetscInt       size;
384 
385       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
386       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
387     }
388     /* Face vertices have 2 + cells*2 supports */
389     for (f = fStart; f < fEnd; ++f) {
390       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
391       PetscInt       size;
392 
393       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
394       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
395     }
396     break;
397   case REFINER_SIMPLEX_TO_HEX_2D:
398     /* All cells have 4 faces */
399     for (c = cStart; c < cEnd; ++c) {
400       for (r = 0; r < 3; ++r) {
401         const PetscInt newp = (c - cStart)*3 + r;
402 
403         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
404       }
405     }
406     /* Split faces have 2 vertices and the same cells as the parent */
407     for (f = fStart; f < fEnd; ++f) {
408       for (r = 0; r < 2; ++r) {
409         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
410         PetscInt       size;
411 
412         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
413         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
414         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
415       }
416     }
417     /* Interior faces have 2 vertices and 2 cells */
418     for (c = cStart; c < cEnd; ++c) {
419       for (r = 0; r < 3; ++r) {
420         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
421 
422         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
423         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
424       }
425     }
426     /* Old vertices have identical supports */
427     for (v = vStart; v < vEnd; ++v) {
428       const PetscInt newp = vStartNew + (v - vStart);
429       PetscInt       size;
430 
431       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
432       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
433     }
434     /* Split-face vertices have cells + 2 supports */
435     for (f = fStart; f < fEnd; ++f) {
436       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
437       PetscInt       size;
438 
439       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
440       ierr = DMPlexSetSupportSize(rdm, newp, size + 2);CHKERRQ(ierr);
441     }
442     /* Interior vertices have 3 supports */
443     for (c = cStart; c < cEnd; ++c) {
444       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
445 
446       ierr = DMPlexSetSupportSize(rdm, newp, 3);CHKERRQ(ierr);
447     }
448     break;
449   case REFINER_HEX_2D:
450     /* All cells have 4 faces */
451     for (c = cStart; c < cEnd; ++c) {
452       for (r = 0; r < 4; ++r) {
453         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
454 
455         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
456       }
457     }
458     /* Split faces have 2 vertices and the same cells as the parent */
459     for (f = fStart; f < fEnd; ++f) {
460       for (r = 0; r < 2; ++r) {
461         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
462         PetscInt       size;
463 
464         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
465         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
466         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
467       }
468     }
469     /* Interior faces have 2 vertices and 2 cells */
470     for (c = cStart; c < cEnd; ++c) {
471       for (r = 0; r < 4; ++r) {
472         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
473 
474         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
475         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
476       }
477     }
478     /* Old vertices have identical supports */
479     for (v = vStart; v < vEnd; ++v) {
480       const PetscInt newp = vStartNew + (v - vStart);
481       PetscInt       size;
482 
483       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
484       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
485     }
486     /* Face vertices have 2 + cells supports */
487     for (f = fStart; f < fEnd; ++f) {
488       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
489       PetscInt       size;
490 
491       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
492       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
493     }
494     /* Cell vertices have 4 supports */
495     for (c = cStart; c < cEnd; ++c) {
496       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
497 
498       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
499     }
500     break;
501   case REFINER_HYBRID_SIMPLEX_2D:
502     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
503     cMax = PetscMin(cEnd, cMax);
504     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
505     fMax = PetscMin(fEnd, fMax);
506     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
507     /* Interior cells have 3 faces */
508     for (c = cStart; c < cMax; ++c) {
509       for (r = 0; r < 4; ++r) {
510         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
511 
512         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
513       }
514     }
515     /* Hybrid cells have 4 faces */
516     for (c = cMax; c < cEnd; ++c) {
517       for (r = 0; r < 2; ++r) {
518         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
519 
520         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
521       }
522     }
523     /* Interior split faces have 2 vertices and the same cells as the parent */
524     for (f = fStart; f < fMax; ++f) {
525       for (r = 0; r < 2; ++r) {
526         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
527         PetscInt       size;
528 
529         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
530         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
531         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
532       }
533     }
534     /* Interior cell faces have 2 vertices and 2 cells */
535     for (c = cStart; c < cMax; ++c) {
536       for (r = 0; r < 3; ++r) {
537         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
538 
539         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
540         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
541       }
542     }
543     /* Hybrid faces have 2 vertices and the same cells */
544     for (f = fMax; f < fEnd; ++f) {
545       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
546       PetscInt       size;
547 
548       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
549       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
550       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
551     }
552     /* Hybrid cell faces have 2 vertices and 2 cells */
553     for (c = cMax; c < cEnd; ++c) {
554       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
555 
556       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
557       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
558     }
559     /* Old vertices have identical supports */
560     for (v = vStart; v < vEnd; ++v) {
561       const PetscInt newp = vStartNew + (v - vStart);
562       PetscInt       size;
563 
564       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
565       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
566     }
567     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
568     for (f = fStart; f < fMax; ++f) {
569       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
570       const PetscInt *support;
571       PetscInt       size, newSize = 2, s;
572 
573       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
574       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
575       for (s = 0; s < size; ++s) {
576         if (support[s] >= cMax) newSize += 1;
577         else newSize += 2;
578       }
579       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
580     }
581     break;
582   case REFINER_HYBRID_HEX_2D:
583     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
584     cMax = PetscMin(cEnd, cMax);
585     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
586     fMax = PetscMin(fEnd, fMax);
587     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
588     /* Interior cells have 4 faces */
589     for (c = cStart; c < cMax; ++c) {
590       for (r = 0; r < 4; ++r) {
591         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
592 
593         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
594       }
595     }
596     /* Hybrid cells have 4 faces */
597     for (c = cMax; c < cEnd; ++c) {
598       for (r = 0; r < 2; ++r) {
599         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
600 
601         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
602       }
603     }
604     /* Interior split faces have 2 vertices and the same cells as the parent */
605     for (f = fStart; f < fMax; ++f) {
606       for (r = 0; r < 2; ++r) {
607         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
608         PetscInt       size;
609 
610         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
611         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
612         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
613       }
614     }
615     /* Interior cell faces have 2 vertices and 2 cells */
616     for (c = cStart; c < cMax; ++c) {
617       for (r = 0; r < 4; ++r) {
618         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
619 
620         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
621         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
622       }
623     }
624     /* Hybrid faces have 2 vertices and the same cells */
625     for (f = fMax; f < fEnd; ++f) {
626       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
627       PetscInt       size;
628 
629       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
630       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
631       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
632     }
633     /* Hybrid cell faces have 2 vertices and 2 cells */
634     for (c = cMax; c < cEnd; ++c) {
635       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
636 
637       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
638       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
639     }
640     /* Old vertices have identical supports */
641     for (v = vStart; v < vEnd; ++v) {
642       const PetscInt newp = vStartNew + (v - vStart);
643       PetscInt       size;
644 
645       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
646       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
647     }
648     /* Face vertices have 2 + cells supports */
649     for (f = fStart; f < fMax; ++f) {
650       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
651       PetscInt       size;
652 
653       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
654       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
655     }
656     /* Cell vertices have 4 supports */
657     for (c = cStart; c < cMax; ++c) {
658       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
659 
660       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
661     }
662     break;
663   case REFINER_SIMPLEX_3D:
664     /* All cells have 4 faces */
665     for (c = cStart; c < cEnd; ++c) {
666       for (r = 0; r < 8; ++r) {
667         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
668 
669         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
670       }
671     }
672     /* Split faces have 3 edges and the same cells as the parent */
673     for (f = fStart; f < fEnd; ++f) {
674       for (r = 0; r < 4; ++r) {
675         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
676         PetscInt       size;
677 
678         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
679         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
680         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
681       }
682     }
683     /* Interior cell faces have 3 edges and 2 cells */
684     for (c = cStart; c < cEnd; ++c) {
685       for (r = 0; r < 8; ++r) {
686         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + r;
687 
688         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
689         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
690       }
691     }
692     /* Split edges have 2 vertices and the same faces */
693     for (e = eStart; e < eEnd; ++e) {
694       for (r = 0; r < 2; ++r) {
695         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
696         PetscInt       size;
697 
698         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
699         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
700         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
701       }
702     }
703     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
704     for (f = fStart; f < fEnd; ++f) {
705       for (r = 0; r < 3; ++r) {
706         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
707         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
708         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;
709 
710         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
711         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
712         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
713         for (s = 0; s < supportSize; ++s) {
714           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
715           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
716           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
717           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
718           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
719           er = GetTriMidEdgeInverse_Static(ornt[c], r);
720           if (er == eint[c]) {
721             intFaces += 1;
722           } else {
723             intFaces += 2;
724           }
725         }
726         ierr = DMPlexSetSupportSize(rdm, newp, 2+intFaces);CHKERRQ(ierr);
727       }
728     }
729     /* Interior cell edges have 2 vertices and 4 faces */
730     for (c = cStart; c < cEnd; ++c) {
731       const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
732 
733       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
734       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
735     }
736     /* Old vertices have identical supports */
737     for (v = vStart; v < vEnd; ++v) {
738       const PetscInt newp = vStartNew + (v - vStart);
739       PetscInt       size;
740 
741       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
742       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
743     }
744     /* Edge vertices have 2 + faces*2 + cells*0/1 supports */
745     for (e = eStart; e < eEnd; ++e) {
746       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
747       PetscInt       size, *star = NULL, starSize, s, cellSize = 0;
748 
749       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
750       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
751       for (s = 0; s < starSize*2; s += 2) {
752         const PetscInt *cone, *ornt;
753         PetscInt        e01, e23;
754 
755         if ((star[s] >= cStart) && (star[s] < cEnd)) {
756           /* Check edge 0-1 */
757           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
758           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
759           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
760           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
761           /* Check edge 2-3 */
762           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
763           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
764           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
765           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
766           if ((e01 == e) || (e23 == e)) ++cellSize;
767         }
768       }
769       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
770       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2 + cellSize);CHKERRQ(ierr);
771     }
772     break;
773   case REFINER_HYBRID_SIMPLEX_3D:
774     ierr = DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 8*(cMax - cStart),
775                                  eStartNew + 2*(eMax - eStart) + 3*(fMax - fStart) + (cMax - cStart), PETSC_DETERMINE);CHKERRQ(ierr);
776     /* Interior cells have 4 faces */
777     for (c = cStart; c < cMax; ++c) {
778       for (r = 0; r < 8; ++r) {
779         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
780 
781         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
782       }
783     }
784     /* Hybrid cells have 5 faces */
785     for (c = cMax; c < cEnd; ++c) {
786       for (r = 0; r < 4; ++r) {
787         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;
788 
789         ierr = DMPlexSetConeSize(rdm, newp, 5);CHKERRQ(ierr);
790       }
791     }
792     /* Interior split faces have 3 edges and the same cells as the parent */
793     for (f = fStart; f < fMax; ++f) {
794       for (r = 0; r < 4; ++r) {
795         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
796         PetscInt       size;
797 
798         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
799         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
800         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
801       }
802     }
803     /* Interior cell faces have 3 edges and 2 cells */
804     for (c = cStart; c < cMax; ++c) {
805       for (r = 0; r < 8; ++r) {
806         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + r;
807 
808         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
809         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
810       }
811     }
812     /* Hybrid split faces have 4 edges and the same cells as the parent */
813     for (f = fMax; f < fEnd; ++f) {
814       for (r = 0; r < 2; ++r) {
815         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
816         PetscInt       size;
817 
818         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
819         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
820         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
821       }
822     }
823     /* Hybrid cells faces have 4 edges and 2 cells */
824     for (c = cMax; c < cEnd; ++c) {
825       for (r = 0; r < 3; ++r) {
826         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + r;
827 
828         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
829         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
830       }
831     }
832     /* Interior split edges have 2 vertices and the same faces */
833     for (e = eStart; e < eMax; ++e) {
834       for (r = 0; r < 2; ++r) {
835         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
836         PetscInt       size;
837 
838         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
839         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
840         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
841       }
842     }
843     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
844     for (f = fStart; f < fMax; ++f) {
845       for (r = 0; r < 3; ++r) {
846         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
847         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
848         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;
849 
850         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
851         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
852         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
853         for (s = 0; s < supportSize; ++s) {
854           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
855           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
856           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
857           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
858           if (support[s] < cMax) {
859             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
860             er = GetTriMidEdgeInverse_Static(ornt[c], r);
861             if (er == eint[c]) {
862               intFaces += 1;
863             } else {
864               intFaces += 2;
865             }
866           } else {
867             intFaces += 1;
868           }
869         }
870         ierr = DMPlexSetSupportSize(rdm, newp, 2+intFaces);CHKERRQ(ierr);
871       }
872     }
873     /* Interior cell edges have 2 vertices and 4 faces */
874     for (c = cStart; c < cMax; ++c) {
875       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
876 
877       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
878       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
879     }
880     /* Hybrid edges have 2 vertices and the same faces */
881     for (e = eMax; e < eEnd; ++e) {
882       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
883       PetscInt       size;
884 
885       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
886       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
887       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
888     }
889     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
890     for (f = fMax; f < fEnd; ++f) {
891       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
892       PetscInt       size;
893 
894       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
895       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
896       ierr = DMPlexSetSupportSize(rdm, newp, 2+2*size);CHKERRQ(ierr);
897     }
898     /* Interior vertices have identical supports */
899     for (v = vStart; v < vEnd; ++v) {
900       const PetscInt newp = vStartNew + (v - vStart);
901       PetscInt       size;
902 
903       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
904       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
905     }
906     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
907     for (e = eStart; e < eMax; ++e) {
908       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
909       const PetscInt *support;
910       PetscInt        size, *star = NULL, starSize, s, faceSize = 0, cellSize = 0;
911 
912       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
913       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
914       for (s = 0; s < size; ++s) {
915         if (support[s] < fMax) faceSize += 2;
916         else                   faceSize += 1;
917       }
918       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
919       for (s = 0; s < starSize*2; s += 2) {
920         const PetscInt *cone, *ornt;
921         PetscInt        e01, e23;
922 
923         if ((star[s] >= cStart) && (star[s] < cMax)) {
924           /* Check edge 0-1 */
925           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
926           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
927           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
928           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
929           /* Check edge 2-3 */
930           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
931           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
932           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
933           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
934           if ((e01 == e) || (e23 == e)) ++cellSize;
935         }
936       }
937       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
938       ierr = DMPlexSetSupportSize(rdm, newp, 2 + faceSize + cellSize);CHKERRQ(ierr);
939     }
940     break;
941   case REFINER_SIMPLEX_TO_HEX_3D:
942     /* All cells have 6 faces */
943     for (c = cStart; c < cEnd; ++c) {
944       for (r = 0; r < 4; ++r) {
945         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
946 
947         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
948       }
949     }
950     /* Split faces have 4 edges and the same cells as the parent */
951     for (f = fStart; f < fEnd; ++f) {
952       for (r = 0; r < 3; ++r) {
953         const PetscInt newp = fStartNew + (f - fStart)*3 + r;
954         PetscInt       size;
955 
956         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
957         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
958         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
959       }
960     }
961     /* Interior cell faces have 4 edges and 2 cells */
962     for (c = cStart; c < cEnd; ++c) {
963       for (r = 0; r < 6; ++r) {
964         const PetscInt newp = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + r;
965 
966         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
967         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
968       }
969     }
970     /* Split edges have 2 vertices and the same faces */
971     for (e = eStart; e < eEnd; ++e) {
972       for (r = 0; r < 2; ++r) {
973         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
974         PetscInt       size;
975 
976         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
977         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
978         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
979       }
980     }
981     /* Face edges have 2 vertices and 2 + cell faces supports */
982     for (f = fStart; f < fEnd; ++f) {
983       for (r = 0; r < 3; ++r) {
984         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
985         PetscInt        size;
986 
987         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
988         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
989         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
990       }
991     }
992     /* Interior cell edges have 2 vertices and 3 faces */
993     for (c = cStart; c < cEnd; ++c) {
994       for (r = 0; r < 4; ++r) {
995         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + r;
996 
997         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
998         ierr = DMPlexSetSupportSize(rdm, newp, 3);CHKERRQ(ierr);
999       }
1000     }
1001     /* Old vertices have identical supports */
1002     for (v = vStart; v < vEnd; ++v) {
1003       const PetscInt newp = vStartNew + (v - vStart);
1004       PetscInt       size;
1005 
1006       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1007       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1008     }
1009     /* Edge vertices have 2 + faces supports */
1010     for (e = eStart; e < eEnd; ++e) {
1011       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1012       PetscInt       size;
1013 
1014       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1015       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1016     }
1017     /* Face vertices have 3 + cells supports */
1018     for (f = fStart; f < fEnd; ++f) {
1019       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + f - fStart;
1020       PetscInt       size;
1021 
1022       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1023       ierr = DMPlexSetSupportSize(rdm, newp, 3 + size);CHKERRQ(ierr);
1024     }
1025     /* Interior cell vertices have 4 supports */
1026     for (c = cStart; c < cEnd; ++c) {
1027       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + fEnd - fStart + c - cStart;
1028 
1029       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1030     }
1031     break;
1032   case REFINER_HEX_3D:
1033     /* All cells have 6 faces */
1034     for (c = cStart; c < cEnd; ++c) {
1035       for (r = 0; r < 8; ++r) {
1036         const PetscInt newp = (c - cStart)*8 + r;
1037 
1038         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1039       }
1040     }
1041     /* Split faces have 4 edges and the same cells as the parent */
1042     for (f = fStart; f < fEnd; ++f) {
1043       for (r = 0; r < 4; ++r) {
1044         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
1045         PetscInt       size;
1046 
1047         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1048         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1049         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1050       }
1051     }
1052     /* Interior faces have 4 edges and 2 cells */
1053     for (c = cStart; c < cEnd; ++c) {
1054       for (r = 0; r < 12; ++r) {
1055         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
1056 
1057         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1058         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1059       }
1060     }
1061     /* Split edges have 2 vertices and the same faces as the parent */
1062     for (e = eStart; e < eEnd; ++e) {
1063       for (r = 0; r < 2; ++r) {
1064         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1065         PetscInt       size;
1066 
1067         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1068         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1069         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1070       }
1071     }
1072     /* Face edges have 2 vertices and 2+cells faces */
1073     for (f = fStart; f < fEnd; ++f) {
1074       for (r = 0; r < 4; ++r) {
1075         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
1076         PetscInt       size;
1077 
1078         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1079         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1080         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1081       }
1082     }
1083     /* Cell edges have 2 vertices and 4 faces */
1084     for (c = cStart; c < cEnd; ++c) {
1085       for (r = 0; r < 6; ++r) {
1086         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
1087 
1088         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1089         ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1090       }
1091     }
1092     /* Old vertices have identical supports */
1093     for (v = vStart; v < vEnd; ++v) {
1094       const PetscInt newp = vStartNew + (v - vStart);
1095       PetscInt       size;
1096 
1097       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1098       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1099     }
1100     /* Edge vertices have 2 + faces supports */
1101     for (e = eStart; e < eEnd; ++e) {
1102       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1103       PetscInt       size;
1104 
1105       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1106       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1107     }
1108     /* Face vertices have 4 + cells supports */
1109     for (f = fStart; f < fEnd; ++f) {
1110       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
1111       PetscInt       size;
1112 
1113       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1114       ierr = DMPlexSetSupportSize(rdm, newp, 4 + size);CHKERRQ(ierr);
1115     }
1116     /* Cell vertices have 6 supports */
1117     for (c = cStart; c < cEnd; ++c) {
1118       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
1119 
1120       ierr = DMPlexSetSupportSize(rdm, newp, 6);CHKERRQ(ierr);
1121     }
1122     break;
1123   case REFINER_HYBRID_HEX_3D:
1124     ierr = DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 12*(cMax - cStart),
1125                                  eStartNew + 2*(eMax - eStart) + 4*(fMax - fStart) + 6*(cMax - cStart), PETSC_DETERMINE);CHKERRQ(ierr);
1126     /* Interior cells have 6 faces */
1127     for (c = cStart; c < cMax; ++c) {
1128       for (r = 0; r < 8; ++r) {
1129         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
1130 
1131         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1132       }
1133     }
1134     /* Hybrid cells have 6 faces */
1135     for (c = cMax; c < cEnd; ++c) {
1136       for (r = 0; r < 4; ++r) {
1137         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;
1138 
1139         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1140       }
1141     }
1142     /* Interior split faces have 4 edges and the same cells as the parent */
1143     for (f = fStart; f < fMax; ++f) {
1144       for (r = 0; r < 4; ++r) {
1145         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
1146         PetscInt       size;
1147 
1148         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1149         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1150         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1151       }
1152     }
1153     /* Interior cell faces have 4 edges and 2 cells */
1154     for (c = cStart; c < cMax; ++c) {
1155       for (r = 0; r < 12; ++r) {
1156         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
1157 
1158         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1159         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1160       }
1161     }
1162     /* Hybrid split faces have 4 edges and the same cells as the parent */
1163     for (f = fMax; f < fEnd; ++f) {
1164       for (r = 0; r < 2; ++r) {
1165         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
1166         PetscInt       size;
1167 
1168         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1169         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1170         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1171       }
1172     }
1173     /* Hybrid cells faces have 4 edges and 2 cells */
1174     for (c = cMax; c < cEnd; ++c) {
1175       for (r = 0; r < 4; ++r) {
1176         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + r;
1177 
1178         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1179         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1180       }
1181     }
1182     /* Interior split edges have 2 vertices and the same faces as the parent */
1183     for (e = eStart; e < eMax; ++e) {
1184       for (r = 0; r < 2; ++r) {
1185         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1186         PetscInt       size;
1187 
1188         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1189         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1190         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1191       }
1192     }
1193     /* Interior face edges have 2 vertices and 2+cells faces */
1194     for (f = fStart; f < fMax; ++f) {
1195       for (r = 0; r < 4; ++r) {
1196         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
1197         PetscInt       size;
1198 
1199         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1200         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1201         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1202       }
1203     }
1204     /* Interior cell edges have 2 vertices and 4 faces */
1205     for (c = cStart; c < cMax; ++c) {
1206       for (r = 0; r < 6; ++r) {
1207         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
1208 
1209         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1210         ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1211       }
1212     }
1213     /* Hybrid edges have 2 vertices and the same faces */
1214     for (e = eMax; e < eEnd; ++e) {
1215       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
1216       PetscInt       size;
1217 
1218       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1219       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1220       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1221     }
1222     /* Hybrid face edges have 2 vertices and 2+cells faces */
1223     for (f = fMax; f < fEnd; ++f) {
1224       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
1225       PetscInt       size;
1226 
1227       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1228       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1229       ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1230     }
1231     /* Hybrid cell edges have 2 vertices and 4 faces */
1232     for (c = cMax; c < cEnd; ++c) {
1233       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
1234 
1235       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1236       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1237     }
1238     /* Interior vertices have identical supports */
1239     for (v = vStart; v < vEnd; ++v) {
1240       const PetscInt newp = vStartNew + (v - vStart);
1241       PetscInt       size;
1242 
1243       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1244       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1245     }
1246     /* Interior edge vertices have 2 + faces supports */
1247     for (e = eStart; e < eMax; ++e) {
1248       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1249       PetscInt       size;
1250 
1251       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1252       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1253     }
1254     /* Interior face vertices have 4 + cells supports */
1255     for (f = fStart; f < fMax; ++f) {
1256       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
1257       PetscInt       size;
1258 
1259       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1260       ierr = DMPlexSetSupportSize(rdm, newp, 4 + size);CHKERRQ(ierr);
1261     }
1262     /* Interior cell vertices have 6 supports */
1263     for (c = cStart; c < cMax; ++c) {
1264       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
1265 
1266       ierr = DMPlexSetSupportSize(rdm, newp, 6);CHKERRQ(ierr);
1267     }
1268     break;
1269   default:
1270     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
1271   }
1272   PetscFunctionReturn(0);
1273 }
1274 
1275 static PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
1276 {
1277   const PetscInt *faces, cellInd[4] = {0, 1, 2, 3};
1278   PetscInt        cStart,    cEnd,    cMax,    vStart,    vEnd, vMax, fStart,    fEnd,    fMax,    eStart,    eEnd,    eMax;
1279   PetscInt        cStartNew, cEndNew, cMaxNew, vStartNew, vEndNew,    fStartNew, fEndNew, fMaxNew, eStartNew, eEndNew, eMaxNew;
1280   PetscInt        depth, maxSupportSize, *supportRef, c, f, e, v, r, p;
1281   PetscErrorCode  ierr;
1282 
1283   PetscFunctionBegin;
1284   if (!refiner) PetscFunctionReturn(0);
1285   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1286   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
1287   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
1288   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1289   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
1290   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
1291   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
1292   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
1293   switch (refiner) {
1294   case REFINER_SIMPLEX_1D:
1295     /* Max support size of refined mesh is 2 */
1296     ierr = PetscMalloc1(2, &supportRef);CHKERRQ(ierr);
1297     /* All cells have 2 vertices */
1298     for (c = cStart; c < cEnd; ++c) {
1299       const PetscInt  newv = vStartNew + (vEnd - vStart) + (c - cStart);
1300 
1301       for (r = 0; r < 2; ++r) {
1302         const PetscInt newp = cStartNew + (c - cStart)*2 + r;
1303         const PetscInt *cone;
1304         PetscInt        coneNew[2];
1305 
1306         ierr             = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1307         coneNew[0]       = vStartNew + (cone[0] - vStart);
1308         coneNew[1]       = vStartNew + (cone[1] - vStart);
1309         coneNew[(r+1)%2] = newv;
1310         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1311 #if 1
1312         if ((newp < cStartNew) || (newp >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp, cStartNew, cEndNew);
1313         for (p = 0; p < 2; ++p) {
1314           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
1315         }
1316 #endif
1317       }
1318     }
1319     /* Old vertices have identical supports */
1320     for (v = vStart; v < vEnd; ++v) {
1321       const PetscInt  newp = vStartNew + (v - vStart);
1322       const PetscInt *support, *cone;
1323       PetscInt        size, s;
1324 
1325       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1326       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1327       for (s = 0; s < size; ++s) {
1328         PetscInt r = 0;
1329 
1330         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1331         if (cone[1] == v) r = 1;
1332         supportRef[s] = cStartNew + (support[s] - cStart)*2 + r;
1333       }
1334       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1335 #if 1
1336       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1337       for (p = 0; p < size; ++p) {
1338         if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
1339       }
1340 #endif
1341     }
1342     /* Cell vertices have support of 2 cells */
1343     for (c = cStart; c < cEnd; ++c) {
1344       const PetscInt  newp = vStartNew + (vEnd - vStart) + (c - cStart);
1345 
1346       supportRef[0] = cStartNew + (c - cStart)*2 + 0;
1347       supportRef[1] = cStartNew + (c - cStart)*2 + 1;
1348       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1349 #if 1
1350       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1351       for (p = 0; p < 2; ++p) {
1352         if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
1353       }
1354 #endif
1355     }
1356     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1357     break;
1358   case REFINER_SIMPLEX_2D:
1359     /*
1360      2
1361      |\
1362      | \
1363      |  \
1364      |   \
1365      | C  \
1366      |     \
1367      |      \
1368      2---1---1
1369      |\  D  / \
1370      | 2   0   \
1371      |A \ /  B  \
1372      0---0-------1
1373      */
1374     /* All cells have 3 faces */
1375     for (c = cStart; c < cEnd; ++c) {
1376       const PetscInt  newp = cStartNew + (c - cStart)*4;
1377       const PetscInt *cone, *ornt;
1378       PetscInt        coneNew[3], orntNew[3];
1379 
1380       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1381       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1382       /* A triangle */
1383       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1384       orntNew[0] = ornt[0];
1385       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1386       orntNew[1] = -2;
1387       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1388       orntNew[2] = ornt[2];
1389       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1390       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1391 #if 1
1392       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
1393       for (p = 0; p < 3; ++p) {
1394         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1395       }
1396 #endif
1397       /* B triangle */
1398       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1399       orntNew[0] = ornt[0];
1400       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1401       orntNew[1] = ornt[1];
1402       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1403       orntNew[2] = -2;
1404       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1405       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1406 #if 1
1407       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
1408       for (p = 0; p < 3; ++p) {
1409         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1410       }
1411 #endif
1412       /* C triangle */
1413       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1414       orntNew[0] = -2;
1415       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1416       orntNew[1] = ornt[1];
1417       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1418       orntNew[2] = ornt[2];
1419       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1420       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1421 #if 1
1422       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
1423       for (p = 0; p < 3; ++p) {
1424         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1425       }
1426 #endif
1427       /* D triangle */
1428       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1429       orntNew[0] = 0;
1430       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1431       orntNew[1] = 0;
1432       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1433       orntNew[2] = 0;
1434       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1435       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1436 #if 1
1437       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
1438       for (p = 0; p < 3; ++p) {
1439         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1440       }
1441 #endif
1442     }
1443     /* Split faces have 2 vertices and the same cells as the parent */
1444     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1445     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
1446     for (f = fStart; f < fEnd; ++f) {
1447       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1448 
1449       for (r = 0; r < 2; ++r) {
1450         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1451         const PetscInt *cone, *ornt, *support;
1452         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1453 
1454         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1455         coneNew[0]       = vStartNew + (cone[0] - vStart);
1456         coneNew[1]       = vStartNew + (cone[1] - vStart);
1457         coneNew[(r+1)%2] = newv;
1458         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1459 #if 1
1460         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1461         for (p = 0; p < 2; ++p) {
1462           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
1463         }
1464 #endif
1465         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1466         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1467         for (s = 0; s < supportSize; ++s) {
1468           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1469           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1470           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1471           for (c = 0; c < coneSize; ++c) {
1472             if (cone[c] == f) break;
1473           }
1474           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1475         }
1476         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1477 #if 1
1478         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1479         for (p = 0; p < supportSize; ++p) {
1480           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
1481         }
1482 #endif
1483       }
1484     }
1485     /* Interior faces have 2 vertices and 2 cells */
1486     for (c = cStart; c < cEnd; ++c) {
1487       const PetscInt *cone;
1488 
1489       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1490       for (r = 0; r < 3; ++r) {
1491         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
1492         PetscInt       coneNew[2];
1493         PetscInt       supportNew[2];
1494 
1495         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
1496         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
1497         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1498 #if 1
1499         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1500         for (p = 0; p < 2; ++p) {
1501           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
1502         }
1503 #endif
1504         supportNew[0] = (c - cStart)*4 + (r+1)%3;
1505         supportNew[1] = (c - cStart)*4 + 3;
1506         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1507 #if 1
1508         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1509         for (p = 0; p < 2; ++p) {
1510           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
1511         }
1512 #endif
1513       }
1514     }
1515     /* Old vertices have identical supports */
1516     for (v = vStart; v < vEnd; ++v) {
1517       const PetscInt  newp = vStartNew + (v - vStart);
1518       const PetscInt *support, *cone;
1519       PetscInt        size, s;
1520 
1521       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1522       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1523       for (s = 0; s < size; ++s) {
1524         PetscInt r = 0;
1525 
1526         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1527         if (cone[1] == v) r = 1;
1528         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1529       }
1530       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1531 #if 1
1532       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1533       for (p = 0; p < size; ++p) {
1534         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
1535       }
1536 #endif
1537     }
1538     /* Face vertices have 2 + cells*2 supports */
1539     for (f = fStart; f < fEnd; ++f) {
1540       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1541       const PetscInt *cone, *support;
1542       PetscInt        size, s;
1543 
1544       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1545       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1546       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1547       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1548       for (s = 0; s < size; ++s) {
1549         PetscInt r = 0;
1550 
1551         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1552         if      (cone[1] == f) r = 1;
1553         else if (cone[2] == f) r = 2;
1554         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
1555         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
1556       }
1557       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1558 #if 1
1559       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1560       for (p = 0; p < 2+size*2; ++p) {
1561         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
1562       }
1563 #endif
1564     }
1565     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1566     break;
1567   case REFINER_SIMPLEX_TO_HEX_2D:
1568     /*
1569      2
1570      |\
1571      | \
1572      |  \
1573      |   \
1574      | C  \
1575      |     \
1576      2      1
1577      |\    / \
1578      | 2  1   \
1579      |  \/     \
1580      |   |      \
1581      |A  |   B   \
1582      |   0        \
1583      |   |         \
1584      0---0----------1
1585      */
1586     /* All cells have 4 faces */
1587     for (c = cStart; c < cEnd; ++c) {
1588       const PetscInt  newp = cStartNew + (c - cStart)*3;
1589       const PetscInt *cone, *ornt;
1590       PetscInt        coneNew[4], orntNew[4];
1591 
1592       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1593       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1594       /* A quad */
1595       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1596       orntNew[0] = ornt[0];
1597       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1598       orntNew[1] = 0;
1599       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1600       orntNew[2] = -2;
1601       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1602       orntNew[3] = ornt[2];
1603       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1604       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1605 #if 1
1606       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
1607       for (p = 0; p < 4; ++p) {
1608         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1609       }
1610 #endif
1611       /* B quad */
1612       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1613       orntNew[0] = ornt[0];
1614       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1615       orntNew[1] = ornt[1];
1616       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1617       orntNew[2] = 0;
1618       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1619       orntNew[3] = -2;
1620       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1621       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1622 #if 1
1623       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
1624       for (p = 0; p < 4; ++p) {
1625         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1626       }
1627 #endif
1628       /* C quad */
1629       coneNew[0] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1630       orntNew[0] = ornt[1];
1631       coneNew[1] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1632       orntNew[1] = ornt[2];
1633       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1634       orntNew[2] = 0;
1635       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1636       orntNew[3] = -2;
1637       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1638       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1639 #if 1
1640       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
1641       for (p = 0; p < 4; ++p) {
1642         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1643       }
1644 #endif
1645     }
1646     /* Split faces have 2 vertices and the same cells as the parent */
1647     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1648     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
1649     for (f = fStart; f < fEnd; ++f) {
1650       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1651 
1652       for (r = 0; r < 2; ++r) {
1653         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1654         const PetscInt *cone, *ornt, *support;
1655         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1656 
1657         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1658         coneNew[0]       = vStartNew + (cone[0] - vStart);
1659         coneNew[1]       = vStartNew + (cone[1] - vStart);
1660         coneNew[(r+1)%2] = newv;
1661         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1662 #if 1
1663         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1664         for (p = 0; p < 2; ++p) {
1665           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
1666         }
1667 #endif
1668         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1669         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1670         for (s = 0; s < supportSize; ++s) {
1671           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1672           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1673           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1674           for (c = 0; c < coneSize; ++c) {
1675             if (cone[c] == f) break;
1676           }
1677           supportRef[s] = cStartNew + (support[s] - cStart)*3 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1678         }
1679         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1680 #if 1
1681         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1682         for (p = 0; p < supportSize; ++p) {
1683           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
1684         }
1685 #endif
1686       }
1687     }
1688     /* Interior faces have 2 vertices and 2 cells */
1689     for (c = cStart; c < cEnd; ++c) {
1690       const PetscInt *cone;
1691 
1692       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1693       for (r = 0; r < 3; ++r) {
1694         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
1695         PetscInt       coneNew[2];
1696         PetscInt       supportNew[2];
1697 
1698         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
1699         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
1700         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1701 #if 1
1702         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1703         for (p = 0; p < 2; ++p) {
1704           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
1705         }
1706 #endif
1707         supportNew[0] = (c - cStart)*3 + r%3;
1708         supportNew[1] = (c - cStart)*3 + (r+1)%3;
1709         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1710 #if 1
1711         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1712         for (p = 0; p < 2; ++p) {
1713           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
1714         }
1715 #endif
1716       }
1717     }
1718     /* Old vertices have identical supports */
1719     for (v = vStart; v < vEnd; ++v) {
1720       const PetscInt  newp = vStartNew + (v - vStart);
1721       const PetscInt *support, *cone;
1722       PetscInt        size, s;
1723 
1724       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1725       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1726       for (s = 0; s < size; ++s) {
1727         PetscInt r = 0;
1728 
1729         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1730         if (cone[1] == v) r = 1;
1731         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1732       }
1733       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1734 #if 1
1735       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1736       for (p = 0; p < size; ++p) {
1737         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
1738       }
1739 #endif
1740     }
1741     /* Split-face vertices have cells + 2 supports */
1742     for (f = fStart; f < fEnd; ++f) {
1743       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1744       const PetscInt *cone, *support;
1745       PetscInt        size, s;
1746 
1747       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1748       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1749       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1750       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1751       for (s = 0; s < size; ++s) {
1752         PetscInt r = 0;
1753 
1754         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1755         if      (cone[1] == f) r = 1;
1756         else if (cone[2] == f) r = 2;
1757         supportRef[2+s+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
1758       }
1759       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1760 #if 1
1761       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1762       for (p = 0; p < 2+size; ++p) {
1763         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
1764       }
1765 #endif
1766     }
1767     /* Interior vertices vertices have 3 supports */
1768     for (c = cStart; c < cEnd; ++c) {
1769       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
1770 
1771       supportRef[0] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 0;
1772       supportRef[1] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 1;
1773       supportRef[2] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 2;
1774       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1775     }
1776     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1777     break;
1778   case REFINER_HEX_2D:
1779     /*
1780      3---------2---------2
1781      |         |         |
1782      |    D    2    C    |
1783      |         |         |
1784      3----3----0----1----1
1785      |         |         |
1786      |    A    0    B    |
1787      |         |         |
1788      0---------0---------1
1789      */
1790     /* All cells have 4 faces */
1791     for (c = cStart; c < cEnd; ++c) {
1792       const PetscInt  newp = (c - cStart)*4;
1793       const PetscInt *cone, *ornt;
1794       PetscInt        coneNew[4], orntNew[4];
1795 
1796       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1797       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1798       /* A quad */
1799       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1800       orntNew[0] = ornt[0];
1801       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
1802       orntNew[1] = 0;
1803       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
1804       orntNew[2] = -2;
1805       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
1806       orntNew[3] = ornt[3];
1807       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1808       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1809 #if 1
1810       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
1811       for (p = 0; p < 4; ++p) {
1812         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1813       }
1814 #endif
1815       /* B quad */
1816       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1817       orntNew[0] = ornt[0];
1818       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1819       orntNew[1] = ornt[1];
1820       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
1821       orntNew[2] = -2;
1822       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
1823       orntNew[3] = -2;
1824       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1825       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1826 #if 1
1827       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
1828       for (p = 0; p < 4; ++p) {
1829         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1830       }
1831 #endif
1832       /* C quad */
1833       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
1834       orntNew[0] = 0;
1835       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1836       orntNew[1] = ornt[1];
1837       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1838       orntNew[2] = ornt[2];
1839       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
1840       orntNew[3] = -2;
1841       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1842       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1843 #if 1
1844       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
1845       for (p = 0; p < 4; ++p) {
1846         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1847       }
1848 #endif
1849       /* D quad */
1850       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
1851       orntNew[0] = 0;
1852       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
1853       orntNew[1] = 0;
1854       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1855       orntNew[2] = ornt[2];
1856       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
1857       orntNew[3] = ornt[3];
1858       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1859       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1860 #if 1
1861       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
1862       for (p = 0; p < 4; ++p) {
1863         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1864       }
1865 #endif
1866     }
1867     /* Split faces have 2 vertices and the same cells as the parent */
1868     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1869     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
1870     for (f = fStart; f < fEnd; ++f) {
1871       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1872 
1873       for (r = 0; r < 2; ++r) {
1874         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1875         const PetscInt *cone, *ornt, *support;
1876         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1877 
1878         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1879         coneNew[0]       = vStartNew + (cone[0] - vStart);
1880         coneNew[1]       = vStartNew + (cone[1] - vStart);
1881         coneNew[(r+1)%2] = newv;
1882         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1883 #if 1
1884         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1885         for (p = 0; p < 2; ++p) {
1886           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
1887         }
1888 #endif
1889         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1890         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1891         for (s = 0; s < supportSize; ++s) {
1892           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1893           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1894           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1895           for (c = 0; c < coneSize; ++c) {
1896             if (cone[c] == f) break;
1897           }
1898           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
1899         }
1900         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1901 #if 1
1902         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1903         for (p = 0; p < supportSize; ++p) {
1904           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
1905         }
1906 #endif
1907       }
1908     }
1909     /* Interior faces have 2 vertices and 2 cells */
1910     for (c = cStart; c < cEnd; ++c) {
1911       const PetscInt *cone;
1912       PetscInt        coneNew[2], supportNew[2];
1913 
1914       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1915       for (r = 0; r < 4; ++r) {
1916         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
1917 
1918 	if (r==1 || r==2) {
1919           coneNew[0] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
1920           coneNew[1] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
1921 	} else {
1922           coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
1923           coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
1924 	}
1925 	ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1926 #if 1
1927         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1928         for (p = 0; p < 2; ++p) {
1929           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
1930         }
1931 #endif
1932         supportNew[0] = (c - cStart)*4 + r;
1933         supportNew[1] = (c - cStart)*4 + (r+1)%4;
1934         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1935 #if 1
1936         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1937         for (p = 0; p < 2; ++p) {
1938           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
1939         }
1940 #endif
1941       }
1942     }
1943     /* Old vertices have identical supports */
1944     for (v = vStart; v < vEnd; ++v) {
1945       const PetscInt  newp = vStartNew + (v - vStart);
1946       const PetscInt *support, *cone;
1947       PetscInt        size, s;
1948 
1949       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1950       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1951       for (s = 0; s < size; ++s) {
1952         PetscInt r = 0;
1953 
1954         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1955         if (cone[1] == v) r = 1;
1956         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1957       }
1958       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1959 #if 1
1960       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1961       for (p = 0; p < size; ++p) {
1962         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
1963       }
1964 #endif
1965     }
1966     /* Face vertices have 2 + cells supports */
1967     for (f = fStart; f < fEnd; ++f) {
1968       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1969       const PetscInt *cone, *support;
1970       PetscInt        size, s;
1971 
1972       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1973       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1974       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1975       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1976       for (s = 0; s < size; ++s) {
1977         PetscInt r = 0;
1978 
1979         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1980         if      (cone[1] == f) r = 1;
1981         else if (cone[2] == f) r = 2;
1982         else if (cone[3] == f) r = 3;
1983         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
1984       }
1985       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1986 #if 1
1987       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1988       for (p = 0; p < 2+size; ++p) {
1989         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
1990       }
1991 #endif
1992     }
1993     /* Cell vertices have 4 supports */
1994     for (c = cStart; c < cEnd; ++c) {
1995       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
1996       PetscInt       supportNew[4];
1997 
1998       for (r = 0; r < 4; ++r) {
1999         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
2000       }
2001       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2002     }
2003     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2004     break;
2005   case REFINER_HYBRID_SIMPLEX_2D:
2006     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
2007     cMax = PetscMin(cEnd, cMax);
2008     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
2009     fMax = PetscMin(fEnd, fMax);
2010     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);CHKERRQ(ierr);
2011     /* Interior cells have 3 faces */
2012     for (c = cStart; c < cMax; ++c) {
2013       const PetscInt  newp = cStartNew + (c - cStart)*4;
2014       const PetscInt *cone, *ornt;
2015       PetscInt        coneNew[3], orntNew[3];
2016 
2017       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2018       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2019       /* A triangle */
2020       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2021       orntNew[0] = ornt[0];
2022       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
2023       orntNew[1] = -2;
2024       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2025       orntNew[2] = ornt[2];
2026       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2027       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2028 #if 1
2029       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+0, cStartNew, cMaxNew);
2030       for (p = 0; p < 3; ++p) {
2031         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2032       }
2033 #endif
2034       /* B triangle */
2035       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2036       orntNew[0] = ornt[0];
2037       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2038       orntNew[1] = ornt[1];
2039       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
2040       orntNew[2] = -2;
2041       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2042       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2043 #if 1
2044       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+1, cStartNew, cMaxNew);
2045       for (p = 0; p < 3; ++p) {
2046         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2047       }
2048 #endif
2049       /* C triangle */
2050       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
2051       orntNew[0] = -2;
2052       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2053       orntNew[1] = ornt[1];
2054       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2055       orntNew[2] = ornt[2];
2056       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2057       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2058 #if 1
2059       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+2, cStartNew, cMaxNew);
2060       for (p = 0; p < 3; ++p) {
2061         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2062       }
2063 #endif
2064       /* D triangle */
2065       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
2066       orntNew[0] = 0;
2067       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
2068       orntNew[1] = 0;
2069       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
2070       orntNew[2] = 0;
2071       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2072       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2073 #if 1
2074       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+3, cStartNew, cMaxNew);
2075       for (p = 0; p < 3; ++p) {
2076         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2077       }
2078 #endif
2079     }
2080     /*
2081      2----3----3
2082      |         |
2083      |    B    |
2084      |         |
2085      0----4--- 1
2086      |         |
2087      |    A    |
2088      |         |
2089      0----2----1
2090      */
2091     /* Hybrid cells have 4 faces */
2092     for (c = cMax; c < cEnd; ++c) {
2093       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
2094       const PetscInt *cone, *ornt;
2095       PetscInt        coneNew[4], orntNew[4], r;
2096 
2097       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2098       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2099       r    = (ornt[0] < 0 ? 1 : 0);
2100       /* A quad */
2101       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + r;
2102       orntNew[0]   = ornt[0];
2103       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + r;
2104       orntNew[1]   = ornt[1];
2105       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2+r] - fMax);
2106       orntNew[2+r] = 0;
2107       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
2108       orntNew[3-r] = 0;
2109       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2110       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2111 #if 1
2112       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
2113       for (p = 0; p < 4; ++p) {
2114         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2115       }
2116 #endif
2117       /* B quad */
2118       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + 1-r;
2119       orntNew[0]   = ornt[0];
2120       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + 1-r;
2121       orntNew[1]   = ornt[1];
2122       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
2123       orntNew[2+r] = 0;
2124       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3-r] - fMax);
2125       orntNew[3-r] = 0;
2126       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2127       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2128 #if 1
2129       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
2130       for (p = 0; p < 4; ++p) {
2131         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2132       }
2133 #endif
2134     }
2135     /* Interior split faces have 2 vertices and the same cells as the parent */
2136     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2137     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2138     for (f = fStart; f < fMax; ++f) {
2139       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
2140 
2141       for (r = 0; r < 2; ++r) {
2142         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2143         const PetscInt *cone, *ornt, *support;
2144         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2145 
2146         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2147         coneNew[0]       = vStartNew + (cone[0] - vStart);
2148         coneNew[1]       = vStartNew + (cone[1] - vStart);
2149         coneNew[(r+1)%2] = newv;
2150         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2151 #if 1
2152         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2153         for (p = 0; p < 2; ++p) {
2154           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2155         }
2156 #endif
2157         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2158         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2159         for (s = 0; s < supportSize; ++s) {
2160           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2161           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2162           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2163           for (c = 0; c < coneSize; ++c) if (cone[c] == f) break;
2164           if (support[s] >= cMax) {
2165             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[c] < 0 ? 1-r : r);
2166           } else {
2167             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
2168           }
2169         }
2170         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2171 #if 1
2172         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2173         for (p = 0; p < supportSize; ++p) {
2174           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
2175         }
2176 #endif
2177       }
2178     }
2179     /* Interior cell faces have 2 vertices and 2 cells */
2180     for (c = cStart; c < cMax; ++c) {
2181       const PetscInt *cone;
2182 
2183       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2184       for (r = 0; r < 3; ++r) {
2185         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
2186         PetscInt       coneNew[2];
2187         PetscInt       supportNew[2];
2188 
2189         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
2190         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
2191         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2192 #if 1
2193         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2194         for (p = 0; p < 2; ++p) {
2195           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2196         }
2197 #endif
2198         supportNew[0] = (c - cStart)*4 + (r+1)%3;
2199         supportNew[1] = (c - cStart)*4 + 3;
2200         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2201 #if 1
2202         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2203         for (p = 0; p < 2; ++p) {
2204           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
2205         }
2206 #endif
2207       }
2208     }
2209     /* Interior hybrid faces have 2 vertices and the same cells */
2210     for (f = fMax; f < fEnd; ++f) {
2211       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
2212       const PetscInt *cone, *ornt;
2213       const PetscInt *support;
2214       PetscInt        coneNew[2];
2215       PetscInt        supportNew[2];
2216       PetscInt        size, s, r;
2217 
2218       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2219       coneNew[0] = vStartNew + (cone[0] - vStart);
2220       coneNew[1] = vStartNew + (cone[1] - vStart);
2221       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2222 #if 1
2223       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2224       for (p = 0; p < 2; ++p) {
2225         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2226       }
2227 #endif
2228       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2229       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2230       for (s = 0; s < size; ++s) {
2231         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2232         ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2233         for (r = 0; r < 2; ++r) {
2234           if (cone[r+2] == f) break;
2235         }
2236         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[0] < 0 ? 1-r : r);
2237       }
2238       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2239 #if 1
2240       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2241       for (p = 0; p < size; ++p) {
2242         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
2243       }
2244 #endif
2245     }
2246     /* Cell hybrid faces have 2 vertices and 2 cells */
2247     for (c = cMax; c < cEnd; ++c) {
2248       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
2249       const PetscInt *cone;
2250       PetscInt        coneNew[2];
2251       PetscInt        supportNew[2];
2252 
2253       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2254       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
2255       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
2256       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2257 #if 1
2258       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2259       for (p = 0; p < 2; ++p) {
2260         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2261       }
2262 #endif
2263       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
2264       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
2265       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2266 #if 1
2267       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2268       for (p = 0; p < 2; ++p) {
2269         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
2270       }
2271 #endif
2272     }
2273     /* Old vertices have identical supports */
2274     for (v = vStart; v < vEnd; ++v) {
2275       const PetscInt  newp = vStartNew + (v - vStart);
2276       const PetscInt *support, *cone;
2277       PetscInt        size, s;
2278 
2279       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2280       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2281       for (s = 0; s < size; ++s) {
2282         if (support[s] >= fMax) {
2283           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
2284         } else {
2285           PetscInt r = 0;
2286 
2287           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2288           if (cone[1] == v) r = 1;
2289           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2290         }
2291       }
2292       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2293 #if 1
2294       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2295       for (p = 0; p < size; ++p) {
2296         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
2297       }
2298 #endif
2299     }
2300     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
2301     for (f = fStart; f < fMax; ++f) {
2302       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2303       const PetscInt *cone, *support;
2304       PetscInt        size, newSize = 2, s;
2305 
2306       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2307       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2308       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2309       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2310       for (s = 0; s < size; ++s) {
2311         PetscInt r = 0;
2312 
2313         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2314         if (support[s] >= cMax) {
2315           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
2316 
2317           newSize += 1;
2318         } else {
2319           if      (cone[1] == f) r = 1;
2320           else if (cone[2] == f) r = 2;
2321           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
2322           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
2323 
2324           newSize += 2;
2325         }
2326       }
2327       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2328 #if 1
2329       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2330       for (p = 0; p < newSize; ++p) {
2331         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
2332       }
2333 #endif
2334     }
2335     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2336     break;
2337   case REFINER_HYBRID_HEX_2D:
2338     /* Hybrid Hex 2D */
2339     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
2340     cMax = PetscMin(cEnd, cMax);
2341     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
2342     fMax = PetscMin(fEnd, fMax);
2343     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);CHKERRQ(ierr);
2344     /* Interior cells have 4 faces */
2345     for (c = cStart; c < cMax; ++c) {
2346       const PetscInt  newp = cStartNew + (c - cStart)*4;
2347       const PetscInt *cone, *ornt;
2348       PetscInt        coneNew[4], orntNew[4];
2349 
2350       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2351       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2352       /* A quad */
2353       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2354       orntNew[0] = ornt[0];
2355       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
2356       orntNew[1] = 0;
2357       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
2358       orntNew[2] = -2;
2359       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
2360       orntNew[3] = ornt[3];
2361       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2362       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2363 #if 1
2364       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+0, cStartNew, cMaxNew);
2365       for (p = 0; p < 4; ++p) {
2366         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2367       }
2368 #endif
2369       /* B quad */
2370       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2371       orntNew[0] = ornt[0];
2372       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2373       orntNew[1] = ornt[1];
2374       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
2375       orntNew[2] = 0;
2376       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
2377       orntNew[3] = -2;
2378       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2379       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2380 #if 1
2381       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+1, cStartNew, cMaxNew);
2382       for (p = 0; p < 4; ++p) {
2383         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2384       }
2385 #endif
2386       /* C quad */
2387       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
2388       orntNew[0] = -2;
2389       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2390       orntNew[1] = ornt[1];
2391       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2392       orntNew[2] = ornt[2];
2393       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
2394       orntNew[3] = 0;
2395       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2396       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2397 #if 1
2398       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+2, cStartNew, cMaxNew);
2399       for (p = 0; p < 4; ++p) {
2400         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2401       }
2402 #endif
2403       /* D quad */
2404       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
2405       orntNew[0] = 0;
2406       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
2407       orntNew[1] = -2;
2408       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2409       orntNew[2] = ornt[2];
2410       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
2411       orntNew[3] = ornt[3];
2412       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2413       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2414 #if 1
2415       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+3, cStartNew, cMaxNew);
2416       for (p = 0; p < 4; ++p) {
2417         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2418       }
2419 #endif
2420     }
2421     /*
2422      2----3----3
2423      |         |
2424      |    B    |
2425      |         |
2426      0----4--- 1
2427      |         |
2428      |    A    |
2429      |         |
2430      0----2----1
2431      */
2432     /* Hybrid cells have 4 faces */
2433     for (c = cMax; c < cEnd; ++c) {
2434       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
2435       const PetscInt *cone, *ornt;
2436       PetscInt        coneNew[4], orntNew[4];
2437 
2438       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2439       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2440       /* A quad */
2441       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2442       orntNew[0] = ornt[0];
2443       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2444       orntNew[1] = ornt[1];
2445       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[2] - fMax);
2446       orntNew[2] = 0;
2447       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
2448       orntNew[3] = 0;
2449       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2450       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2451 #if 1
2452       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
2453       for (p = 0; p < 4; ++p) {
2454         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2455       }
2456 #endif
2457       /* B quad */
2458       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2459       orntNew[0] = ornt[0];
2460       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2461       orntNew[1] = ornt[1];
2462       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
2463       orntNew[2] = 0;
2464       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[3] - fMax);
2465       orntNew[3] = 0;
2466       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2467       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2468 #if 1
2469       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
2470       for (p = 0; p < 4; ++p) {
2471         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2472       }
2473 #endif
2474     }
2475     /* Interior split faces have 2 vertices and the same cells as the parent */
2476     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2477     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2478     for (f = fStart; f < fMax; ++f) {
2479       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
2480 
2481       for (r = 0; r < 2; ++r) {
2482         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2483         const PetscInt *cone, *ornt, *support;
2484         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2485 
2486         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2487         coneNew[0]       = vStartNew + (cone[0] - vStart);
2488         coneNew[1]       = vStartNew + (cone[1] - vStart);
2489         coneNew[(r+1)%2] = newv;
2490         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2491 #if 1
2492         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2493         for (p = 0; p < 2; ++p) {
2494           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2495         }
2496 #endif
2497         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2498         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2499         for (s = 0; s < supportSize; ++s) {
2500           if (support[s] >= cMax) {
2501             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
2502           } else {
2503             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2504             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2505             ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2506             for (c = 0; c < coneSize; ++c) {
2507               if (cone[c] == f) break;
2508             }
2509             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
2510           }
2511         }
2512         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2513 #if 1
2514         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2515         for (p = 0; p < supportSize; ++p) {
2516           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
2517         }
2518 #endif
2519       }
2520     }
2521     /* Interior cell faces have 2 vertices and 2 cells */
2522     for (c = cStart; c < cMax; ++c) {
2523       const PetscInt *cone;
2524 
2525       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2526       for (r = 0; r < 4; ++r) {
2527         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
2528         PetscInt       coneNew[2], supportNew[2];
2529 
2530         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2531         coneNew[1] = vStartNew + (vEnd - vStart) + (fMax    - fStart) + (c - cStart);
2532         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2533 #if 1
2534         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2535         for (p = 0; p < 2; ++p) {
2536           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2537         }
2538 #endif
2539         supportNew[0] = (c - cStart)*4 + r;
2540         supportNew[1] = (c - cStart)*4 + (r+1)%4;
2541         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2542 #if 1
2543         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2544         for (p = 0; p < 2; ++p) {
2545           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
2546         }
2547 #endif
2548       }
2549     }
2550     /* Hybrid faces have 2 vertices and the same cells */
2551     for (f = fMax; f < fEnd; ++f) {
2552       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
2553       const PetscInt *cone, *support;
2554       PetscInt        coneNew[2], supportNew[2];
2555       PetscInt        size, s, r;
2556 
2557       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2558       coneNew[0] = vStartNew + (cone[0] - vStart);
2559       coneNew[1] = vStartNew + (cone[1] - vStart);
2560       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2561 #if 1
2562       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2563       for (p = 0; p < 2; ++p) {
2564         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2565       }
2566 #endif
2567       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2568       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2569       for (s = 0; s < size; ++s) {
2570         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2571         for (r = 0; r < 2; ++r) {
2572           if (cone[r+2] == f) break;
2573         }
2574         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
2575       }
2576       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2577 #if 1
2578       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2579       for (p = 0; p < size; ++p) {
2580         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
2581       }
2582 #endif
2583     }
2584     /* Cell hybrid faces have 2 vertices and 2 cells */
2585     for (c = cMax; c < cEnd; ++c) {
2586       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
2587       const PetscInt *cone;
2588       PetscInt        coneNew[2], supportNew[2];
2589 
2590       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2591       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
2592       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
2593       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2594 #if 1
2595       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2596       for (p = 0; p < 2; ++p) {
2597         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2598       }
2599 #endif
2600       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
2601       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
2602       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2603 #if 1
2604       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2605       for (p = 0; p < 2; ++p) {
2606         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
2607       }
2608 #endif
2609     }
2610     /* Old vertices have identical supports */
2611     for (v = vStart; v < vEnd; ++v) {
2612       const PetscInt  newp = vStartNew + (v - vStart);
2613       const PetscInt *support, *cone;
2614       PetscInt        size, s;
2615 
2616       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2617       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2618       for (s = 0; s < size; ++s) {
2619         if (support[s] >= fMax) {
2620           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (support[s] - fMax);
2621         } else {
2622           PetscInt r = 0;
2623 
2624           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2625           if (cone[1] == v) r = 1;
2626           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2627         }
2628       }
2629       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2630 #if 1
2631       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2632       for (p = 0; p < size; ++p) {
2633         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
2634       }
2635 #endif
2636     }
2637     /* Face vertices have 2 + cells supports */
2638     for (f = fStart; f < fMax; ++f) {
2639       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2640       const PetscInt *cone, *support;
2641       PetscInt        size, s;
2642 
2643       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2644       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2645       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2646       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2647       for (s = 0; s < size; ++s) {
2648         PetscInt r = 0;
2649 
2650         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2651         if (support[s] >= cMax) {
2652           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (support[s] - cMax);
2653         } else {
2654           if      (cone[1] == f) r = 1;
2655           else if (cone[2] == f) r = 2;
2656           else if (cone[3] == f) r = 3;
2657           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*4 + r;
2658         }
2659       }
2660       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2661 #if 1
2662       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2663       for (p = 0; p < 2+size; ++p) {
2664         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
2665       }
2666 #endif
2667     }
2668     /* Cell vertices have 4 supports */
2669     for (c = cStart; c < cMax; ++c) {
2670       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
2671       PetscInt       supportNew[4];
2672 
2673       for (r = 0; r < 4; ++r) {
2674         supportNew[r] = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
2675       }
2676       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2677     }
2678     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2679     break;
2680   case REFINER_SIMPLEX_3D:
2681     /* All cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
2682     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
2683     for (c = cStart; c < cEnd; ++c) {
2684       const PetscInt  newp = cStartNew + (c - cStart)*8;
2685       const PetscInt *cone, *ornt;
2686       PetscInt        coneNew[4], orntNew[4];
2687 
2688       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2689       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2690       /* A tetrahedron: {0, a, c, d} */
2691       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
2692       orntNew[0] = ornt[0];
2693       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
2694       orntNew[1] = ornt[1];
2695       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
2696       orntNew[2] = ornt[2];
2697       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
2698       orntNew[3] = 0;
2699       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2700       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2701 #if 1
2702       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
2703       for (p = 0; p < 4; ++p) {
2704         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2705       }
2706 #endif
2707       /* B tetrahedron: {a, 1, b, e} */
2708       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
2709       orntNew[0] = ornt[0];
2710       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
2711       orntNew[1] = ornt[1];
2712       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
2713       orntNew[2] = 0;
2714       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
2715       orntNew[3] = ornt[3];
2716       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2717       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2718 #if 1
2719       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
2720       for (p = 0; p < 4; ++p) {
2721         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2722       }
2723 #endif
2724       /* C tetrahedron: {c, b, 2, f} */
2725       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
2726       orntNew[0] = ornt[0];
2727       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
2728       orntNew[1] = 0;
2729       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
2730       orntNew[2] = ornt[2];
2731       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
2732       orntNew[3] = ornt[3];
2733       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2734       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2735 #if 1
2736       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
2737       for (p = 0; p < 4; ++p) {
2738         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2739       }
2740 #endif
2741       /* D tetrahedron: {d, e, f, 3} */
2742       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
2743       orntNew[0] = 0;
2744       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
2745       orntNew[1] = ornt[1];
2746       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
2747       orntNew[2] = ornt[2];
2748       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
2749       orntNew[3] = ornt[3];
2750       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2751       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2752 #if 1
2753       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
2754       for (p = 0; p < 4; ++p) {
2755         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2756       }
2757 #endif
2758       /* A' tetrahedron: {c, d, a, f} */
2759       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
2760       orntNew[0] = -3;
2761       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
2762       orntNew[1] = ornt[2] < 0 ? -(GetTriMidEdge_Static(ornt[2], 0)+1) : GetTriMidEdge_Static(ornt[2], 0);
2763       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
2764       orntNew[2] = 0;
2765       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
2766       orntNew[3] = 2;
2767       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
2768       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
2769 #if 1
2770       if ((newp+4 < cStartNew) || (newp+4 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+4, cStartNew, cEndNew);
2771       for (p = 0; p < 4; ++p) {
2772         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2773       }
2774 #endif
2775       /* B' tetrahedron: {e, b, a, f} */
2776       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
2777       orntNew[0] = -2;
2778       coneNew[1] = fStartNew + (cone[3] - fStart)*4 + 3;
2779       orntNew[1] = ornt[3] < 0 ? -(GetTriMidEdge_Static(ornt[3], 1)+1) : GetTriMidEdge_Static(ornt[3], 1);
2780       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
2781       orntNew[2] = 0;
2782       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
2783       orntNew[3] = 0;
2784       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
2785       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
2786 #if 1
2787       if ((newp+5 < cStartNew) || (newp+5 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+5, cStartNew, cEndNew);
2788       for (p = 0; p < 4; ++p) {
2789         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2790       }
2791 #endif
2792       /* C' tetrahedron: {f, a, c, b} */
2793       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
2794       orntNew[0] = -2;
2795       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
2796       orntNew[1] = -2;
2797       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
2798       orntNew[2] = -1;
2799       coneNew[3] = fStartNew + (cone[0] - fStart)*4 + 3;
2800       orntNew[3] = ornt[0] < 0 ? -(GetTriMidEdge_Static(ornt[0], 2)+1) : GetTriMidEdge_Static(ornt[0], 2);
2801       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
2802       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
2803 #if 1
2804       if ((newp+6 < cStartNew) || (newp+6 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+6, cStartNew, cEndNew);
2805       for (p = 0; p < 4; ++p) {
2806         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2807       }
2808 #endif
2809       /* D' tetrahedron: {f, a, e, d} */
2810       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
2811       orntNew[0] = -2;
2812       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
2813       orntNew[1] = -1;
2814       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
2815       orntNew[2] = -2;
2816       coneNew[3] = fStartNew + (cone[1] - fStart)*4 + 3;
2817       orntNew[3] = ornt[1] < 0 ? -(GetTriMidEdge_Static(ornt[1], 1)+1) : GetTriMidEdge_Static(ornt[1], 1);
2818       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
2819       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
2820 #if 1
2821       if ((newp+7 < cStartNew) || (newp+7 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+7, cStartNew, cEndNew);
2822       for (p = 0; p < 4; ++p) {
2823         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2824       }
2825 #endif
2826     }
2827     /* Split faces have 3 edges and the same cells as the parent */
2828     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2829     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2830     for (f = fStart; f < fEnd; ++f) {
2831       const PetscInt  newp = fStartNew + (f - fStart)*4;
2832       const PetscInt *cone, *ornt, *support;
2833       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
2834 
2835       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2836       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
2837       /* A triangle */
2838       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
2839       orntNew[0] = ornt[0];
2840       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
2841       orntNew[1] = -2;
2842       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
2843       orntNew[2] = ornt[2];
2844       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2845       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2846 #if 1
2847       if ((newp+0 < fStartNew) || (newp+0 >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+0, fStartNew, fEndNew);
2848       for (p = 0; p < 3; ++p) {
2849         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
2850       }
2851 #endif
2852       /* B triangle */
2853       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
2854       orntNew[0] = ornt[0];
2855       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
2856       orntNew[1] = ornt[1];
2857       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
2858       orntNew[2] = -2;
2859       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2860       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2861 #if 1
2862       if ((newp+1 < fStartNew) || (newp+1 >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+1, fStartNew, fEndNew);
2863       for (p = 0; p < 3; ++p) {
2864         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
2865       }
2866 #endif
2867       /* C triangle */
2868       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
2869       orntNew[0] = -2;
2870       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
2871       orntNew[1] = ornt[1];
2872       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
2873       orntNew[2] = ornt[2];
2874       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2875       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2876 #if 1
2877       if ((newp+2 < fStartNew) || (newp+2 >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+2, fStartNew, fEndNew);
2878       for (p = 0; p < 3; ++p) {
2879         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
2880       }
2881 #endif
2882       /* D triangle */
2883       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
2884       orntNew[0] = 0;
2885       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
2886       orntNew[1] = 0;
2887       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
2888       orntNew[2] = 0;
2889       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2890       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2891 #if 1
2892       if ((newp+3 < fStartNew) || (newp+3 >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+3, fStartNew, fEndNew);
2893       for (p = 0; p < 3; ++p) {
2894         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
2895       }
2896 #endif
2897       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2898       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2899       for (r = 0; r < 4; ++r) {
2900         for (s = 0; s < supportSize; ++s) {
2901           PetscInt subf;
2902           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2903           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2904           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2905           for (c = 0; c < coneSize; ++c) {
2906             if (cone[c] == f) break;
2907           }
2908           subf = GetTriSubfaceInverse_Static(ornt[c], r);
2909           supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
2910         }
2911         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
2912 #if 1
2913         if ((newp+r < fStartNew) || (newp+r >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+r, fStartNew, fEndNew);
2914         for (p = 0; p < supportSize; ++p) {
2915           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
2916         }
2917 #endif
2918       }
2919     }
2920     /* Interior faces have 3 edges and 2 cells */
2921     for (c = cStart; c < cEnd; ++c) {
2922       PetscInt        newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8;
2923       const PetscInt *cone, *ornt;
2924       PetscInt        coneNew[3], orntNew[3];
2925       PetscInt        supportNew[2];
2926 
2927       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2928       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2929       /* Face A: {c, a, d} */
2930       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
2931       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2932       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
2933       orntNew[1] = ornt[1] < 0 ? -2 : 0;
2934       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 2);
2935       orntNew[2] = ornt[2] < 0 ? -2 : 0;
2936       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2937       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2938 #if 1
2939       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2940       for (p = 0; p < 3; ++p) {
2941         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
2942       }
2943 #endif
2944       supportNew[0] = (c - cStart)*8 + 0;
2945       supportNew[1] = (c - cStart)*8 + 0+4;
2946       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2947 #if 1
2948       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2949       for (p = 0; p < 2; ++p) {
2950         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
2951       }
2952 #endif
2953       ++newp;
2954       /* Face B: {a, b, e} */
2955       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
2956       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2957       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 0);
2958       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2959       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
2960       orntNew[2] = ornt[1] < 0 ? -2 : 0;
2961       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2962       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2963 #if 1
2964       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2965       for (p = 0; p < 3; ++p) {
2966         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
2967       }
2968 #endif
2969       supportNew[0] = (c - cStart)*8 + 1;
2970       supportNew[1] = (c - cStart)*8 + 1+4;
2971       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2972 #if 1
2973       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2974       for (p = 0; p < 2; ++p) {
2975         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
2976       }
2977 #endif
2978       ++newp;
2979       /* Face C: {c, f, b} */
2980       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
2981       orntNew[0] = ornt[2] < 0 ? -2 : 0;
2982       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
2983       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2984       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 1);
2985       orntNew[2] = ornt[0] < 0 ? -2 : 0;
2986       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2987       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2988 #if 1
2989       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2990       for (p = 0; p < 3; ++p) {
2991         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
2992       }
2993 #endif
2994       supportNew[0] = (c - cStart)*8 + 2;
2995       supportNew[1] = (c - cStart)*8 + 2+4;
2996       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2997 #if 1
2998       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2999       for (p = 0; p < 2; ++p) {
3000         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
3001       }
3002 #endif
3003       ++newp;
3004       /* Face D: {d, e, f} */
3005       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 0);
3006       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3007       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3008       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3009       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3010       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3011       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3012       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3013 #if 1
3014       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3015       for (p = 0; p < 3; ++p) {
3016         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3017       }
3018 #endif
3019       supportNew[0] = (c - cStart)*8 + 3;
3020       supportNew[1] = (c - cStart)*8 + 3+4;
3021       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3022 #if 1
3023       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3024       for (p = 0; p < 2; ++p) {
3025         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
3026       }
3027 #endif
3028       ++newp;
3029       /* Face E: {d, f, a} */
3030       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3031       orntNew[0] = ornt[2] < 0 ? 0 : -2;
3032       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3033       orntNew[1] = -2;
3034       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3035       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3036       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3037       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3038 #if 1
3039       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3040       for (p = 0; p < 3; ++p) {
3041         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3042       }
3043 #endif
3044       supportNew[0] = (c - cStart)*8 + 0+4;
3045       supportNew[1] = (c - cStart)*8 + 3+4;
3046       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3047 #if 1
3048       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3049       for (p = 0; p < 2; ++p) {
3050         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
3051       }
3052 #endif
3053       ++newp;
3054       /* Face F: {c, a, f} */
3055       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3056       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3057       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3058       orntNew[1] = 0;
3059       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3060       orntNew[2] = ornt[2] < 0 ? 0 : -2;
3061       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3062       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3063 #if 1
3064       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3065       for (p = 0; p < 3; ++p) {
3066         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3067       }
3068 #endif
3069       supportNew[0] = (c - cStart)*8 + 0+4;
3070       supportNew[1] = (c - cStart)*8 + 2+4;
3071       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3072 #if 1
3073       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3074       for (p = 0; p < 2; ++p) {
3075         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
3076       }
3077 #endif
3078       ++newp;
3079       /* Face G: {e, a, f} */
3080       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3081       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3082       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3083       orntNew[1] = 0;
3084       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3085       orntNew[2] = ornt[3] < 0 ? 0 : -2;
3086       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3087       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3088 #if 1
3089       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3090       for (p = 0; p < 3; ++p) {
3091         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3092       }
3093 #endif
3094       supportNew[0] = (c - cStart)*8 + 1+4;
3095       supportNew[1] = (c - cStart)*8 + 3+4;
3096       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3097 #if 1
3098       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3099       for (p = 0; p < 2; ++p) {
3100         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
3101       }
3102 #endif
3103       ++newp;
3104       /* Face H: {a, b, f} */
3105       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3106       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3107       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3108       orntNew[1] = ornt[3] < 0 ? 0 : -2;
3109       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3110       orntNew[2] = -2;
3111       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3112       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3113 #if 1
3114       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3115       for (p = 0; p < 3; ++p) {
3116         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3117       }
3118 #endif
3119       supportNew[0] = (c - cStart)*8 + 1+4;
3120       supportNew[1] = (c - cStart)*8 + 2+4;
3121       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3122 #if 1
3123       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3124       for (p = 0; p < 2; ++p) {
3125         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
3126       }
3127 #endif
3128       ++newp;
3129     }
3130     /* Split Edges have 2 vertices and the same faces as the parent */
3131     for (e = eStart; e < eEnd; ++e) {
3132       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
3133 
3134       for (r = 0; r < 2; ++r) {
3135         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
3136         const PetscInt *cone, *ornt, *support;
3137         PetscInt        coneNew[2], coneSize, c, supportSize, s;
3138 
3139         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3140         coneNew[0]       = vStartNew + (cone[0] - vStart);
3141         coneNew[1]       = vStartNew + (cone[1] - vStart);
3142         coneNew[(r+1)%2] = newv;
3143         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3144 #if 1
3145         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3146         for (p = 0; p < 2; ++p) {
3147           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
3148         }
3149 #endif
3150         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
3151         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3152         for (s = 0; s < supportSize; ++s) {
3153           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3154           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3155           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3156           for (c = 0; c < coneSize; ++c) {
3157             if (cone[c] == e) break;
3158           }
3159           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
3160         }
3161         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3162 #if 1
3163         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3164         for (p = 0; p < supportSize; ++p) {
3165           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
3166         }
3167 #endif
3168       }
3169     }
3170     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
3171     for (f = fStart; f < fEnd; ++f) {
3172       const PetscInt *cone, *ornt, *support;
3173       PetscInt        coneSize, supportSize, s;
3174 
3175       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3176       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3177       for (r = 0; r < 3; ++r) {
3178         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
3179         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
3180         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
3181                                     -1, -1,  1,  6,  0,  4,
3182                                      2,  5,  3,  4, -1, -1,
3183                                     -1, -1,  3,  6,  2,  7};
3184 
3185         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3186         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
3187         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
3188         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3189 #if 1
3190         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3191         for (p = 0; p < 2; ++p) {
3192           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
3193         }
3194 #endif
3195         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
3196         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
3197         for (s = 0; s < supportSize; ++s) {
3198           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3199           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3200           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3201           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
3202           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
3203           er = GetTriMidEdgeInverse_Static(ornt[c], r);
3204           if (er == eint[c]) {
3205             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
3206           } else {
3207             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
3208             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
3209           }
3210         }
3211         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3212 #if 1
3213         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3214         for (p = 0; p < intFaces; ++p) {
3215           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
3216         }
3217 #endif
3218       }
3219     }
3220     /* Interior edges have 2 vertices and 4 faces */
3221     for (c = cStart; c < cEnd; ++c) {
3222       const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3223       const PetscInt *cone, *ornt, *fcone;
3224       PetscInt        coneNew[2], supportNew[4], find;
3225 
3226       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3227       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3228       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
3229       find = GetTriEdge_Static(ornt[0], 0);
3230       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3231       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
3232       find = GetTriEdge_Static(ornt[2], 1);
3233       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3234       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3235 #if 1
3236       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3237       for (p = 0; p < 2; ++p) {
3238         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
3239       }
3240 #endif
3241       supportNew[0] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 4;
3242       supportNew[1] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 5;
3243       supportNew[2] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 6;
3244       supportNew[3] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 7;
3245       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3246 #if 1
3247       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3248       for (p = 0; p < 4; ++p) {
3249         if ((supportNew[p] < fStartNew) || (supportNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportNew[p], fStartNew, fEndNew);
3250       }
3251 #endif
3252     }
3253     /* Old vertices have identical supports */
3254     for (v = vStart; v < vEnd; ++v) {
3255       const PetscInt  newp = vStartNew + (v - vStart);
3256       const PetscInt *support, *cone;
3257       PetscInt        size, s;
3258 
3259       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
3260       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
3261       for (s = 0; s < size; ++s) {
3262         PetscInt r = 0;
3263 
3264         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3265         if (cone[1] == v) r = 1;
3266         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
3267       }
3268       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3269 #if 1
3270       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3271       for (p = 0; p < size; ++p) {
3272         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
3273       }
3274 #endif
3275     }
3276     /* Edge vertices have 2 + face*2 + 0/1 supports */
3277     for (e = eStart; e < eEnd; ++e) {
3278       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
3279       const PetscInt *cone, *support;
3280       PetscInt       *star = NULL, starSize, cellSize = 0, coneSize, size, s;
3281 
3282       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
3283       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3284       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
3285       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
3286       for (s = 0; s < size; ++s) {
3287         PetscInt r = 0;
3288 
3289         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3290         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3291         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
3292         supportRef[2+s*2+0] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
3293         supportRef[2+s*2+1] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
3294       }
3295       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
3296       for (s = 0; s < starSize*2; s += 2) {
3297         const PetscInt *cone, *ornt;
3298         PetscInt        e01, e23;
3299 
3300         if ((star[s] >= cStart) && (star[s] < cEnd)) {
3301           /* Check edge 0-1 */
3302           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
3303           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
3304           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
3305           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
3306           /* Check edge 2-3 */
3307           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
3308           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
3309           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
3310           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
3311           if ((e01 == e) || (e23 == e)) {supportRef[2+size*2+cellSize++] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (star[s] - cStart);}
3312         }
3313       }
3314       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
3315       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3316 #if 1
3317       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3318       for (p = 0; p < 2+size*2+cellSize; ++p) {
3319         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
3320       }
3321 #endif
3322     }
3323     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3324     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
3325     break;
3326   case REFINER_HYBRID_SIMPLEX_3D:
3327     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
3328     /* Interior cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
3329     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
3330     for (c = cStart; c < cMax; ++c) {
3331       const PetscInt  newp = cStartNew + (c - cStart)*8;
3332       const PetscInt *cone, *ornt;
3333       PetscInt        coneNew[4], orntNew[4];
3334 
3335       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3336       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3337       /* A tetrahedron: {0, a, c, d} */
3338       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
3339       orntNew[0] = ornt[0];
3340       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
3341       orntNew[1] = ornt[1];
3342       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
3343       orntNew[2] = ornt[2];
3344       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
3345       orntNew[3] = 0;
3346       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3347       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3348 #if 1
3349       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cMaxNew);
3350       for (p = 0; p < 4; ++p) {
3351         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3352       }
3353 #endif
3354       /* B tetrahedron: {a, 1, b, e} */
3355       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
3356       orntNew[0] = ornt[0];
3357       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
3358       orntNew[1] = ornt[1];
3359       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
3360       orntNew[2] = 0;
3361       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
3362       orntNew[3] = ornt[3];
3363       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3364       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3365 #if 1
3366       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cMaxNew);
3367       for (p = 0; p < 4; ++p) {
3368         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3369       }
3370 #endif
3371       /* C tetrahedron: {c, b, 2, f} */
3372       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
3373       orntNew[0] = ornt[0];
3374       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
3375       orntNew[1] = 0;
3376       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
3377       orntNew[2] = ornt[2];
3378       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
3379       orntNew[3] = ornt[3];
3380       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3381       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3382 #if 1
3383       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cMaxNew);
3384       for (p = 0; p < 4; ++p) {
3385         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3386       }
3387 #endif
3388       /* D tetrahedron: {d, e, f, 3} */
3389       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
3390       orntNew[0] = 0;
3391       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
3392       orntNew[1] = ornt[1];
3393       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
3394       orntNew[2] = ornt[2];
3395       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
3396       orntNew[3] = ornt[3];
3397       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3398       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3399 #if 1
3400       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cMaxNew);
3401       for (p = 0; p < 4; ++p) {
3402         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3403       }
3404 #endif
3405       /* A' tetrahedron: {d, a, c, f} */
3406       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
3407       orntNew[0] = -3;
3408       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
3409       orntNew[1] = ornt[2] < 0 ? -(GetTriMidEdge_Static(ornt[2], 0)+1) : GetTriMidEdge_Static(ornt[2], 0);
3410       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
3411       orntNew[2] = 0;
3412       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
3413       orntNew[3] = 2;
3414       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
3415       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
3416 #if 1
3417       if ((newp+4 < cStartNew) || (newp+4 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+4, cStartNew, cMaxNew);
3418       for (p = 0; p < 4; ++p) {
3419         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3420       }
3421 #endif
3422       /* B' tetrahedron: {e, b, a, f} */
3423       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
3424       orntNew[0] = -3;
3425       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
3426       orntNew[1] = 1;
3427       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
3428       orntNew[2] = 0;
3429       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + 3;
3430       orntNew[3] = ornt[3] < 0 ? -(GetTriMidEdge_Static(ornt[3], 0)+1) : GetTriMidEdge_Static(ornt[3], 0);
3431       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
3432       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
3433 #if 1
3434       if ((newp+5 < cStartNew) || (newp+5 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+5, cStartNew, cMaxNew);
3435       for (p = 0; p < 4; ++p) {
3436         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3437       }
3438 #endif
3439       /* C' tetrahedron: {b, f, c, a} */
3440       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
3441       orntNew[0] = -3;
3442       coneNew[1] = fStartNew + (cone[0] - fStart)*4 + 3;
3443       orntNew[1] = ornt[0] < 0 ? -(GetTriMidEdge_Static(ornt[0], 2)+1) : GetTriMidEdge_Static(ornt[0], 2);
3444       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
3445       orntNew[2] = -3;
3446       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
3447       orntNew[3] = -2;
3448       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
3449       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
3450 #if 1
3451       if ((newp+6 < cStartNew) || (newp+6 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+6, cStartNew, cMaxNew);
3452       for (p = 0; p < 4; ++p) {
3453         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3454       }
3455 #endif
3456       /* D' tetrahedron: {f, e, d, a} */
3457       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
3458       orntNew[0] = -3;
3459       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
3460       orntNew[1] = -3;
3461       coneNew[2] = fStartNew + (cone[1] - fStart)*4 + 3;
3462       orntNew[2] = ornt[1] < 0 ? -(GetTriMidEdge_Static(ornt[1], 0)+1) : GetTriMidEdge_Static(ornt[1], 0);
3463       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
3464       orntNew[3] = -3;
3465       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
3466       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
3467 #if 1
3468       if ((newp+7 < cStartNew) || (newp+7 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+7, cStartNew, cMaxNew);
3469       for (p = 0; p < 4; ++p) {
3470         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3471       }
3472 #endif
3473     }
3474     /* Hybrid cells have 5 faces */
3475     for (c = cMax; c < cEnd; ++c) {
3476       const PetscInt  newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4;
3477       const PetscInt *cone, *ornt, *fornt;
3478       PetscInt        coneNew[5], orntNew[5], o, of, i;
3479 
3480       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3481       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3482       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
3483       o = ornt[0] < 0 ? -1 : 1;
3484       for (r = 0; r < 3; ++r) {
3485         coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], r);
3486         orntNew[0] = ornt[0];
3487         coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], r);
3488         orntNew[1] = ornt[1];
3489         of = fornt[GetTriEdge_Static(ornt[0], r)]       < 0 ? -1 : 1;
3490         i  = GetTriEdgeInverse_Static(ornt[0], r)       + 2;
3491         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], r)]       - fMax)*2 + (o*of < 0 ? 1 : 0);
3492         orntNew[i] = 0;
3493         i  = GetTriEdgeInverse_Static(ornt[0], (r+1)%3) + 2;
3494         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + GetTriSubface_Static(ornt[0], r);
3495         orntNew[i] = 0;
3496         of = fornt[GetTriEdge_Static(ornt[0], (r+2)%3)] < 0 ? -1 : 1;
3497         i  = GetTriEdgeInverse_Static(ornt[0], (r+2)%3) + 2;
3498         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);
3499         orntNew[i] = 0;
3500         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
3501         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
3502 #if 1
3503         if ((newp+r < cMaxNew) || (newp+r >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", newp+r, cMaxNew, cEndNew);
3504         for (p = 0; p < 2; ++p) {
3505           if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3506         }
3507         for (p = 2; p < 5; ++p) {
3508           if ((coneNew[p] < fMaxNew)   || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", coneNew[p], fMaxNew, fEndNew);
3509         }
3510 #endif
3511       }
3512       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + 3;
3513       orntNew[0] = 0;
3514       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + 3;
3515       orntNew[1] = 0;
3516       coneNew[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
3517       orntNew[2] = 0;
3518       coneNew[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
3519       orntNew[3] = 0;
3520       coneNew[4] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
3521       orntNew[4] = 0;
3522       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3523       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3524 #if 1
3525       if ((newp+3 < cMaxNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", newp+3, cMaxNew, cEndNew);
3526       for (p = 0; p < 2; ++p) {
3527         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3528       }
3529       for (p = 2; p < 5; ++p) {
3530         if ((coneNew[p] < fMaxNew)   || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", coneNew[p], fMaxNew, fEndNew);
3531       }
3532 #endif
3533     }
3534     /* Split faces have 3 edges and the same cells as the parent */
3535     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3536     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
3537     for (f = fStart; f < fMax; ++f) {
3538       const PetscInt  newp = fStartNew + (f - fStart)*4;
3539       const PetscInt *cone, *ornt, *support;
3540       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
3541 
3542       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3543       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3544       /* A triangle */
3545       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
3546       orntNew[0] = ornt[0];
3547       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
3548       orntNew[1] = -2;
3549       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
3550       orntNew[2] = ornt[2];
3551       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3552       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3553 #if 1
3554       if ((newp+0 < fStartNew) || (newp+0 >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+0, fStartNew, fMaxNew);
3555       for (p = 0; p < 3; ++p) {
3556         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3557       }
3558 #endif
3559       /* B triangle */
3560       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
3561       orntNew[0] = ornt[0];
3562       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
3563       orntNew[1] = ornt[1];
3564       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
3565       orntNew[2] = -2;
3566       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3567       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3568 #if 1
3569       if ((newp+1 < fStartNew) || (newp+1 >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+1, fStartNew, fMaxNew);
3570       for (p = 0; p < 3; ++p) {
3571         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3572       }
3573 #endif
3574       /* C triangle */
3575       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
3576       orntNew[0] = -2;
3577       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
3578       orntNew[1] = ornt[1];
3579       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
3580       orntNew[2] = ornt[2];
3581       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3582       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3583 #if 1
3584       if ((newp+2 < fStartNew) || (newp+2 >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+2, fStartNew, fMaxNew);
3585       for (p = 0; p < 3; ++p) {
3586         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3587       }
3588 #endif
3589       /* D triangle */
3590       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
3591       orntNew[0] = 0;
3592       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
3593       orntNew[1] = 0;
3594       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
3595       orntNew[2] = 0;
3596       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3597       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3598 #if 1
3599       if ((newp+3 < fStartNew) || (newp+3 >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+3, fStartNew, fMaxNew);
3600       for (p = 0; p < 3; ++p) {
3601         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3602       }
3603 #endif
3604       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3605       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3606       for (r = 0; r < 4; ++r) {
3607         for (s = 0; s < supportSize; ++s) {
3608           PetscInt subf;
3609           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3610           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3611           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3612           for (c = 0; c < coneSize; ++c) {
3613             if (cone[c] == f) break;
3614           }
3615           subf = GetTriSubfaceInverse_Static(ornt[c], r);
3616           if (support[s] < cMax) {
3617             supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
3618           } else {
3619             supportRef[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (r==3 ? r : subf);
3620           }
3621         }
3622         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
3623 #if 1
3624         if ((newp+r < fStartNew) || (newp+r >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+r, fStartNew, fMaxNew);
3625         for (p = 0; p < supportSize; ++p) {
3626           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior or hybrid cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
3627         }
3628 #endif
3629       }
3630     }
3631     /* Interior cell faces have 3 edges and 2 cells */
3632     for (c = cStart; c < cMax; ++c) {
3633       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8;
3634       const PetscInt *cone, *ornt;
3635       PetscInt        coneNew[3], orntNew[3];
3636       PetscInt        supportNew[2];
3637 
3638       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3639       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3640       /* Face A: {c, a, d} */
3641       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3642       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3643       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3644       orntNew[1] = ornt[1] < 0 ? -2 : 0;
3645       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 2);
3646       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3647       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3648       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3649 #if 1
3650       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3651       for (p = 0; p < 3; ++p) {
3652         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3653       }
3654 #endif
3655       supportNew[0] = (c - cStart)*8 + 0;
3656       supportNew[1] = (c - cStart)*8 + 0+4;
3657       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3658 #if 1
3659       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3660       for (p = 0; p < 2; ++p) {
3661         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
3662       }
3663 #endif
3664       ++newp;
3665       /* Face B: {a, b, e} */
3666       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3667       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3668       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 0);
3669       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3670       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3671       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3672       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3673       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3674 #if 1
3675       if ((newp+1 < fStartNew) || (newp+1 >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+1, fStartNew, fMaxNew);
3676       for (p = 0; p < 3; ++p) {
3677         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3678       }
3679 #endif
3680       supportNew[0] = (c - cStart)*8 + 1;
3681       supportNew[1] = (c - cStart)*8 + 1+4;
3682       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3683 #if 1
3684       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3685       for (p = 0; p < 2; ++p) {
3686         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
3687       }
3688 #endif
3689       ++newp;
3690       /* Face C: {c, f, b} */
3691       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3692       orntNew[0] = ornt[2] < 0 ? -2 : 0;
3693       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3694       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3695       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 1);
3696       orntNew[2] = ornt[0] < 0 ? -2 : 0;
3697       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3698       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3699 #if 1
3700       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3701       for (p = 0; p < 3; ++p) {
3702         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3703       }
3704 #endif
3705       supportNew[0] = (c - cStart)*8 + 2;
3706       supportNew[1] = (c - cStart)*8 + 2+4;
3707       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3708 #if 1
3709       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3710       for (p = 0; p < 2; ++p) {
3711         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
3712       }
3713 #endif
3714       ++newp;
3715       /* Face D: {d, e, f} */
3716       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 0);
3717       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3718       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3719       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3720       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3721       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3722       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3723       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3724 #if 1
3725       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3726       for (p = 0; p < 3; ++p) {
3727         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3728       }
3729 #endif
3730       supportNew[0] = (c - cStart)*8 + 3;
3731       supportNew[1] = (c - cStart)*8 + 3+4;
3732       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3733 #if 1
3734       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3735       for (p = 0; p < 2; ++p) {
3736         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
3737       }
3738 #endif
3739       ++newp;
3740       /* Face E: {d, f, a} */
3741       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3742       orntNew[0] = ornt[2] < 0 ? 0 : -2;
3743       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3744       orntNew[1] = -2;
3745       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3746       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3747       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3748       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3749 #if 1
3750       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3751       for (p = 0; p < 3; ++p) {
3752         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3753       }
3754 #endif
3755       supportNew[0] = (c - cStart)*8 + 0+4;
3756       supportNew[1] = (c - cStart)*8 + 3+4;
3757       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3758 #if 1
3759       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3760       for (p = 0; p < 2; ++p) {
3761         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
3762       }
3763 #endif
3764       ++newp;
3765       /* Face F: {c, a, f} */
3766       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3767       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3768       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3769       orntNew[1] = 0;
3770       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3771       orntNew[2] = ornt[2] < 0 ? 0 : -2;
3772       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3773       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3774 #if 1
3775       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3776       for (p = 0; p < 3; ++p) {
3777         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3778       }
3779 #endif
3780       supportNew[0] = (c - cStart)*8 + 0+4;
3781       supportNew[1] = (c - cStart)*8 + 2+4;
3782       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3783 #if 1
3784       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3785       for (p = 0; p < 2; ++p) {
3786         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
3787       }
3788 #endif
3789       ++newp;
3790       /* Face G: {e, a, f} */
3791       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3792       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3793       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3794       orntNew[1] = 0;
3795       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3796       orntNew[2] = ornt[3] < 0 ? 0 : -2;
3797       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3798       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3799 #if 1
3800       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3801       for (p = 0; p < 3; ++p) {
3802         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3803       }
3804 #endif
3805       supportNew[0] = (c - cStart)*8 + 1+4;
3806       supportNew[1] = (c - cStart)*8 + 3+4;
3807       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3808 #if 1
3809       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3810       for (p = 0; p < 2; ++p) {
3811         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
3812       }
3813 #endif
3814       ++newp;
3815       /* Face H: {a, b, f} */
3816       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3817       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3818       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3819       orntNew[1] = ornt[3] < 0 ? 0 : -2;
3820       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3821       orntNew[2] = -2;
3822       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3823       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3824 #if 1
3825       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3826       for (p = 0; p < 3; ++p) {
3827         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3828       }
3829 #endif
3830       supportNew[0] = (c - cStart)*8 + 1+4;
3831       supportNew[1] = (c - cStart)*8 + 2+4;
3832       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3833 #if 1
3834       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3835       for (p = 0; p < 2; ++p) {
3836         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
3837       }
3838 #endif
3839       ++newp;
3840     }
3841     /* Hybrid split faces have 4 edges and same cells */
3842     for (f = fMax; f < fEnd; ++f) {
3843       const PetscInt *cone, *ornt, *support;
3844       PetscInt        coneNew[4], orntNew[4];
3845       PetscInt        supportNew[2], size, s, c;
3846 
3847       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3848       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3849       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3850       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3851       for (r = 0; r < 2; ++r) {
3852         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
3853 
3854         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
3855         orntNew[0]   = ornt[0];
3856         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
3857         orntNew[1]   = ornt[1];
3858         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (cone[2+r] - eMax);
3859         orntNew[2+r] = 0;
3860         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd      - eMax) + (f - fMax);
3861         orntNew[3-r] = 0;
3862         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3863         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3864 #if 1
3865         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
3866         for (p = 0; p < 2; ++p) {
3867           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3868         }
3869         for (p = 2; p < 4; ++p) {
3870           if ((coneNew[p] < eMaxNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", coneNew[p], eMaxNew, eEndNew);
3871         }
3872 #endif
3873         for (s = 0; s < size; ++s) {
3874           const PetscInt *coneCell, *orntCell, *fornt;
3875           PetscInt        o, of;
3876 
3877           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
3878           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
3879           o = orntCell[0] < 0 ? -1 : 1;
3880           for (c = 2; c < 5; ++c) if (coneCell[c] == f) break;
3881           if (c >= 5) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
3882           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
3883           of = fornt[c-2] < 0 ? -1 : 1;
3884           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetTriEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%3;
3885         }
3886         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3887 #if 1
3888         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
3889         for (p = 0; p < size; ++p) {
3890           if ((supportNew[p] < cMaxNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", supportNew[p], cMaxNew, cEndNew);
3891         }
3892 #endif
3893       }
3894     }
3895     /* Hybrid cell faces have 4 edges and 2 cells */
3896     for (c = cMax; c < cEnd; ++c) {
3897       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3;
3898       const PetscInt *cone, *ornt;
3899       PetscInt        coneNew[4], orntNew[4];
3900       PetscInt        supportNew[2];
3901 
3902       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3903       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3904       for (r = 0; r < 3; ++r) {
3905         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + (r+2)%3;
3906         orntNew[0] = 0;
3907         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + (r+2)%3;
3908         orntNew[1] = 0;
3909         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+(r+2)%3] - fMax);
3910         orntNew[2] = 0;
3911         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+r]       - fMax);
3912         orntNew[3] = 0;
3913         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
3914         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
3915 #if 1
3916         if ((newp+r < fMaxNew) || (newp+r >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp+r, fMaxNew, fEndNew);
3917         for (p = 0; p < 2; ++p) {
3918           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3919         }
3920         for (p = 2; p < 4; ++p) {
3921           if ((coneNew[p] < eMaxNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", coneNew[p], eMaxNew, eEndNew);
3922         }
3923 #endif
3924         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetTriSubface_Static(ornt[0], r);
3925         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + 3;
3926         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
3927 #if 1
3928         if ((newp+r < fMaxNew) || (newp+r >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp+r, fMaxNew, fEndNew);
3929         for (p = 0; p < 2; ++p) {
3930           if ((supportNew[p] < cMaxNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", supportNew[p], cMaxNew, cEndNew);
3931         }
3932 #endif
3933       }
3934     }
3935     /* Interior split edges have 2 vertices and the same faces as the parent */
3936     for (e = eStart; e < eMax; ++e) {
3937       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
3938 
3939       for (r = 0; r < 2; ++r) {
3940         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
3941         const PetscInt *cone, *ornt, *support;
3942         PetscInt        coneNew[2], coneSize, c, supportSize, s;
3943 
3944         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3945         coneNew[0]       = vStartNew + (cone[0] - vStart);
3946         coneNew[1]       = vStartNew + (cone[1] - vStart);
3947         coneNew[(r+1)%2] = newv;
3948         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3949 #if 1
3950         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3951         for (p = 0; p < 2; ++p) {
3952           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
3953         }
3954 #endif
3955         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
3956         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3957         for (s = 0; s < supportSize; ++s) {
3958           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3959           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3960           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3961           for (c = 0; c < coneSize; ++c) if (cone[c] == e) break;
3962           if (support[s] < fMax) {
3963             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
3964           } else {
3965             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
3966           }
3967         }
3968         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3969 #if 1
3970         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3971         for (p = 0; p < supportSize; ++p) {
3972           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior or hybrid face [%d, %d)", supportRef[p], fStartNew, fEndNew);
3973         }
3974 #endif
3975       }
3976     }
3977     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
3978     for (f = fStart; f < fMax; ++f) {
3979       const PetscInt *cone, *ornt, *support;
3980       PetscInt        coneSize, supportSize, s;
3981 
3982       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3983       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3984       for (r = 0; r < 3; ++r) {
3985         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
3986         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
3987         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
3988                                     -1, -1,  1,  6,  0,  4,
3989                                      2,  5,  3,  4, -1, -1,
3990                                     -1, -1,  3,  6,  2,  7};
3991 
3992         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3993         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
3994         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
3995         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3996 #if 1
3997         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3998         for (p = 0; p < 2; ++p) {
3999           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4000         }
4001 #endif
4002         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
4003         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
4004         for (s = 0; s < supportSize; ++s) {
4005           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4006           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4007           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4008           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
4009           if (support[s] < cMax) {
4010             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
4011             er = GetTriMidEdgeInverse_Static(ornt[c], r);
4012             if (er == eint[c]) {
4013               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
4014             } else {
4015               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
4016               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
4017             }
4018           } else {
4019             supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (r + 1)%3;
4020           }
4021         }
4022         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4023 #if 1
4024         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4025         for (p = 0; p < intFaces; ++p) {
4026           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior or hybrid face [%d, %d)", supportRef[p], fStartNew, fEndNew);
4027         }
4028 #endif
4029       }
4030     }
4031     /* Interior cell edges have 2 vertices and 4 faces */
4032     for (c = cStart; c < cMax; ++c) {
4033       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4034       const PetscInt *cone, *ornt, *fcone;
4035       PetscInt        coneNew[2], supportNew[4], find;
4036 
4037       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4038       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4039       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
4040       find = GetTriEdge_Static(ornt[0], 0);
4041       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4042       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
4043       find = GetTriEdge_Static(ornt[2], 1);
4044       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4045       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4046 #if 1
4047       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4048       for (p = 0; p < 2; ++p) {
4049         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4050       }
4051 #endif
4052       supportNew[0] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 4;
4053       supportNew[1] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 5;
4054       supportNew[2] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 6;
4055       supportNew[3] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 7;
4056       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4057 #if 1
4058       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4059       for (p = 0; p < 4; ++p) {
4060         if ((supportNew[p] < fStartNew) || (supportNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportNew[p], fStartNew, fMaxNew);
4061       }
4062 #endif
4063     }
4064     /* Hybrid edges have two vertices and the same faces */
4065     for (e = eMax; e < eEnd; ++e) {
4066       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
4067       const PetscInt *cone, *support, *fcone;
4068       PetscInt        coneNew[2], size, fsize, s;
4069 
4070       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4071       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4072       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4073       coneNew[0] = vStartNew + (cone[0] - vStart);
4074       coneNew[1] = vStartNew + (cone[1] - vStart);
4075       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4076 #if 1
4077       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4078       for (p = 0; p < 2; ++p) {
4079         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4080       }
4081 #endif
4082       for (s = 0; s < size; ++s) {
4083         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
4084         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
4085         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
4086         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
4087         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + c-2;
4088       }
4089       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4090 #if 1
4091       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4092       for (p = 0; p < size; ++p) {
4093         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", supportRef[p], fMaxNew, fEndNew);
4094       }
4095 #endif
4096     }
4097     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
4098     for (f = fMax; f < fEnd; ++f) {
4099       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
4100       const PetscInt *cone, *support, *ccone, *cornt;
4101       PetscInt        coneNew[2], size, csize, s;
4102 
4103       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4104       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4105       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4106       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
4107       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
4108       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4109 #if 1
4110       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4111       for (p = 0; p < 2; ++p) {
4112         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4113       }
4114 #endif
4115       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 0;
4116       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 1;
4117       for (s = 0; s < size; ++s) {
4118         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
4119         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
4120         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
4121         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
4122         if ((c < 2) || (c >= csize)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Hybrid face %d is not in cone of hybrid cell %d", f, support[s]);
4123         supportRef[2+s*2+0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + c-2;
4124         supportRef[2+s*2+1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (c-1)%3;
4125       }
4126       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4127 #if 1
4128       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4129       for (p = 0; p < 2+size*2; ++p) {
4130         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", supportRef[p], fMaxNew, fEndNew);
4131       }
4132 #endif
4133     }
4134     /* Interior vertices have identical supports */
4135     for (v = vStart; v < vEnd; ++v) {
4136       const PetscInt  newp = vStartNew + (v - vStart);
4137       const PetscInt *support, *cone;
4138       PetscInt        size, s;
4139 
4140       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4141       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4142       for (s = 0; s < size; ++s) {
4143         PetscInt r = 0;
4144 
4145         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4146         if (cone[1] == v) r = 1;
4147         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4148         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (support[s] - eMax);
4149       }
4150       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4151 #if 1
4152       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4153       for (p = 0; p < size; ++p) {
4154         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior or hybrid edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
4155       }
4156 #endif
4157     }
4158     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
4159     for (e = eStart; e < eMax; ++e) {
4160       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4161       const PetscInt *cone, *support;
4162       PetscInt       *star = NULL, starSize, faceSize = 0, cellSize = 0, coneSize, size, s;
4163 
4164       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4165       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4166       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4167       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4168       for (s = 0; s < size; ++s) {
4169         PetscInt r = 0;
4170 
4171         if (support[s] < fMax) {
4172           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4173           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4174           for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
4175           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
4176           supportRef[2+faceSize+1] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
4177           faceSize += 2;
4178         } else {
4179           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (support[s] - fMax);
4180           ++faceSize;
4181         }
4182       }
4183       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4184       for (s = 0; s < starSize*2; s += 2) {
4185         const PetscInt *cone, *ornt;
4186         PetscInt        e01, e23;
4187 
4188         if ((star[s] >= cStart) && (star[s] < cMax)) {
4189           /* Check edge 0-1 */
4190           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
4191           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
4192           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
4193           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
4194           /* Check edge 2-3 */
4195           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
4196           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
4197           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
4198           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
4199           if ((e01 == e) || (e23 == e)) {supportRef[2+faceSize+cellSize++] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (star[s] - cStart);}
4200         }
4201       }
4202       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4203       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4204 #if 1
4205       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4206       for (p = 0; p < 2+faceSize+cellSize; ++p) {
4207         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior or hybrid edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
4208       }
4209 #endif
4210     }
4211     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4212     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
4213     break;
4214   case REFINER_SIMPLEX_TO_HEX_3D:
4215     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
4216     /* All cells have 6 faces */
4217     for (c = cStart; c < cEnd; ++c) {
4218       const PetscInt  newp = cStartNew + (c - cStart)*4;
4219       const PetscInt *cone, *ornt;
4220       PetscInt        coneNew[6];
4221       PetscInt        orntNew[6];
4222 
4223       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4224       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4225       /* A hex */
4226       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 0); /* B */
4227       orntNew[0] = ornt[0] < 0 ? -1 : 1;
4228       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 3;               /* T */
4229       orntNew[1] = -4;
4230       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 0); /* F */
4231       orntNew[2] = ornt[2] < 0 ? -1 : 1;
4232       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 0;               /* K */
4233       orntNew[3] = -1;
4234       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 2;               /* R */
4235       orntNew[4] = 0;
4236       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 0); /* L */
4237       orntNew[5] = ornt[1] < 0 ? -1 : 1;
4238       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4239       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4240 #if 1
4241       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
4242       for (p = 0; p < 6; ++p) {
4243         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4244       }
4245 #endif
4246       /* B hex */
4247       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 1); /* B */
4248       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4249       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 4;               /* T */
4250       orntNew[1] = 0;
4251       coneNew[2] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 0;               /* F */
4252       orntNew[2] = 0;
4253       coneNew[3] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 1); /* K */
4254       orntNew[3] = ornt[3] < 0 ? -2 : 0;
4255       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 1;               /* R */
4256       orntNew[4] = 0;
4257       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 2); /* L */
4258       orntNew[5] = ornt[1] < 0 ? -4 : 2;
4259       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4260       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4261 #if 1
4262       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
4263       for (p = 0; p < 6; ++p) {
4264         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4265       }
4266 #endif
4267       /* C hex */
4268       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 2); /* B */
4269       orntNew[0] = ornt[0] < 0 ? -4 : 2;
4270       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 5;               /* T */
4271       orntNew[1] = -4;
4272       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 1); /* F */
4273       orntNew[2] = ornt[2] < 0 ? -2 : 0;
4274       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 1;               /* K */
4275       orntNew[3] = -1;
4276       coneNew[4] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 0); /* R */
4277       orntNew[4] = ornt[3] < 0 ? -1 : 1;
4278       coneNew[5] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 2;               /* L */
4279       orntNew[5] = -4;
4280       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4281       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4282 #if 1
4283       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
4284       for (p = 0; p < 6; ++p) {
4285         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4286       }
4287 #endif
4288       /* D hex */
4289       coneNew[0] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 3;               /* B */
4290       orntNew[0] = 0;
4291       coneNew[1] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 2); /* T */
4292       orntNew[1] = ornt[3] < 0 ? -1 : 1;
4293       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 2); /* F */
4294       orntNew[2] = ornt[2] < 0 ? -4 : 2;
4295       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 4;               /* K */
4296       orntNew[3] = -1;
4297       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 5;               /* R */
4298       orntNew[4] = 0;
4299       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 1); /* L */
4300       orntNew[5] = ornt[1] < 0 ? -2 : 0;
4301       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4302       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4303 #if 1
4304       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
4305       for (p = 0; p < 6; ++p) {
4306         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4307       }
4308 #endif
4309     }
4310     /* Split faces have 4 edges and the same cells as the parent */
4311     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4312     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
4313     for (f = fStart; f < fEnd; ++f) {
4314       const PetscInt  newp = fStartNew + (f - fStart)*3;
4315       const PetscInt *cone, *ornt, *support;
4316       PetscInt        coneNew[4], orntNew[4], coneSize, supportSize, s;
4317 
4318       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4319       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4320       /* A quad */
4321       coneNew[0] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
4322       orntNew[0] = ornt[2];
4323       coneNew[1] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
4324       orntNew[1] = ornt[0];
4325       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
4326       orntNew[2] = 0;
4327       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
4328       orntNew[3] = -2;
4329       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4330       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4331 #if 1
4332       if ((newp+0 < fStartNew) || (newp+0 >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+0, fStartNew, fEndNew);
4333       for (p = 0; p < 4; ++p) {
4334         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
4335       }
4336 #endif
4337       /* B quad */
4338       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
4339       orntNew[0] = ornt[0];
4340       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
4341       orntNew[1] = ornt[1];
4342       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
4343       orntNew[2] = 0;
4344       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
4345       orntNew[3] = -2;
4346       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4347       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4348 #if 1
4349       if ((newp+1 < fStartNew) || (newp+1 >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+1, fStartNew, fEndNew);
4350       for (p = 0; p < 4; ++p) {
4351         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
4352       }
4353 #endif
4354       /* C quad */
4355       coneNew[0] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
4356       orntNew[0] = ornt[1];
4357       coneNew[1] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
4358       orntNew[1] = ornt[2];
4359       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
4360       orntNew[2] = 0;
4361       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
4362       orntNew[3] = -2;
4363       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4364       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4365 #if 1
4366       if ((newp+2 < fStartNew) || (newp+2 >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+2, fStartNew, fEndNew);
4367       for (p = 0; p < 4; ++p) {
4368         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
4369       }
4370 #endif
4371       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4372       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4373       for (r = 0; r < 3; ++r) {
4374         for (s = 0; s < supportSize; ++s) {
4375           PetscInt subf;
4376           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4377           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4378           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4379           for (c = 0; c < coneSize; ++c) {
4380             if (cone[c] == f) break;
4381           }
4382           subf = GetTriSubfaceInverse_Static(ornt[c], r);
4383           supportRef[s] = cStartNew + (support[s] - cStart)*4 + faces[c*3+subf];
4384         }
4385         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
4386 #if 1
4387         if ((newp+r < fStartNew) || (newp+r >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+r, fStartNew, fEndNew);
4388         for (p = 0; p < supportSize; ++p) {
4389           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
4390         }
4391 #endif
4392       }
4393     }
4394     /* Interior faces have 4 edges and 2 cells */
4395     for (c = cStart; c < cEnd; ++c) {
4396       PetscInt        newp = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6;
4397       const PetscInt *cone, *ornt;
4398       PetscInt        coneNew[4], orntNew[4];
4399       PetscInt        supportNew[2];
4400 
4401       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4402       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4403       /* Face {a, g, m, h} */
4404       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],0);
4405       orntNew[0] = 0;
4406       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
4407       orntNew[1] = 0;
4408       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
4409       orntNew[2] = -2;
4410       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],2);
4411       orntNew[3] = -2;
4412       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4413       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4414 #if 1
4415       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4416       for (p = 0; p < 4; ++p) {
4417         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
4418       }
4419 #endif
4420       supportNew[0] = (c - cStart)*4 + 0;
4421       supportNew[1] = (c - cStart)*4 + 1;
4422       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4423 #if 1
4424       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4425       for (p = 0; p < 2; ++p) {
4426         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
4427       }
4428 #endif
4429       ++newp;
4430       /* Face {g, b, l , m} */
4431       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],1);
4432       orntNew[0] = -2;
4433       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],0);
4434       orntNew[1] = 0;
4435       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
4436       orntNew[2] = 0;
4437       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
4438       orntNew[3] = -2;
4439       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4440       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4441 #if 1
4442       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4443       for (p = 0; p < 4; ++p) {
4444         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
4445       }
4446 #endif
4447       supportNew[0] = (c - cStart)*4 + 1;
4448       supportNew[1] = (c - cStart)*4 + 2;
4449       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4450 #if 1
4451       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4452       for (p = 0; p < 2; ++p) {
4453         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
4454       }
4455 #endif
4456       ++newp;
4457       /* Face {c, g, m, i} */
4458       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],2);
4459       orntNew[0] = 0;
4460       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
4461       orntNew[1] = 0;
4462       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
4463       orntNew[2] = -2;
4464       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],0);
4465       orntNew[3] = -2;
4466       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4467       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4468 #if 1
4469       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4470       for (p = 0; p < 4; ++p) {
4471         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
4472       }
4473 #endif
4474       supportNew[0] = (c - cStart)*4 + 0;
4475       supportNew[1] = (c - cStart)*4 + 2;
4476       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4477 #if 1
4478       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4479       for (p = 0; p < 2; ++p) {
4480         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
4481       }
4482 #endif
4483       ++newp;
4484       /* Face {d, h, m, i} */
4485       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],0);
4486       orntNew[0] = 0;
4487       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
4488       orntNew[1] = 0;
4489       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
4490       orntNew[2] = -2;
4491       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],2);
4492       orntNew[3] = -2;
4493       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4494       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4495 #if 1
4496       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4497       for (p = 0; p < 4; ++p) {
4498         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
4499       }
4500 #endif
4501       supportNew[0] = (c - cStart)*4 + 0;
4502       supportNew[1] = (c - cStart)*4 + 3;
4503       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4504 #if 1
4505       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4506       for (p = 0; p < 2; ++p) {
4507         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
4508       }
4509 #endif
4510       ++newp;
4511       /* Face {h, m, l, e} */
4512       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
4513       orntNew[0] = 0;
4514       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
4515       orntNew[1] = -2;
4516       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],1);
4517       orntNew[2] = -2;
4518       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],1);
4519       orntNew[3] = 0;
4520       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4521       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4522 #if 1
4523       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4524       for (p = 0; p < 4; ++p) {
4525         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
4526       }
4527 #endif
4528       supportNew[0] = (c - cStart)*4 + 1;
4529       supportNew[1] = (c - cStart)*4 + 3;
4530       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4531 #if 1
4532       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4533       for (p = 0; p < 2; ++p) {
4534         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
4535       }
4536 #endif
4537       ++newp;
4538       /* Face {i, m, l, f} */
4539       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
4540       orntNew[0] = 0;
4541       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
4542       orntNew[1] = -2;
4543       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],2);
4544       orntNew[2] = -2;
4545       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],1);
4546       orntNew[3] = 0;
4547       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4548       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4549 #if 1
4550       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4551       for (p = 0; p < 4; ++p) {
4552         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
4553       }
4554 #endif
4555       supportNew[0] = (c - cStart)*4 + 2;
4556       supportNew[1] = (c - cStart)*4 + 3;
4557       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4558 #if 1
4559       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4560       for (p = 0; p < 2; ++p) {
4561         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
4562       }
4563 #endif
4564       ++newp;
4565     }
4566     /* Split Edges have 2 vertices and the same faces as the parent */
4567     for (e = eStart; e < eEnd; ++e) {
4568       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
4569 
4570       for (r = 0; r < 2; ++r) {
4571         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
4572         const PetscInt *cone, *ornt, *support;
4573         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4574 
4575         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4576         coneNew[0]       = vStartNew + (cone[0] - vStart);
4577         coneNew[1]       = vStartNew + (cone[1] - vStart);
4578         coneNew[(r+1)%2] = newv;
4579         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4580 #if 1
4581         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4582         for (p = 0; p < 2; ++p) {
4583           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4584         }
4585 #endif
4586         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
4587         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4588         for (s = 0; s < supportSize; ++s) {
4589           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4590           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4591           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4592           for (c = 0; c < coneSize; ++c) {
4593             if (cone[c] == e) break;
4594           }
4595           supportRef[s] = fStartNew + (support[s] - fStart)*3 + (c + (ornt[c] < 0 ? 1-r : r))%3;
4596         }
4597         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4598 #if 1
4599         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4600         for (p = 0; p < supportSize; ++p) {
4601           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
4602         }
4603 #endif
4604       }
4605     }
4606     /* Face edges have 2 vertices and 2 + cell faces supports */
4607     for (f = fStart; f < fEnd; ++f) {
4608       const PetscInt *cone, *ornt, *support;
4609       PetscInt        coneSize, supportSize, s;
4610 
4611       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4612       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4613       for (r = 0; r < 3; ++r) {
4614         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
4615         PetscInt        coneNew[2];
4616         PetscInt        fint[4][3] = { {0, 1, 2},
4617                                        {3, 4, 0},
4618                                        {2, 5, 3},
4619                                        {1, 4, 5} };
4620 
4621         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4622         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
4623         coneNew[1] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + f - fStart;
4624         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4625 #if 1
4626         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4627         for (p = 0; p < 2; ++p) {
4628           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4629         }
4630 #endif
4631         supportRef[0] = fStartNew + (f - fStart)*3 + (r+0)%3;
4632         supportRef[1] = fStartNew + (f - fStart)*3 + (r+1)%3;
4633         for (s = 0; s < supportSize; ++s) {
4634           PetscInt er;
4635           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4636           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4637           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4638           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
4639           er = GetTriInteriorEdgeInverse_Static(ornt[c], r);
4640           supportRef[2+s] = fStartNew + (fEnd - fStart)*3 + (support[s] - cStart)*6 + fint[c][er];
4641         }
4642         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4643 #if 1
4644         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4645         for (p = 0; p < supportSize + 2; ++p) {
4646           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
4647         }
4648 #endif
4649       }
4650     }
4651     /* Interior cell edges have 2 vertices and 3 faces */
4652     for (c = cStart; c < cEnd; ++c) {
4653       const PetscInt *cone;
4654       PetscInt       fint[4][3] = { {0,1,2},
4655                                     {0,3,4},
4656                                     {2,3,5},
4657                                     {1,4,5} } ;
4658 
4659       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4660       for (r = 0; r < 4; r++) {
4661         PetscInt       coneNew[2], supportNew[3];
4662         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + r;
4663 
4664         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
4665         coneNew[1] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd -fStart) + c - cStart;
4666         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4667 #if 1
4668         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4669         for (p = 0; p < 2; ++p) {
4670           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4671         }
4672 #endif
4673         supportNew[0] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][0];
4674         supportNew[1] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][1];
4675         supportNew[2] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][2];
4676         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4677 #if 1
4678         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4679         for (p = 0; p < 3; ++p) {
4680           if ((supportNew[p] < fStartNew) || (supportNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportNew[p], fStartNew, fEndNew);
4681         }
4682 #endif
4683       }
4684     }
4685     /* Old vertices have identical supports */
4686     for (v = vStart; v < vEnd; ++v) {
4687       const PetscInt  newp = vStartNew + (v - vStart);
4688       const PetscInt *support, *cone;
4689       PetscInt        size, s;
4690 
4691       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4692       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4693       for (s = 0; s < size; ++s) {
4694         PetscInt r = 0;
4695 
4696         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4697         if (cone[1] == v) r = 1;
4698         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4699       }
4700       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4701 #if 1
4702       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4703       for (p = 0; p < size; ++p) {
4704         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
4705       }
4706 #endif
4707     }
4708     /* Edge vertices have 2 + faces supports */
4709     for (e = eStart; e < eEnd; ++e) {
4710       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4711       const PetscInt *cone, *support;
4712       PetscInt        size, s;
4713 
4714       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4715       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4716       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4717       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4718       for (s = 0; s < size; ++s) {
4719         PetscInt r = 0, coneSize;
4720 
4721         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4722         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4723         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
4724         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + r;
4725       }
4726       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4727 #if 1
4728       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4729       for (p = 0; p < 2+size; ++p) {
4730         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
4731       }
4732 #endif
4733     }
4734     /* Face vertices have 3 + cells supports */
4735     for (f = fStart; f < fEnd; ++f) {
4736       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
4737       const PetscInt *cone, *support;
4738       PetscInt        size, s;
4739 
4740       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4741       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4742       supportRef[0] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 0;
4743       supportRef[1] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 1;
4744       supportRef[2] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 2;
4745       for (s = 0; s < size; ++s) {
4746         PetscInt r = 0, coneSize;
4747 
4748         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4749         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4750         for (r = 0; r < coneSize; ++r) {if (cone[r] == f) break;}
4751         supportRef[3+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (support[s] - cStart)*4 + r;
4752       }
4753       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4754 #if 1
4755       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4756       for (p = 0; p < 3+size; ++p) {
4757         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
4758       }
4759 #endif
4760     }
4761     /* Interior cell vertices have 4 supports */
4762     for (c = cStart; c < cEnd; ++c) {
4763       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + c - cStart;
4764       supportRef[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
4765       supportRef[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
4766       supportRef[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
4767       supportRef[3] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
4768       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4769 #if 1
4770       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4771       for (p = 0; p < 4; ++p) {
4772         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
4773       }
4774 #endif
4775     }
4776     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4777     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
4778     break;
4779   case REFINER_HEX_3D:
4780     /*
4781      Bottom (viewed from top)    Top
4782      1---------2---------2       7---------2---------6
4783      |         |         |       |         |         |
4784      |    B    2    C    |       |    H    2    G    |
4785      |         |         |       |         |         |
4786      3----3----0----1----1       3----3----0----1----1
4787      |         |         |       |         |         |
4788      |    A    0    D    |       |    E    0    F    |
4789      |         |         |       |         |         |
4790      0---------0---------3       4---------0---------5
4791      */
4792     /* All cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
4793     for (c = cStart; c < cEnd; ++c) {
4794       const PetscInt  newp = (c - cStart)*8;
4795       const PetscInt *cone, *ornt;
4796       PetscInt        coneNew[6], orntNew[6];
4797 
4798       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4799       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4800       /* A hex */
4801       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
4802       orntNew[0] = ornt[0];
4803       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
4804       orntNew[1] = 0;
4805       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
4806       orntNew[2] = ornt[2];
4807       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
4808       orntNew[3] = 0;
4809       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
4810       orntNew[4] = 0;
4811       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
4812       orntNew[5] = ornt[5];
4813       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4814       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4815 #if 1
4816       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
4817       for (p = 0; p < 6; ++p) {
4818         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4819       }
4820 #endif
4821       /* B hex */
4822       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
4823       orntNew[0] = ornt[0];
4824       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
4825       orntNew[1] = 0;
4826       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
4827       orntNew[2] = -1;
4828       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
4829       orntNew[3] = ornt[3];
4830       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
4831       orntNew[4] = 0;
4832       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
4833       orntNew[5] = ornt[5];
4834       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4835       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4836 #if 1
4837       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
4838       for (p = 0; p < 6; ++p) {
4839         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4840       }
4841 #endif
4842       /* C hex */
4843       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
4844       orntNew[0] = ornt[0];
4845       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
4846       orntNew[1] = 0;
4847       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
4848       orntNew[2] = -1;
4849       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
4850       orntNew[3] = ornt[3];
4851       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
4852       orntNew[4] = ornt[4];
4853       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
4854       orntNew[5] = -4;
4855       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4856       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4857 #if 1
4858       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
4859       for (p = 0; p < 6; ++p) {
4860         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4861       }
4862 #endif
4863       /* D hex */
4864       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
4865       orntNew[0] = ornt[0];
4866       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
4867       orntNew[1] = 0;
4868       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
4869       orntNew[2] = ornt[2];
4870       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
4871       orntNew[3] = 0;
4872       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
4873       orntNew[4] = ornt[4];
4874       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
4875       orntNew[5] = -4;
4876       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4877       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4878 #if 1
4879       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
4880       for (p = 0; p < 6; ++p) {
4881         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4882       }
4883 #endif
4884       /* E hex */
4885       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
4886       orntNew[0] = -4;
4887       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
4888       orntNew[1] = ornt[1];
4889       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
4890       orntNew[2] = ornt[2];
4891       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
4892       orntNew[3] = 0;
4893       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
4894       orntNew[4] = -1;
4895       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
4896       orntNew[5] = ornt[5];
4897       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
4898       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
4899 #if 1
4900       if ((newp+4 < cStartNew) || (newp+4 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+4, cStartNew, cEndNew);
4901       for (p = 0; p < 6; ++p) {
4902         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4903       }
4904 #endif
4905       /* F hex */
4906       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
4907       orntNew[0] = -4;
4908       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
4909       orntNew[1] = ornt[1];
4910       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
4911       orntNew[2] = ornt[2];
4912       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4913       orntNew[3] = -1;
4914       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
4915       orntNew[4] = ornt[4];
4916       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
4917       orntNew[5] = 1;
4918       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
4919       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
4920 #if 1
4921       if ((newp+5 < cStartNew) || (newp+5 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+5, cStartNew, cEndNew);
4922       for (p = 0; p < 6; ++p) {
4923         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4924       }
4925 #endif
4926       /* G hex */
4927       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
4928       orntNew[0] = -4;
4929       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
4930       orntNew[1] = ornt[1];
4931       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4932       orntNew[2] = 0;
4933       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
4934       orntNew[3] = ornt[3];
4935       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
4936       orntNew[4] = ornt[4];
4937       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
4938       orntNew[5] = -3;
4939       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
4940       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
4941 #if 1
4942       if ((newp+6 < cStartNew) || (newp+6 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+6, cStartNew, cEndNew);
4943       for (p = 0; p < 6; ++p) {
4944         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4945       }
4946 #endif
4947       /* H hex */
4948       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
4949       orntNew[0] = -4;
4950       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
4951       orntNew[1] = ornt[1];
4952       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
4953       orntNew[2] = -1;
4954       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
4955       orntNew[3] = ornt[3];
4956       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
4957       orntNew[4] = 3;
4958       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
4959       orntNew[5] = ornt[5];
4960       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
4961       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
4962 #if 1
4963       if ((newp+7 < cStartNew) || (newp+7 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+7, cStartNew, cEndNew);
4964       for (p = 0; p < 6; ++p) {
4965         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4966       }
4967 #endif
4968     }
4969     /* Split faces have 4 edges and the same cells as the parent */
4970     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4971     ierr = PetscMalloc1(4 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
4972     for (f = fStart; f < fEnd; ++f) {
4973       for (r = 0; r < 4; ++r) {
4974         /* TODO: This can come from GetFaces_Internal() */
4975         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};
4976         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
4977         const PetscInt *cone, *ornt, *support;
4978         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
4979 
4980         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4981         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4982         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
4983         orntNew[(r+3)%4] = ornt[(r+3)%4];
4984         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
4985         orntNew[(r+0)%4] = ornt[r];
4986         coneNew[(r+1)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
4987         orntNew[(r+1)%4] = 0;
4988         coneNew[(r+2)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + (r+3)%4;
4989         orntNew[(r+2)%4] = -2;
4990         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4991         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4992 #if 1
4993         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4994         for (p = 0; p < 4; ++p) {
4995           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
4996         }
4997 #endif
4998         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4999         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5000         for (s = 0; s < supportSize; ++s) {
5001           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5002           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5003           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5004           for (c = 0; c < coneSize; ++c) {
5005             if (cone[c] == f) break;
5006           }
5007           supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+GetQuadSubfaceInverse_Static(ornt[c], r)];
5008         }
5009         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5010 #if 1
5011         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5012         for (p = 0; p < supportSize; ++p) {
5013           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
5014         }
5015 #endif
5016       }
5017     }
5018     /* Interior faces have 4 edges and 2 cells */
5019     for (c = cStart; c < cEnd; ++c) {
5020       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};
5021       const PetscInt *cone, *ornt;
5022       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
5023 
5024       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5025       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5026       /* A-D face */
5027       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 0;
5028       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
5029       orntNew[0] = 0;
5030       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
5031       orntNew[1] = 0;
5032       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
5033       orntNew[2] = -2;
5034       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
5035       orntNew[3] = -2;
5036       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5037       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5038 #if 1
5039       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5040       for (p = 0; p < 4; ++p) {
5041         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5042       }
5043 #endif
5044       /* C-D face */
5045       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 1;
5046       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
5047       orntNew[0] = 0;
5048       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
5049       orntNew[1] = 0;
5050       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
5051       orntNew[2] = -2;
5052       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
5053       orntNew[3] = -2;
5054       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5055       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5056 #if 1
5057       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5058       for (p = 0; p < 4; ++p) {
5059         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5060       }
5061 #endif
5062       /* B-C face */
5063       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 2;
5064       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
5065       orntNew[0] = -2;
5066       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
5067       orntNew[1] = 0;
5068       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
5069       orntNew[2] = 0;
5070       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
5071       orntNew[3] = -2;
5072       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5073       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5074 #if 1
5075       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5076       for (p = 0; p < 4; ++p) {
5077         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5078       }
5079 #endif
5080       /* A-B face */
5081       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 3;
5082       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
5083       orntNew[0] = -2;
5084       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
5085       orntNew[1] = 0;
5086       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
5087       orntNew[2] = 0;
5088       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
5089       orntNew[3] = -2;
5090       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5091       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5092 #if 1
5093       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5094       for (p = 0; p < 4; ++p) {
5095         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5096       }
5097 #endif
5098       /* E-F face */
5099       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 4;
5100       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
5101       orntNew[0] = -2;
5102       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
5103       orntNew[1] = -2;
5104       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
5105       orntNew[2] = 0;
5106       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
5107       orntNew[3] = 0;
5108       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5109       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5110 #if 1
5111       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5112       for (p = 0; p < 4; ++p) {
5113         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5114       }
5115 #endif
5116       /* F-G face */
5117       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 5;
5118       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
5119       orntNew[0] = -2;
5120       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
5121       orntNew[1] = -2;
5122       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
5123       orntNew[2] = 0;
5124       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
5125       orntNew[3] = 0;
5126       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5127       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5128 #if 1
5129       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5130       for (p = 0; p < 4; ++p) {
5131         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5132       }
5133 #endif
5134       /* G-H face */
5135       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 6;
5136       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
5137       orntNew[0] = -2;
5138       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
5139       orntNew[1] = 0;
5140       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
5141       orntNew[2] = 0;
5142       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
5143       orntNew[3] = -2;
5144       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5145       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5146 #if 1
5147       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5148       for (p = 0; p < 4; ++p) {
5149         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5150       }
5151 #endif
5152       /* E-H face */
5153       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 7;
5154       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
5155       orntNew[0] = -2;
5156       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
5157       orntNew[1] = -2;
5158       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
5159       orntNew[2] = 0;
5160       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
5161       orntNew[3] = 0;
5162       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5163       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5164 #if 1
5165       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5166       for (p = 0; p < 4; ++p) {
5167         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5168       }
5169 #endif
5170       /* A-E face */
5171       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 8;
5172       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
5173       orntNew[0] = 0;
5174       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
5175       orntNew[1] = 0;
5176       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
5177       orntNew[2] = -2;
5178       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
5179       orntNew[3] = -2;
5180       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5181       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5182 #if 1
5183       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5184       for (p = 0; p < 4; ++p) {
5185         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5186       }
5187 #endif
5188       /* D-F face */
5189       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 9;
5190       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
5191       orntNew[0] = -2;
5192       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
5193       orntNew[1] = 0;
5194       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
5195       orntNew[2] = 0;
5196       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
5197       orntNew[3] = -2;
5198       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5199       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5200 #if 1
5201       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5202       for (p = 0; p < 4; ++p) {
5203         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5204       }
5205 #endif
5206       /* C-G face */
5207       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 10;
5208       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
5209       orntNew[0] = -2;
5210       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
5211       orntNew[1] = -2;
5212       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
5213       orntNew[2] = 0;
5214       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
5215       orntNew[3] = 0;
5216       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5217       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5218 #if 1
5219       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5220       for (p = 0; p < 4; ++p) {
5221         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5222       }
5223 #endif
5224       /* B-H face */
5225       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 11;
5226       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
5227       orntNew[0] = 0;
5228       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
5229       orntNew[1] = -2;
5230       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
5231       orntNew[2] = -2;
5232       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
5233       orntNew[3] = 0;
5234       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5235       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5236 #if 1
5237       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5238       for (p = 0; p < 4; ++p) {
5239         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5240       }
5241 #endif
5242       for (r = 0; r < 12; ++r) {
5243         newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
5244         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
5245         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
5246         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5247 #if 1
5248         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5249         for (p = 0; p < 2; ++p) {
5250           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
5251         }
5252 #endif
5253       }
5254     }
5255     /* Split edges have 2 vertices and the same faces as the parent */
5256     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5257     for (e = eStart; e < eEnd; ++e) {
5258       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
5259 
5260       for (r = 0; r < 2; ++r) {
5261         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
5262         const PetscInt *cone, *ornt, *support;
5263         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5264 
5265         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
5266         coneNew[0]       = vStartNew + (cone[0] - vStart);
5267         coneNew[1]       = vStartNew + (cone[1] - vStart);
5268         coneNew[(r+1)%2] = newv;
5269         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5270 #if 1
5271         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5272         for (p = 0; p < 2; ++p) {
5273           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
5274         }
5275 #endif
5276         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
5277         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5278         for (s = 0; s < supportSize; ++s) {
5279           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5280           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5281           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5282           for (c = 0; c < coneSize; ++c) {
5283             if (cone[c] == e) break;
5284           }
5285           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
5286         }
5287         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5288 #if 1
5289         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5290         for (p = 0; p < supportSize; ++p) {
5291           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
5292         }
5293 #endif
5294       }
5295     }
5296     /* Face edges have 2 vertices and 2+cells faces */
5297     for (f = fStart; f < fEnd; ++f) {
5298       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};
5299       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
5300       const PetscInt *cone, *coneCell, *orntCell, *support;
5301       PetscInt        coneNew[2], coneSize, c, supportSize, s;
5302 
5303       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5304       for (r = 0; r < 4; ++r) {
5305         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
5306 
5307         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
5308         coneNew[1] = newv;
5309         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5310 #if 1
5311         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5312         for (p = 0; p < 2; ++p) {
5313           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
5314         }
5315 #endif
5316         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5317         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5318         supportRef[0] = fStartNew + (f - fStart)*4 + r;
5319         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
5320         for (s = 0; s < supportSize; ++s) {
5321           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5322           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
5323           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
5324           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
5325           supportRef[2+s] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
5326         }
5327         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5328 #if 1
5329         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5330         for (p = 0; p < 2+supportSize; ++p) {
5331           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
5332         }
5333 #endif
5334       }
5335     }
5336     /* Cell edges have 2 vertices and 4 faces */
5337     for (c = cStart; c < cEnd; ++c) {
5338       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};
5339       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
5340       const PetscInt *cone;
5341       PetscInt        coneNew[2], supportNew[4];
5342 
5343       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5344       for (r = 0; r < 6; ++r) {
5345         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
5346 
5347         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
5348         coneNew[1] = newv;
5349         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5350 #if 1
5351         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5352         for (p = 0; p < 2; ++p) {
5353           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
5354         }
5355 #endif
5356         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
5357         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5358 #if 1
5359         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5360         for (p = 0; p < 4; ++p) {
5361           if ((supportNew[p] < fStartNew) || (supportNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportNew[p], fStartNew, fEndNew);
5362         }
5363 #endif
5364       }
5365     }
5366     /* Old vertices have identical supports */
5367     for (v = vStart; v < vEnd; ++v) {
5368       const PetscInt  newp = vStartNew + (v - vStart);
5369       const PetscInt *support, *cone;
5370       PetscInt        size, s;
5371 
5372       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5373       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5374       for (s = 0; s < size; ++s) {
5375         PetscInt r = 0;
5376 
5377         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5378         if (cone[1] == v) r = 1;
5379         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
5380       }
5381       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5382 #if 1
5383       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5384       for (p = 0; p < size; ++p) {
5385         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
5386       }
5387 #endif
5388     }
5389     /* Edge vertices have 2 + faces supports */
5390     for (e = eStart; e < eEnd; ++e) {
5391       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
5392       const PetscInt *cone, *support;
5393       PetscInt        size, s;
5394 
5395       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
5396       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5397       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
5398       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
5399       for (s = 0; s < size; ++s) {
5400         PetscInt r;
5401 
5402         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5403         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
5404         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*4 + r;
5405       }
5406       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5407 #if 1
5408       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5409       for (p = 0; p < 2+size; ++p) {
5410         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
5411       }
5412 #endif
5413     }
5414     /* Face vertices have 4 + cells supports */
5415     for (f = fStart; f < fEnd; ++f) {
5416       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
5417       const PetscInt *cone, *support;
5418       PetscInt        size, s;
5419 
5420       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5421       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5422       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eEnd - eStart)*2 +  (f - fStart)*4 + r;
5423       for (s = 0; s < size; ++s) {
5424         PetscInt r;
5425 
5426         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5427         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
5428         supportRef[4+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (support[s] - cStart)*6 + r;
5429       }
5430       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5431 #if 1
5432       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5433       for (p = 0; p < 4+size; ++p) {
5434         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
5435       }
5436 #endif
5437     }
5438     /* Cell vertices have 6 supports */
5439     for (c = cStart; c < cEnd; ++c) {
5440       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
5441       PetscInt       supportNew[6];
5442 
5443       for (r = 0; r < 6; ++r) {
5444         supportNew[r] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
5445       }
5446       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5447     }
5448     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5449     break;
5450   case REFINER_HYBRID_HEX_3D:
5451     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
5452     /*
5453      Bottom (viewed from top)    Top
5454      1---------2---------2       7---------2---------6
5455      |         |         |       |         |         |
5456      |    B    2    C    |       |    H    2    G    |
5457      |         |         |       |         |         |
5458      3----3----0----1----1       3----3----0----1----1
5459      |         |         |       |         |         |
5460      |    A    0    D    |       |    E    0    F    |
5461      |         |         |       |         |         |
5462      0---------0---------3       4---------0---------5
5463      */
5464     /* Interior cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
5465     for (c = cStart; c < cMax; ++c) {
5466       const PetscInt  newp = (c - cStart)*8;
5467       const PetscInt *cone, *ornt;
5468       PetscInt        coneNew[6], orntNew[6];
5469 
5470       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5471       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5472       /* A hex */
5473       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
5474       orntNew[0] = ornt[0];
5475       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
5476       orntNew[1] = 0;
5477       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
5478       orntNew[2] = ornt[2];
5479       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
5480       orntNew[3] = 0;
5481       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
5482       orntNew[4] = 0;
5483       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
5484       orntNew[5] = ornt[5];
5485       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5486       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5487 #if 1
5488       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cMaxNew);
5489       for (p = 0; p < 6; ++p) {
5490         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
5491       }
5492 #endif
5493       /* B hex */
5494       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
5495       orntNew[0] = ornt[0];
5496       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
5497       orntNew[1] = 0;
5498       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
5499       orntNew[2] = -1;
5500       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
5501       orntNew[3] = ornt[3];
5502       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
5503       orntNew[4] = 0;
5504       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
5505       orntNew[5] = ornt[5];
5506       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5507       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5508 #if 1
5509       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cMaxNew);
5510       for (p = 0; p < 6; ++p) {
5511         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
5512       }
5513 #endif
5514       /* C hex */
5515       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
5516       orntNew[0] = ornt[0];
5517       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
5518       orntNew[1] = 0;
5519       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
5520       orntNew[2] = -1;
5521       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
5522       orntNew[3] = ornt[3];
5523       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
5524       orntNew[4] = ornt[4];
5525       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
5526       orntNew[5] = -4;
5527       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5528       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5529 #if 1
5530       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cMaxNew);
5531       for (p = 0; p < 6; ++p) {
5532         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
5533       }
5534 #endif
5535       /* D hex */
5536       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
5537       orntNew[0] = ornt[0];
5538       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
5539       orntNew[1] = 0;
5540       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
5541       orntNew[2] = ornt[2];
5542       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
5543       orntNew[3] = 0;
5544       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
5545       orntNew[4] = ornt[4];
5546       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
5547       orntNew[5] = -4;
5548       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5549       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5550 #if 1
5551       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cMaxNew);
5552       for (p = 0; p < 6; ++p) {
5553         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
5554       }
5555 #endif
5556       /* E hex */
5557       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
5558       orntNew[0] = -4;
5559       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
5560       orntNew[1] = ornt[1];
5561       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
5562       orntNew[2] = ornt[2];
5563       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
5564       orntNew[3] = 0;
5565       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
5566       orntNew[4] = -1;
5567       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
5568       orntNew[5] = ornt[5];
5569       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
5570       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
5571 #if 1
5572       if ((newp+4 < cStartNew) || (newp+4 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+4, cStartNew, cMaxNew);
5573       for (p = 0; p < 6; ++p) {
5574         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
5575       }
5576 #endif
5577       /* F hex */
5578       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
5579       orntNew[0] = -4;
5580       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
5581       orntNew[1] = ornt[1];
5582       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
5583       orntNew[2] = ornt[2];
5584       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
5585       orntNew[3] = -1;
5586       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
5587       orntNew[4] = ornt[4];
5588       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
5589       orntNew[5] = 1;
5590       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
5591       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
5592 #if 1
5593       if ((newp+5 < cStartNew) || (newp+5 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+5, cStartNew, cMaxNew);
5594       for (p = 0; p < 6; ++p) {
5595         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
5596       }
5597 #endif
5598       /* G hex */
5599       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
5600       orntNew[0] = -4;
5601       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
5602       orntNew[1] = ornt[1];
5603       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
5604       orntNew[2] = 0;
5605       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
5606       orntNew[3] = ornt[3];
5607       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
5608       orntNew[4] = ornt[4];
5609       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
5610       orntNew[5] = -3;
5611       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
5612       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
5613 #if 1
5614       if ((newp+6 < cStartNew) || (newp+6 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+6, cStartNew, cMaxNew);
5615       for (p = 0; p < 6; ++p) {
5616         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
5617       }
5618 #endif
5619       /* H hex */
5620       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
5621       orntNew[0] = -4;
5622       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
5623       orntNew[1] = ornt[1];
5624       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
5625       orntNew[2] = -1;
5626       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
5627       orntNew[3] = ornt[3];
5628       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
5629       orntNew[4] = 3;
5630       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
5631       orntNew[5] = ornt[5];
5632       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
5633       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
5634 #if 1
5635       if ((newp+7 < cStartNew) || (newp+7 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+7, cStartNew, cMaxNew);
5636       for (p = 0; p < 6; ++p) {
5637         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
5638       }
5639 #endif
5640     }
5641     /* Hybrid cells have 6 faces: Front, Back, Sides */
5642     /*
5643      3---------2---------2
5644      |         |         |
5645      |    D    2    C    |
5646      |         |         |
5647      3----3----0----1----1
5648      |         |         |
5649      |    A    0    B    |
5650      |         |         |
5651      0---------0---------1
5652      */
5653     for (c = cMax; c < cEnd; ++c) {
5654       const PetscInt  newp = (cMax - cStart)*8 + (c - cMax)*4;
5655       const PetscInt *cone, *ornt, *fornt;
5656       PetscInt        coneNew[6], orntNew[6], o, of, i;
5657 
5658       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5659       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5660       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
5661       o = ornt[0] < 0 ? -1 : 1;
5662       for (r = 0; r < 4; ++r) {
5663         PetscInt subfA = GetQuadSubface_Static(ornt[0], r);
5664         PetscInt edgeA = GetQuadEdge_Static(ornt[0], r);
5665         PetscInt edgeB = GetQuadEdge_Static(ornt[0], (r+3)%4);
5666         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]);
5667         coneNew[0]         = fStartNew + (cone[0] - fStart)*4 + subfA;
5668         orntNew[0]         = ornt[0];
5669         coneNew[1]         = fStartNew + (cone[1] - fStart)*4 + subfA;
5670         orntNew[1]         = ornt[0];
5671         of = fornt[edgeA] < 0 ? -1 : 1;
5672         i  = GetQuadEdgeInverse_Static(ornt[0], r) + 2;
5673         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeA] - fMax)*2 + (o*of < 0 ? 1 : 0);
5674         orntNew[i] = ornt[edgeA];
5675         i  = GetQuadEdgeInverse_Static(ornt[0], (r+1)%4) + 2;
5676         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeA;
5677         orntNew[i] = 0;
5678         i  = GetQuadEdgeInverse_Static(ornt[0], (r+2)%4) + 2;
5679         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeB;
5680         orntNew[i] = -2;
5681         of = fornt[edgeB] < 0 ? -1 : 1;
5682         i  = GetQuadEdgeInverse_Static(ornt[0], (r+3)%4) + 2;
5683         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeB] - fMax)*2 + (o*of < 0 ? 0 : 1);
5684         orntNew[i] = ornt[edgeB];
5685         ierr       = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
5686         ierr       = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
5687 #if 1
5688         if ((newp+r < cMaxNew) || (newp+r >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", newp+r, cMaxNew, cEndNew);
5689         for (p = 0; p < 2; ++p) {
5690           if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
5691         }
5692         for (p = 2; p < 6; ++p) {
5693           if ((coneNew[p] < fMaxNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", coneNew[p], fMaxNew, fEndNew);
5694         }
5695 #endif
5696       }
5697     }
5698     /* Interior split faces have 4 edges and the same cells as the parent */
5699     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5700     ierr = PetscMalloc1(4 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
5701     for (f = fStart; f < fMax; ++f) {
5702       for (r = 0; r < 4; ++r) {
5703         /* TODO: This can come from GetFaces_Internal() */
5704         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};
5705         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
5706         const PetscInt *cone, *ornt, *support;
5707         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
5708 
5709         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5710         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
5711         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
5712         orntNew[(r+3)%4] = ornt[(r+3)%4];
5713         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
5714         orntNew[(r+0)%4] = ornt[r];
5715         coneNew[(r+1)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
5716         orntNew[(r+1)%4] = 0;
5717         coneNew[(r+2)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + (r+3)%4;
5718         orntNew[(r+2)%4] = -2;
5719         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5720         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5721 #if 1
5722         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5723         for (p = 0; p < 4; ++p) {
5724           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5725         }
5726 #endif
5727         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5728         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5729         for (s = 0; s < supportSize; ++s) {
5730           PetscInt subf;
5731           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5732           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5733           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5734           for (c = 0; c < coneSize; ++c) {
5735             if (cone[c] == f) break;
5736           }
5737           subf = GetQuadSubfaceInverse_Static(ornt[c], r);
5738           if (support[s] < cMax) {
5739             supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+subf];
5740           } else {
5741             supportRef[s] = cStartNew + (cMax       - cStart)*8 + (support[s] - cMax)*4 + subf;
5742           }
5743         }
5744         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5745 #if 1
5746         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5747         for (p = 0; p < supportSize; ++p) {
5748           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
5749         }
5750 #endif
5751       }
5752     }
5753     /* Interior cell faces have 4 edges and 2 cells */
5754     for (c = cStart; c < cMax; ++c) {
5755       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};
5756       const PetscInt *cone, *ornt;
5757       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
5758 
5759       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5760       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5761       /* A-D face */
5762       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 0;
5763       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
5764       orntNew[0] = 0;
5765       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
5766       orntNew[1] = 0;
5767       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
5768       orntNew[2] = -2;
5769       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
5770       orntNew[3] = -2;
5771       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5772       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5773 #if 1
5774       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5775       for (p = 0; p < 4; ++p) {
5776         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5777       }
5778 #endif
5779       /* C-D face */
5780       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 1;
5781       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
5782       orntNew[0] = 0;
5783       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
5784       orntNew[1] = 0;
5785       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
5786       orntNew[2] = -2;
5787       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
5788       orntNew[3] = -2;
5789       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5790       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5791 #if 1
5792       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5793       for (p = 0; p < 4; ++p) {
5794         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5795       }
5796 #endif
5797       /* B-C face */
5798       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 2;
5799       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
5800       orntNew[0] = -2;
5801       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
5802       orntNew[1] = 0;
5803       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
5804       orntNew[2] = 0;
5805       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
5806       orntNew[3] = -2;
5807       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5808       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5809 #if 1
5810       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5811       for (p = 0; p < 4; ++p) {
5812         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5813       }
5814 #endif
5815       /* A-B face */
5816       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 3;
5817       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
5818       orntNew[0] = -2;
5819       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
5820       orntNew[1] = 0;
5821       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
5822       orntNew[2] = 0;
5823       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
5824       orntNew[3] = -2;
5825       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5826       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5827 #if 1
5828       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5829       for (p = 0; p < 4; ++p) {
5830         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5831       }
5832 #endif
5833       /* E-F face */
5834       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 4;
5835       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
5836       orntNew[0] = -2;
5837       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
5838       orntNew[1] = -2;
5839       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
5840       orntNew[2] = 0;
5841       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
5842       orntNew[3] = 0;
5843       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5844       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5845 #if 1
5846       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5847       for (p = 0; p < 4; ++p) {
5848         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5849       }
5850 #endif
5851       /* F-G face */
5852       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 5;
5853       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
5854       orntNew[0] = -2;
5855       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
5856       orntNew[1] = -2;
5857       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
5858       orntNew[2] = 0;
5859       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
5860       orntNew[3] = 0;
5861       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5862       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5863 #if 1
5864       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5865       for (p = 0; p < 4; ++p) {
5866         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5867       }
5868 #endif
5869       /* G-H face */
5870       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 6;
5871       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
5872       orntNew[0] = -2;
5873       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
5874       orntNew[1] = 0;
5875       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
5876       orntNew[2] = 0;
5877       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
5878       orntNew[3] = -2;
5879       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5880       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5881 #if 1
5882       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5883       for (p = 0; p < 4; ++p) {
5884         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5885       }
5886 #endif
5887       /* E-H face */
5888       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 7;
5889       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
5890       orntNew[0] = -2;
5891       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
5892       orntNew[1] = -2;
5893       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
5894       orntNew[2] = 0;
5895       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
5896       orntNew[3] = 0;
5897       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5898       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5899 #if 1
5900       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5901       for (p = 0; p < 4; ++p) {
5902         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5903       }
5904 #endif
5905       /* A-E face */
5906       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 8;
5907       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
5908       orntNew[0] = 0;
5909       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
5910       orntNew[1] = 0;
5911       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
5912       orntNew[2] = -2;
5913       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
5914       orntNew[3] = -2;
5915       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5916       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5917 #if 1
5918       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5919       for (p = 0; p < 4; ++p) {
5920         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5921       }
5922 #endif
5923       /* D-F face */
5924       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 9;
5925       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
5926       orntNew[0] = -2;
5927       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
5928       orntNew[1] = 0;
5929       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
5930       orntNew[2] = 0;
5931       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
5932       orntNew[3] = -2;
5933       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5934       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5935 #if 1
5936       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5937       for (p = 0; p < 4; ++p) {
5938         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5939       }
5940 #endif
5941       /* C-G face */
5942       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 10;
5943       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
5944       orntNew[0] = -2;
5945       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
5946       orntNew[1] = -2;
5947       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
5948       orntNew[2] = 0;
5949       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
5950       orntNew[3] = 0;
5951       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5952       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5953 #if 1
5954       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5955       for (p = 0; p < 4; ++p) {
5956         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5957       }
5958 #endif
5959       /* B-H face */
5960       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 11;
5961       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
5962       orntNew[0] = 0;
5963       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
5964       orntNew[1] = -2;
5965       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
5966       orntNew[2] = -2;
5967       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
5968       orntNew[3] = 0;
5969       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5970       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5971 #if 1
5972       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5973       for (p = 0; p < 4; ++p) {
5974         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5975       }
5976 #endif
5977       for (r = 0; r < 12; ++r) {
5978         newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
5979         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
5980         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
5981         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5982 #if 1
5983         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5984         for (p = 0; p < 2; ++p) {
5985           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
5986         }
5987 #endif
5988       }
5989     }
5990     /* Hybrid split faces have 4 edges and same cells */
5991     for (f = fMax; f < fEnd; ++f) {
5992       const PetscInt *cone, *ornt, *support;
5993       PetscInt        coneNew[4], orntNew[4];
5994       PetscInt        supportNew[2], size, s, c;
5995 
5996       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5997       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
5998       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5999       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6000       for (r = 0; r < 2; ++r) {
6001         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
6002 
6003         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
6004         orntNew[0]   = ornt[0];
6005         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
6006         orntNew[1]   = ornt[1];
6007         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (cone[2+r] - eMax);
6008         orntNew[2+r] = 0;
6009         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd      - eMax) + (f - fMax);
6010         orntNew[3-r] = 0;
6011         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6012         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6013 #if 1
6014         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
6015         for (p = 0; p < 2; ++p) {
6016           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
6017         }
6018         for (p = 2; p < 4; ++p) {
6019           if ((coneNew[p] < eMaxNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", coneNew[p], eMaxNew, eEndNew);
6020         }
6021 #endif
6022         for (s = 0; s < size; ++s) {
6023           const PetscInt *coneCell, *orntCell, *fornt;
6024           PetscInt        o, of;
6025 
6026           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
6027           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
6028           o = orntCell[0] < 0 ? -1 : 1;
6029           for (c = 2; c < 6; ++c) if (coneCell[c] == f) break;
6030           if (c >= 6) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
6031           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
6032           of = fornt[c-2] < 0 ? -1 : 1;
6033           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetQuadEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%4;
6034         }
6035         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6036 #if 1
6037         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
6038         for (p = 0; p < size; ++p) {
6039           if ((supportNew[p] < cMaxNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", supportNew[p], cMaxNew, cEndNew);
6040         }
6041 #endif
6042       }
6043     }
6044     /* Hybrid cell faces have 4 edges and 2 cells */
6045     for (c = cMax; c < cEnd; ++c) {
6046       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4;
6047       const PetscInt *cone, *ornt;
6048       PetscInt        coneNew[4], orntNew[4];
6049       PetscInt        supportNew[2];
6050 
6051       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6052       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6053       for (r = 0; r < 4; ++r) {
6054 #if 0
6055         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], r);
6056         orntNew[0] = 0;
6057         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], r);
6058         orntNew[1] = 0;
6059         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+GetQuadEdge_Static(ornt[0], r)] - fMax);
6060         orntNew[2] = 0;
6061         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd                                   - fMax) + (c - cMax);
6062         orntNew[3] = 0;
6063 #else
6064         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + r;
6065         orntNew[0] = 0;
6066         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + r;
6067         orntNew[1] = 0;
6068         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+r] - fMax);
6069         orntNew[2] = 0;
6070         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd      - fMax) + (c - cMax);
6071         orntNew[3] = 0;
6072 #endif
6073         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
6074         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
6075 #if 1
6076         if ((newp+r < fMaxNew) || (newp+r >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp+r, fMaxNew, fEndNew);
6077         for (p = 0; p < 2; ++p) {
6078           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
6079         }
6080         for (p = 2; p < 4; ++p) {
6081           if ((coneNew[p] < eMaxNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", coneNew[p], eMaxNew, eEndNew);
6082         }
6083 #endif
6084         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], r);
6085         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], (r+1)%4);
6086         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
6087 #if 1
6088         if ((newp+r < fMaxNew) || (newp+r >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp+r, fMaxNew, fEndNew);
6089         for (p = 0; p < 2; ++p) {
6090           if ((supportNew[p] < cMaxNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", supportNew[p], cMaxNew, cEndNew);
6091         }
6092 #endif
6093       }
6094     }
6095     /* Interior split edges have 2 vertices and the same faces as the parent */
6096     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6097     for (e = eStart; e < eMax; ++e) {
6098       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
6099 
6100       for (r = 0; r < 2; ++r) {
6101         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
6102         const PetscInt *cone, *ornt, *support;
6103         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6104 
6105         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6106         coneNew[0]       = vStartNew + (cone[0] - vStart);
6107         coneNew[1]       = vStartNew + (cone[1] - vStart);
6108         coneNew[(r+1)%2] = newv;
6109         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6110 #if 1
6111         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6112         for (p = 0; p < 2; ++p) {
6113           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6114         }
6115 #endif
6116         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
6117         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
6118         for (s = 0; s < supportSize; ++s) {
6119           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6120           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6121           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
6122           for (c = 0; c < coneSize; ++c) {
6123             if (cone[c] == e) break;
6124           }
6125           if (support[s] < fMax) {
6126             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%4;
6127           } else {
6128             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
6129           }
6130         }
6131         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6132 #if 1
6133         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6134         for (p = 0; p < supportSize; ++p) {
6135           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6136         }
6137 #endif
6138       }
6139     }
6140     /* Interior face edges have 2 vertices and 2+cells faces */
6141     for (f = fStart; f < fMax; ++f) {
6142       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};
6143       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
6144       const PetscInt *cone, *coneCell, *orntCell, *support;
6145       PetscInt        coneNew[2], coneSize, c, supportSize, s;
6146 
6147       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6148       for (r = 0; r < 4; ++r) {
6149         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
6150 
6151         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
6152         coneNew[1] = newv;
6153         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6154 #if 1
6155         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6156         for (p = 0; p < 2; ++p) {
6157           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6158         }
6159 #endif
6160         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6161         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6162         supportRef[0] = fStartNew + (f - fStart)*4 + r;
6163         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
6164         for (s = 0; s < supportSize; ++s) {
6165           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6166           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
6167           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
6168           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
6169           if (support[s] < cMax) {
6170             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
6171           } else {
6172             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + r;
6173           }
6174         }
6175         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6176 #if 1
6177         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6178         for (p = 0; p < 2+supportSize; ++p) {
6179           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6180         }
6181 #endif
6182       }
6183     }
6184     /* Interior cell edges have 2 vertices and 4 faces */
6185     for (c = cStart; c < cMax; ++c) {
6186       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};
6187       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
6188       const PetscInt *cone;
6189       PetscInt        coneNew[2], supportNew[4];
6190 
6191       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6192       for (r = 0; r < 6; ++r) {
6193         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
6194 
6195         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
6196         coneNew[1] = newv;
6197         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6198 #if 1
6199         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6200         for (p = 0; p < 2; ++p) {
6201           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6202         }
6203 #endif
6204         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
6205         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6206 #if 1
6207         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6208         for (p = 0; p < 4; ++p) {
6209           if ((supportNew[p] < fStartNew) || (supportNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportNew[p], fStartNew, fMaxNew);
6210         }
6211 #endif
6212       }
6213     }
6214     /* Hybrid edges have two vertices and the same faces */
6215     for (e = eMax; e < eEnd; ++e) {
6216       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
6217       const PetscInt *cone, *support, *fcone;
6218       PetscInt        coneNew[2], size, fsize, s;
6219 
6220       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6221       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
6222       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
6223       coneNew[0] = vStartNew + (cone[0] - vStart);
6224       coneNew[1] = vStartNew + (cone[1] - vStart);
6225       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6226 #if 1
6227       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6228       for (p = 0; p < 2; ++p) {
6229         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6230       }
6231 #endif
6232       for (s = 0; s < size; ++s) {
6233         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
6234         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
6235         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
6236         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
6237         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + c-2;
6238       }
6239       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6240 #if 1
6241       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6242       for (p = 0; p < size; ++p) {
6243         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", supportRef[p], fMaxNew, fEndNew);
6244       }
6245 #endif
6246     }
6247     /* Hybrid face edges have 2 vertices and 2+cells faces */
6248     for (f = fMax; f < fEnd; ++f) {
6249       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
6250       const PetscInt *cone, *support, *ccone, *cornt;
6251       PetscInt        coneNew[2], size, csize, s;
6252 
6253       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6254       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6255       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6256       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
6257       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
6258       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6259 #if 1
6260       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6261       for (p = 0; p < 2; ++p) {
6262         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6263       }
6264 #endif
6265       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 0;
6266       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 1;
6267       for (s = 0; s < size; ++s) {
6268         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
6269         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
6270         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
6271         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
6272         if ((c < 2) || (c >= csize)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Hybrid face %d is not in cone of hybrid cell %d", f, support[s]);
6273         supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + c-2;
6274       }
6275       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6276 #if 1
6277       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6278       for (p = 0; p < 2+size; ++p) {
6279         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", supportRef[p], fMaxNew, fEndNew);
6280       }
6281 #endif
6282     }
6283     /* Hybrid cell edges have 2 vertices and 4 faces */
6284     for (c = cMax; c < cEnd; ++c) {
6285       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
6286       const PetscInt *cone, *support;
6287       PetscInt        coneNew[2], size;
6288 
6289       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6290       ierr = DMPlexGetSupportSize(dm, c, &size);CHKERRQ(ierr);
6291       ierr = DMPlexGetSupport(dm, c, &support);CHKERRQ(ierr);
6292       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
6293       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
6294       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6295 #if 1
6296       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6297       for (p = 0; p < 2; ++p) {
6298         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6299       }
6300 #endif
6301       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 0;
6302       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 1;
6303       supportRef[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 2;
6304       supportRef[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 3;
6305       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6306 #if 1
6307       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6308       for (p = 0; p < 4; ++p) {
6309         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", supportRef[p], fMaxNew, fEndNew);
6310       }
6311 #endif
6312     }
6313     /* Interior vertices have identical supports */
6314     for (v = vStart; v < vEnd; ++v) {
6315       const PetscInt  newp = vStartNew + (v - vStart);
6316       const PetscInt *support, *cone;
6317       PetscInt        size, s;
6318 
6319       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6320       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6321       for (s = 0; s < size; ++s) {
6322         PetscInt r = 0;
6323 
6324         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6325         if (cone[1] == v) r = 1;
6326         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
6327         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (support[s] - eMax);
6328       }
6329       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6330 #if 1
6331       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6332       for (p = 0; p < size; ++p) {
6333         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
6334       }
6335 #endif
6336     }
6337     /* Interior edge vertices have 2 + faces supports */
6338     for (e = eStart; e < eMax; ++e) {
6339       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
6340       const PetscInt *cone, *support;
6341       PetscInt        size, s;
6342 
6343       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
6344       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
6345       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
6346       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
6347       for (s = 0; s < size; ++s) {
6348         PetscInt r;
6349 
6350         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6351         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
6352         if (support[s] < fMax) {
6353           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*4 + r;
6354         } else {
6355           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (support[s] - fMax);
6356         }
6357       }
6358       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6359 #if 1
6360       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6361       for (p = 0; p < 2+size; ++p) {
6362         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
6363       }
6364 #endif
6365     }
6366     /* Interior face vertices have 4 + cells supports */
6367     for (f = fStart; f < fMax; ++f) {
6368       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
6369       const PetscInt *cone, *support;
6370       PetscInt        size, s;
6371 
6372       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6373       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6374       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eMax - eStart)*2 +  (f - fStart)*4 + r;
6375       for (s = 0; s < size; ++s) {
6376         PetscInt r;
6377 
6378         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6379         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
6380         if (support[s] < cMax) {
6381           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (support[s] - cStart)*6 + r;
6382         } else {
6383           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax       - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (support[s] - cMax);
6384         }
6385       }
6386       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6387 #if 1
6388       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6389       for (p = 0; p < 4+size; ++p) {
6390         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
6391       }
6392 #endif
6393     }
6394     /* Cell vertices have 6 supports */
6395     for (c = cStart; c < cMax; ++c) {
6396       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
6397       PetscInt       supportNew[6];
6398 
6399       for (r = 0; r < 6; ++r) {
6400         supportNew[r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
6401       }
6402       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6403     }
6404     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6405     break;
6406   default:
6407     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6408   }
6409   PetscFunctionReturn(0);
6410 }
6411 
6412 static PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6413 {
6414   PetscSection          coordSection, coordSectionNew;
6415   Vec                   coordinates, coordinatesNew;
6416   PetscScalar          *coords, *coordsNew;
6417   const PetscInt        numVertices = depthSize ? depthSize[0] : 0;
6418   PetscInt              dim, spaceDim, depth, bs, coordSizeNew, cStart, cEnd, cMax;
6419   PetscInt              c, vStart, vStartNew, vEnd, v, eStart, eEnd, eMax, e, fStart, fEnd, fMax, f;
6420   PetscInt              cStartNew, cEndNew, vEndNew, *parentId = NULL;
6421   VecType               vtype;
6422   PetscBool             isperiodic, localize = PETSC_FALSE, needcoords = PETSC_FALSE;
6423   const PetscReal      *maxCell, *L;
6424   const DMBoundaryType *bd;
6425   PetscErrorCode        ierr;
6426 
6427   PetscFunctionBegin;
6428   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6429   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6430   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6431   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6432   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6433   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6434   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, NULL);CHKERRQ(ierr);
6435   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, NULL, NULL, &vStartNew);CHKERRQ(ierr);
6436   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, NULL, NULL, &vEndNew);CHKERRQ(ierr);
6437   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6438   ierr = PetscSectionGetFieldComponents(coordSection, 0, &spaceDim);CHKERRQ(ierr);
6439   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
6440   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
6441   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, spaceDim);CHKERRQ(ierr);
6442   ierr = DMGetPeriodicity(dm, &isperiodic, &maxCell, &L, &bd);CHKERRQ(ierr);
6443   ierr = DMSetPeriodicity(rdm, isperiodic,  maxCell,  L,  bd);CHKERRQ(ierr);
6444   /* Determine if we need to localize coordinates when generating them */
6445   if (isperiodic && !maxCell) {
6446     ierr = DMGetCoordinatesLocalized(dm, &localize);CHKERRQ(ierr);
6447     if (!localize) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Cannot refine if coordinates have not been localized");
6448   }
6449   if (localize) {
6450     PetscInt p, r, newp, *pi;
6451 
6452     /* New coordinates will be already localized on the cell */
6453     ierr = PetscSectionSetChart(coordSectionNew, 0, vStartNew+numVertices);CHKERRQ(ierr);
6454 
6455     /* We need the parentId to properly localize coordinates */
6456     ierr = PetscMalloc1(cEndNew-cStartNew,&pi);CHKERRQ(ierr);
6457     switch (refiner) {
6458     case REFINER_NOOP:
6459       break;
6460     case REFINER_SIMPLEX_1D:
6461       for (p = cStart; p < cEnd; ++p) {
6462         for (r = 0; r < 2; ++r) {
6463           newp     = (p - cStart)*2 + r;
6464           pi[newp] = p;
6465         }
6466       }
6467       break;
6468     case REFINER_SIMPLEX_2D:
6469       for (p = cStart; p < cEnd; ++p) {
6470         for (r = 0; r < 4; ++r) {
6471           newp     = (p - cStart)*4 + r;
6472           pi[newp] = p;
6473         }
6474       }
6475       break;
6476     case REFINER_HEX_2D:
6477       for (p = cStart; p < cEnd; ++p) {
6478         for (r = 0; r < 4; ++r) {
6479           newp     = (p - cStart)*4 + r;
6480           pi[newp] = p;
6481         }
6482       }
6483       break;
6484     case REFINER_SIMPLEX_TO_HEX_2D:
6485       for (p = cStart; p < cEnd; ++p) {
6486         for (r = 0; r < 3; ++r) {
6487           newp     = (p - cStart)*3 + r;
6488           pi[newp] = p;
6489         }
6490       }
6491       break;
6492     case REFINER_HYBRID_SIMPLEX_2D:
6493       for (p = cStart; p < cMax; ++p) {
6494         for (r = 0; r < 4; ++r) {
6495           newp     = (p - cStart)*4 + r;
6496           pi[newp] = p;
6497         }
6498       }
6499       for (p = cMax; p < cEnd; ++p) {
6500         for (r = 0; r < 2; ++r) {
6501           newp     = (cMax - cStart)*4 + (p - cMax)*2 + r;
6502           pi[newp] = p;
6503         }
6504       }
6505       break;
6506     case REFINER_HYBRID_HEX_2D:
6507       for (p = cStart; p < cMax; ++p) {
6508         for (r = 0; r < 4; ++r) {
6509           newp     = (p - cStart)*4 + r;
6510           pi[newp] = p;
6511         }
6512       }
6513       for (p = cMax; p < cEnd; ++p) {
6514         for (r = 0; r < 2; ++r) {
6515           newp     = (cMax - cStart)*4 + (p - cMax)*2 + r;
6516           pi[newp] = p;
6517         }
6518       }
6519       break;
6520     case REFINER_SIMPLEX_3D:
6521       for (p = cStart; p < cEnd; ++p) {
6522         for (r = 0; r < 8; ++r) {
6523           newp     = (p - cStart)*8 + r;
6524           pi[newp] = p;
6525         }
6526       }
6527       break;
6528     case REFINER_HYBRID_SIMPLEX_3D:
6529       for (p = cStart; p < cMax; ++p) {
6530         for (r = 0; r < 8; ++r) {
6531           newp     = (p - cStart)*8 + r;
6532           pi[newp] = p;
6533         }
6534       }
6535       for (p = cMax; p < cEnd; ++p) {
6536         for (r = 0; r < 4; ++r) {
6537           newp     = (cMax - cStart)*8 + (p - cMax)*4 + r;
6538           pi[newp] = p;
6539         }
6540       }
6541       break;
6542     case REFINER_SIMPLEX_TO_HEX_3D:
6543       for (p = cStart; p < cEnd; ++p) {
6544         for (r = 0; r < 4; ++r) {
6545           newp     = (p - cStart)*4 + r;
6546           pi[newp] = p;
6547         }
6548       }
6549       break;
6550     case REFINER_HEX_3D:
6551       for (p = cStart; p < cEnd; ++p) {
6552         for (r = 0; r < 8; ++r) {
6553           newp = (p - cStart)*8 + r;
6554           pi[newp] = p;
6555         }
6556       }
6557       break;
6558     case REFINER_HYBRID_HEX_3D:
6559       for (p = cStart; p < cMax; ++p) {
6560         for (r = 0; r < 8; ++r) {
6561           newp = (p - cStart)*8 + r;
6562           pi[newp] = p;
6563         }
6564       }
6565       for (p = cMax; p < cEnd; ++p) {
6566         for (r = 0; r < 4; ++r) {
6567           newp = (cMax - cStart)*8 + (p - cMax)*4 + r;
6568           pi[newp] = p;
6569         }
6570       }
6571       break;
6572     default:
6573       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6574     }
6575     parentId = pi;
6576   } else {
6577     ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+numVertices);CHKERRQ(ierr);
6578   }
6579   if (cMax < 0) cMax = cEnd;
6580   if (fMax < 0) fMax = fEnd;
6581   if (eMax < 0) eMax = eEnd;
6582 
6583   /* All vertices have the spaceDim coordinates */
6584   if (localize) {
6585     PetscInt c;
6586 
6587     for (c = cStartNew; c < cEndNew; ++c) {
6588       PetscInt *cone = NULL;
6589       PetscInt  closureSize, coneSize = 0, p, pdof;
6590 
6591       ierr = PetscSectionGetDof(coordSection, parentId[c], &pdof); CHKERRQ(ierr);
6592       if (pdof) { /* localize on all cells that are refinement of a localized parent cell */
6593         ierr = DMPlexGetTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6594         for (p = 0; p < closureSize*2; p += 2) {
6595           const PetscInt point = cone[p];
6596           if ((point >= vStartNew) && (point < vEndNew)) coneSize++;
6597         }
6598         ierr = DMPlexRestoreTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6599         ierr = PetscSectionSetDof(coordSectionNew, c, coneSize*spaceDim);CHKERRQ(ierr);
6600         ierr = PetscSectionSetFieldDof(coordSectionNew, c, 0, coneSize*spaceDim);CHKERRQ(ierr);
6601       }
6602     }
6603   }
6604   for (v = vStartNew; v < vStartNew+numVertices; ++v) {
6605     ierr = PetscSectionSetDof(coordSectionNew, v, spaceDim);CHKERRQ(ierr);
6606     ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, spaceDim);CHKERRQ(ierr);
6607   }
6608   ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
6609   ierr = DMSetCoordinateSection(rdm, PETSC_DETERMINE, coordSectionNew);CHKERRQ(ierr);
6610   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6611   ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
6612   ierr = VecCreate(PETSC_COMM_SELF, &coordinatesNew);CHKERRQ(ierr);
6613   ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
6614   ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
6615   ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr);
6616   ierr = VecSetBlockSize(coordinatesNew, bs);CHKERRQ(ierr);
6617   ierr = VecGetType(coordinates, &vtype);CHKERRQ(ierr);
6618   ierr = VecSetType(coordinatesNew, vtype);CHKERRQ(ierr);
6619   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
6620   ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6621 
6622   switch (refiner) {
6623   case REFINER_NOOP: break;
6624   case REFINER_SIMPLEX_TO_HEX_3D:
6625   case REFINER_HEX_3D:
6626   case REFINER_HYBRID_HEX_3D:
6627     /* Face vertices have the average of corner coordinates */
6628     for (f = fStart; f < fMax; ++f) {
6629       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
6630       PetscInt      *cone = NULL;
6631       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
6632 
6633       ierr = DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6634       for (p = 0; p < closureSize*2; p += 2) {
6635         const PetscInt point = cone[p];
6636         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
6637       }
6638       if (localize) {
6639         const PetscInt *support = NULL;
6640         PetscInt       *rStar = NULL;
6641         PetscInt        supportSize, rStarSize, coff, s, ccoff[8];
6642         PetscBool       cellfound = PETSC_FALSE;
6643 
6644         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
6645         ierr = DMPlexGetSupportSize(dm,f,&supportSize);CHKERRQ(ierr);
6646         ierr = DMPlexGetSupport(dm,f,&support);CHKERRQ(ierr);
6647         /* Compute average of coordinates for each cell sharing the face */
6648         for (s = 0; s < supportSize; ++s) {
6649           PetscScalar     coordsNewAux[3] = { 0.0, 0.0, 0.0 };
6650           PetscInt       *cellCone = NULL;
6651           PetscInt        cellClosureSize, cellConeSize = 0, cdof;
6652           const PetscInt  cell = support[s];
6653           PetscBool       copyoff = PETSC_FALSE;
6654 
6655           ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
6656           for (p = 0; p < cellClosureSize*2; p += 2) {
6657             const PetscInt point = cellCone[p];
6658             if ((point >= vStart) && (point < vEnd)) cellCone[cellConeSize++] = point;
6659           }
6660           ierr = PetscSectionGetDof(coordSection, cell, &cdof);CHKERRQ(ierr);
6661           if (!cdof) { /* the parent cell does not have localized coordinates */
6662             cellfound = PETSC_TRUE;
6663             for (v = 0; v < coneSize; ++v) {
6664               ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
6665               for (d = 0; d < spaceDim; ++d) coordsNewAux[d] += coords[off[v]+d];
6666             }
6667             for (d = 0; d < spaceDim; ++d) coordsNewAux[d] /= coneSize;
6668           } else {
6669             ierr = PetscSectionGetOffset(coordSection, cell, &coff);CHKERRQ(ierr);
6670             for (p = 0; p < coneSize; ++p) {
6671               const PetscInt tv = cone[p];
6672               PetscInt       cv, voff;
6673               PetscBool      locv = PETSC_TRUE;
6674 
6675               for (cv = 0; cv < cellConeSize; ++cv) {
6676                 if (cellCone[cv] == tv) {
6677                   ccoff[p] = spaceDim*cv + coff;
6678                   break;
6679                 }
6680               }
6681               if (cv == cellConeSize) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map vertex %D\n",tv);
6682 
6683               ierr = PetscSectionGetOffset(coordSection, cone[p], &voff);CHKERRQ(ierr);
6684               for (d = 0; d < spaceDim; ++d) {
6685                 coordsNewAux[d] += coords[ccoff[p]+d];
6686                 if (!cellfound && coords[voff+d] != coords[ccoff[p]+d]) locv = PETSC_FALSE;
6687               }
6688               if (locv && !cellfound) {
6689                 cellfound = PETSC_TRUE;
6690                 copyoff   = PETSC_TRUE;
6691               }
6692             }
6693             for (d = 0; d < spaceDim; ++d) coordsNewAux[d] /= coneSize;
6694 
6695             /* Found a valid face for the "vertex" part of the Section (physical space)
6696                i.e., a face that has at least one corner in the physical space */
6697             if (copyoff) for (p = 0; p < coneSize; ++p) off[p] = ccoff[p];
6698           }
6699 
6700           /* Localize new coordinates on each refined cell */
6701           for (v = 0; v < rStarSize*2; v += 2) {
6702             if ((rStar[v] >= cStartNew) && (rStar[v] < cEndNew) && parentId[rStar[v]-cStartNew] == cell) {
6703               PetscInt       *rcone = NULL, rclosureSize, lid, rcdof, rcoff;
6704               const PetscInt  rcell = rStar[v];
6705 
6706               ierr = PetscSectionGetDof(coordSectionNew, rcell, &rcdof);CHKERRQ(ierr);
6707               if (!rcdof) continue;
6708               ierr = PetscSectionGetOffset(coordSectionNew, rcell, &rcoff);CHKERRQ(ierr);
6709               ierr = DMPlexGetTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
6710               for (p = 0, lid = 0; p < rclosureSize*2; p += 2) {
6711                 if (rcone[p] == newv) {
6712                   for (d = 0; d < spaceDim; d++) coordsNew[rcoff + lid*spaceDim + d] = coordsNewAux[d];
6713                   break;
6714                 }
6715                 if (rcone[p] >= vStartNew && rcone[p] < vEndNew) lid++;
6716               }
6717               ierr = DMPlexRestoreTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
6718               if (p == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
6719             }
6720           }
6721           ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
6722         }
6723         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
6724         if (!cellfound) {
6725           /* Could not find a valid face for the vertex part, we will get this vertex later (final reduction) */
6726           needcoords = PETSC_TRUE;
6727           coneSize   = 0;
6728         }
6729       } else {
6730         for (v = 0; v < coneSize; ++v) {
6731           ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
6732         }
6733       }
6734       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6735       if (coneSize) {
6736         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
6737         for (v = 0; v < coneSize; ++v) {ierr = DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);CHKERRQ(ierr);}
6738         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
6739       } else {
6740         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = PETSC_MIN_REAL;
6741       }
6742       ierr = DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6743     }
6744   case REFINER_SIMPLEX_TO_HEX_2D:
6745   case REFINER_HEX_2D:
6746   case REFINER_HYBRID_HEX_2D:
6747   case REFINER_SIMPLEX_1D:
6748     /* Cell vertices have the average of corner coordinates */
6749     for (c = cStart; c < cMax; ++c) {
6750       const PetscInt newv = vStartNew + (vEnd - vStart) + (dim > 1 ? (eMax - eStart) : 0) + (c - cStart) + (dim > 2 ? (fMax - fStart) : 0);
6751       PetscInt      *cone = NULL;
6752       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d, cdof = 0;
6753 
6754       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6755       for (p = 0; p < closureSize*2; p += 2) {
6756         const PetscInt point = cone[p];
6757         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
6758       }
6759       if (localize) {
6760         ierr = PetscSectionGetDof(coordSection, c, &cdof);CHKERRQ(ierr);
6761       }
6762       if (cdof) {
6763         PetscInt coff;
6764 
6765         ierr = PetscSectionGetOffset(coordSection, c, &coff);CHKERRQ(ierr);
6766         for (v = 0; v < coneSize; ++v) off[v] = spaceDim*v + coff;
6767       } else {
6768         for (v = 0; v < coneSize; ++v) {
6769           ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
6770         }
6771       }
6772       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6773       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
6774       for (v = 0; v < coneSize; ++v) {ierr = DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);CHKERRQ(ierr);}
6775       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
6776       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6777 
6778       /* Localize new coordinates on each refined cell */
6779       if (cdof) {
6780         PetscInt *rStar = NULL, rStarSize;
6781 
6782         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
6783         for (v = 0; v < rStarSize*2; v += 2) {
6784           if ((rStar[v] >= cStartNew) && (rStar[v] < cEndNew)) {
6785             PetscInt *cone = NULL, closureSize, lid, coff, rc, rcdof;
6786 
6787             rc   = rStar[v];
6788             ierr = PetscSectionGetDof(coordSectionNew, rc, &rcdof);CHKERRQ(ierr);
6789             if (!rcdof) continue;
6790             ierr = PetscSectionGetOffset(coordSectionNew, rc, &coff);CHKERRQ(ierr);
6791             ierr = DMPlexGetTransitiveClosure(rdm, rc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6792             for (p = 0, lid = 0; p < closureSize*2; p += 2) {
6793               if (cone[p] == newv) {
6794                 for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = coordsNew[offnew + d];
6795                 break;
6796               }
6797               if (cone[p] >= vStartNew && cone[p] < vEndNew) lid++;
6798             }
6799             if (p == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
6800             ierr = DMPlexRestoreTransitiveClosure(rdm, rc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6801           }
6802         }
6803         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
6804       }
6805     }
6806   case REFINER_SIMPLEX_2D:
6807   case REFINER_HYBRID_SIMPLEX_2D:
6808   case REFINER_SIMPLEX_3D:
6809   case REFINER_HYBRID_SIMPLEX_3D:
6810     /* Edge vertices have the average of endpoint coordinates */
6811     for (e = eStart; e < eMax; ++e) {
6812       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
6813       const PetscInt *cone;
6814       PetscInt        coneSize, offA, offB, offnew, d;
6815 
6816       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
6817       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
6818       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6819       if (localize) {
6820         PetscInt   coff, toffA = -1, toffB = -1, voffA, voffB;
6821         PetscInt  *eStar = NULL, eStarSize;
6822         PetscInt  *rStar = NULL, rStarSize;
6823         PetscBool  cellfound = PETSC_FALSE;
6824 
6825         offA = offB = -1;
6826         ierr = PetscSectionGetOffset(coordSection, cone[0], &voffA);CHKERRQ(ierr);
6827         ierr = PetscSectionGetOffset(coordSection, cone[1], &voffB);CHKERRQ(ierr);
6828         ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &eStarSize, &eStar);CHKERRQ(ierr);
6829         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
6830         for (v = 0; v < eStarSize*2; v += 2) {
6831           if ((eStar[v] >= cStart) && (eStar[v] < cEnd)) {
6832             PetscScalar     coordsNewAux[3];
6833             PetscInt       *cellCone = NULL;
6834             PetscInt        cellClosureSize, s, cv, cdof;
6835             PetscBool       locvA = PETSC_TRUE, locvB = PETSC_TRUE;
6836             const PetscInt  cell = eStar[v];
6837 
6838             ierr = PetscSectionGetDof(coordSection, cell, &cdof);CHKERRQ(ierr);
6839             if (!cdof) {
6840               /* Found a valid edge for the "vertex" part of the Section */
6841               offA = voffA;
6842               offB = voffB;
6843               cellfound = PETSC_TRUE;
6844             } else {
6845               ierr = PetscSectionGetOffset(coordSection, cell, &coff);CHKERRQ(ierr);
6846               ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
6847               for (s = 0, cv = 0; s < cellClosureSize*2; s += 2) {
6848                 const PetscInt point = cellCone[s];
6849                 if ((point >= vStart) && (point < vEnd)) {
6850                   if (point == cone[0]) toffA = spaceDim*cv + coff;
6851                   else if (point == cone[1]) toffB = spaceDim*cv + coff;
6852                   cv++;
6853                 }
6854               }
6855               ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
6856               for (d = 0; d < spaceDim; ++d) {
6857                 coordsNewAux[d] = 0.5*(coords[toffA+d] + coords[toffB+d]);
6858                 if (coords[toffA+d] != coords[voffA+d]) locvA = PETSC_FALSE;
6859                 if (coords[toffB+d] != coords[voffB+d]) locvB = PETSC_FALSE;
6860               }
6861               /* Found a valid edge for the "vertex" part of the Section */
6862               if (!cellfound && (locvA || locvB)) {
6863                 cellfound = PETSC_TRUE;
6864                 offA = toffA;
6865                 offB = toffB;
6866               }
6867             }
6868 
6869             /* Localize new coordinates on each refined cell */
6870             for (s = 0; s < rStarSize*2; s += 2) {
6871               if ((rStar[s] >= cStartNew) && (rStar[s] < cEndNew) && parentId[rStar[s]-cStartNew] == cell) {
6872                 PetscInt       *rcone = NULL, rclosureSize, lid, p, rcdof;
6873                 const PetscInt  rcell = rStar[s];
6874 
6875                 ierr = PetscSectionGetDof(coordSectionNew, rcell, &rcdof);CHKERRQ(ierr);
6876                 if (!rcdof) continue;
6877                 ierr = PetscSectionGetOffset(coordSectionNew, rcell, &coff);CHKERRQ(ierr);
6878                 ierr = DMPlexGetTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
6879                 for (p = 0, lid = 0; p < rclosureSize*2; p += 2) {
6880                   if (rcone[p] == newv) {
6881                     for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = coordsNewAux[d];
6882                     break;
6883                   }
6884                   if (rcone[p] >= vStartNew && rcone[p] < vEndNew) lid++;
6885                 }
6886                 ierr = DMPlexRestoreTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
6887                 if (p == rclosureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
6888               }
6889             }
6890           }
6891         }
6892         ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &eStarSize, &eStar);CHKERRQ(ierr);
6893         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
6894         if (!cellfound) {
6895           /* Could not find a valid edge for the vertex part, we will get this vertex later (final reduction) */
6896           needcoords = PETSC_TRUE;
6897         }
6898       } else {
6899         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6900         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6901       }
6902       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6903       if (offA != -1 && offB != -1) {
6904         ierr = DMLocalizeCoordinate_Internal(dm, spaceDim, &coords[offA], &coords[offB], &coordsNew[offnew]);CHKERRQ(ierr);
6905         for (d = 0; d < spaceDim; ++d) {
6906           coordsNew[offnew+d] = 0.5*(coords[offA+d] + coordsNew[offnew+d]);
6907         }
6908       } else {
6909         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = PETSC_MIN_REAL;
6910       }
6911     }
6912     /* Old vertices have the same coordinates */
6913     for (v = vStart; v < vEnd; ++v) {
6914       const PetscInt newv = vStartNew + (v - vStart);
6915       PetscInt       off, offnew, d;
6916 
6917       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6918       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6919       for (d = 0; d < spaceDim; ++d) {
6920         coordsNew[offnew+d] = coords[off+d];
6921       }
6922 
6923       /* Localize new coordinates on each refined cell */
6924       if (localize) {
6925         PetscInt  p;
6926         PetscInt *rStar = NULL, rStarSize;
6927 
6928         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
6929         for (p = 0; p < rStarSize*2; p += 2) {
6930           if ((rStar[p] >= cStartNew) && (rStar[p] < cEndNew)) {
6931             PetscScalar  ocoords[3];
6932             PetscInt    *cone = NULL, closureSize, lid, coff, s, oc, cdof;
6933 
6934             c    = rStar[p];
6935             oc   = parentId[c-cStartNew];
6936             ierr = PetscSectionGetDof(coordSectionNew, c, &cdof);CHKERRQ(ierr);
6937             if (!cdof) continue;
6938             ierr = PetscSectionGetDof(coordSection, oc, &cdof);CHKERRQ(ierr);
6939             if (!cdof) continue;
6940             ierr = PetscSectionGetOffset(coordSection, oc, &coff);CHKERRQ(ierr);
6941             ierr = DMPlexGetTransitiveClosure(dm, oc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6942             for (s = 0, lid = 0; s < closureSize*2; s += 2) {
6943               if (cone[s] == v) {
6944                 for (d = 0; d < spaceDim; d++) ocoords[d] = coords[coff + lid*spaceDim + d];
6945                 break;
6946               }
6947               if (cone[s] >= vStart && cone[s] < vEnd) lid++;
6948             }
6949             if (s == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map old vertex %D\n",v);
6950             ierr = DMPlexRestoreTransitiveClosure(dm, oc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6951 
6952             ierr = PetscSectionGetOffset(coordSectionNew, c, &coff);CHKERRQ(ierr);
6953             ierr = DMPlexGetTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6954             for (s = 0, lid = 0; s < closureSize*2; s += 2) {
6955               if (cone[s] == newv) {
6956                 for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = ocoords[d];
6957                 break;
6958               }
6959               if (cone[s] >= vStartNew && cone[s] < vEndNew) lid++;
6960             }
6961             if (s == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
6962             ierr = DMPlexRestoreTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6963           }
6964         }
6965         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
6966       }
6967     }
6968     break;
6969   default:
6970     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6971   }
6972   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
6973   ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6974   ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
6975 
6976   /* Final reduction (if needed) if we are localizing */
6977   if (localize) {
6978     PetscBool gred;
6979 
6980     ierr = MPIU_Allreduce(&needcoords, &gred, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)rdm));CHKERRQ(ierr);
6981     if (gred) {
6982       DM                 cdm;
6983       Vec                aux;
6984       PetscSF            sf;
6985       const PetscScalar *lArray;
6986       PetscScalar       *gArray;
6987 
6988       ierr = DMGetCoordinateDM(rdm, &cdm);CHKERRQ(ierr);
6989       ierr = DMCreateGlobalVector(cdm, &aux);CHKERRQ(ierr);
6990       ierr = DMGetDefaultSF(cdm, &sf);CHKERRQ(ierr);
6991       ierr = VecGetArrayRead(coordinatesNew, &lArray);CHKERRQ(ierr);
6992       ierr = VecSet(aux, PETSC_MIN_REAL);CHKERRQ(ierr);
6993       ierr = VecGetArray(aux, &gArray);CHKERRQ(ierr);
6994       ierr = PetscSFReduceBegin(sf, MPIU_SCALAR, lArray, gArray, MPIU_MAX);CHKERRQ(ierr);
6995       ierr = PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_MAX);CHKERRQ(ierr);
6996       ierr = VecRestoreArrayRead(coordinatesNew, &lArray);CHKERRQ(ierr);
6997       ierr = VecRestoreArray(aux, &gArray);CHKERRQ(ierr);
6998       ierr = DMGlobalToLocalBegin(cdm, aux, INSERT_VALUES, coordinatesNew);CHKERRQ(ierr);
6999       ierr = DMGlobalToLocalEnd(cdm, aux, INSERT_VALUES, coordinatesNew);CHKERRQ(ierr);
7000       ierr = VecDestroy(&aux);CHKERRQ(ierr);
7001     }
7002   }
7003   ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
7004   ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
7005   ierr = PetscFree(parentId);CHKERRQ(ierr);
7006   PetscFunctionReturn(0);
7007 }
7008 
7009 /*@
7010   DMPlexCreateProcessSF - Create an SF which just has process connectivity
7011 
7012   Collective on DM
7013 
7014   Input Parameters:
7015 + dm      - The DM
7016 - sfPoint - The PetscSF which encodes point connectivity
7017 
7018   Output Parameters:
7019 + processRanks - A list of process neighbors, or NULL
7020 - sfProcess    - An SF encoding the process connectivity, or NULL
7021 
7022   Level: developer
7023 
7024 .seealso: PetscSFCreate(), DMPlexCreateTwoSidedProcessSF()
7025 @*/
7026 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
7027 {
7028   PetscInt           numRoots, numLeaves, l;
7029   const PetscInt    *localPoints;
7030   const PetscSFNode *remotePoints;
7031   PetscInt          *localPointsNew;
7032   PetscSFNode       *remotePointsNew;
7033   PetscInt          *ranks, *ranksNew;
7034   PetscMPIInt        size;
7035   PetscErrorCode     ierr;
7036 
7037   PetscFunctionBegin;
7038   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7039   PetscValidHeaderSpecific(sfPoint, PETSCSF_CLASSID, 2);
7040   if (processRanks) {PetscValidPointer(processRanks, 3);}
7041   if (sfProcess)    {PetscValidPointer(sfProcess, 4);}
7042   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) dm), &size);CHKERRQ(ierr);
7043   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
7044   ierr = PetscMalloc1(numLeaves, &ranks);CHKERRQ(ierr);
7045   for (l = 0; l < numLeaves; ++l) {
7046     ranks[l] = remotePoints[l].rank;
7047   }
7048   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
7049   ierr = PetscMalloc1(numLeaves, &ranksNew);CHKERRQ(ierr);
7050   ierr = PetscMalloc1(numLeaves, &localPointsNew);CHKERRQ(ierr);
7051   ierr = PetscMalloc1(numLeaves, &remotePointsNew);CHKERRQ(ierr);
7052   for (l = 0; l < numLeaves; ++l) {
7053     ranksNew[l]              = ranks[l];
7054     localPointsNew[l]        = l;
7055     remotePointsNew[l].index = 0;
7056     remotePointsNew[l].rank  = ranksNew[l];
7057   }
7058   ierr = PetscFree(ranks);CHKERRQ(ierr);
7059   if (processRanks) {ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);}
7060   else              {ierr = PetscFree(ranksNew);CHKERRQ(ierr);}
7061   if (sfProcess) {
7062     ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
7063     ierr = PetscObjectSetName((PetscObject) *sfProcess, "Process SF");CHKERRQ(ierr);
7064     ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
7065     ierr = PetscSFSetGraph(*sfProcess, size, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7066   }
7067   PetscFunctionReturn(0);
7068 }
7069 
7070 static PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7071 {
7072   PetscSF            sf, sfNew, sfProcess;
7073   IS                 processRanks;
7074   MPI_Datatype       depthType;
7075   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
7076   const PetscInt    *localPoints, *neighbors;
7077   const PetscSFNode *remotePoints;
7078   PetscInt          *localPointsNew;
7079   PetscSFNode       *remotePointsNew;
7080   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
7081   PetscInt           ldepth, depth, numNeighbors, pStartNew, pEndNew, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r, n;
7082   PetscInt           cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
7083   PetscErrorCode     ierr;
7084 
7085   PetscFunctionBegin;
7086   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
7087   ierr = DMPlexGetDepth(dm, &ldepth);CHKERRQ(ierr);
7088   ierr = MPIU_Allreduce(&ldepth, &depth, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
7089   if ((ldepth >= 0) && (depth != ldepth)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent Plex depth %d != %d", ldepth, depth);
7090   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7091   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7092   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7093   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7094   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7095   cMax = cMax < 0 ? cEnd : cMax;
7096   fMax = fMax < 0 ? fEnd : fMax;
7097   eMax = eMax < 0 ? eEnd : eMax;
7098   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
7099   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
7100   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
7101   /* Calculate size of new SF */
7102   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
7103   if (numRoots < 0) PetscFunctionReturn(0);
7104   for (l = 0; l < numLeaves; ++l) {
7105     const PetscInt p = localPoints[l];
7106 
7107     switch (refiner) {
7108     case REFINER_SIMPLEX_1D:
7109       if ((p >= vStart) && (p < vEnd)) {
7110         /* Interior vertices stay the same */
7111         ++numLeavesNew;
7112       } else if ((p >= cStart && p < cMax)) {
7113         /* Interior cells add new cells and interior vertices */
7114         numLeavesNew += 2 + 1;
7115       }
7116       break;
7117     case REFINER_SIMPLEX_2D:
7118     case REFINER_HYBRID_SIMPLEX_2D:
7119       if ((p >= vStart) && (p < vEnd)) {
7120         /* Interior vertices stay the same */
7121         ++numLeavesNew;
7122       } else if ((p >= fStart) && (p < fMax)) {
7123         /* Interior faces add new faces and vertex */
7124         numLeavesNew += 2 + 1;
7125       } else if ((p >= fMax) && (p < fEnd)) {
7126         /* Hybrid faces stay the same */
7127         ++numLeavesNew;
7128       } else if ((p >= cStart) && (p < cMax)) {
7129         /* Interior cells add new cells and interior faces */
7130         numLeavesNew += 4 + 3;
7131       } else if ((p >= cMax) && (p < cEnd)) {
7132         /* Hybrid cells add new cells and hybrid face */
7133         numLeavesNew += 2 + 1;
7134       }
7135       break;
7136     case REFINER_SIMPLEX_TO_HEX_2D:
7137       if ((p >= vStart) && (p < vEnd)) {
7138         /* Interior vertices stay the same */
7139         ++numLeavesNew;
7140       } else if ((p >= fStart) && (p < fEnd)) {
7141         /* Interior faces add new faces and vertex */
7142         numLeavesNew += 2 + 1;
7143       } else if ((p >= cStart) && (p < cEnd)) {
7144         /* Interior cells add new cells, interior faces, and vertex */
7145         numLeavesNew += 3 + 3 + 1;
7146       }
7147       break;
7148     case REFINER_HEX_2D:
7149     case REFINER_HYBRID_HEX_2D:
7150       if ((p >= vStart) && (p < vEnd)) {
7151         /* Interior vertices stay the same */
7152         ++numLeavesNew;
7153       } else if ((p >= fStart) && (p < fMax)) {
7154         /* Interior faces add new faces and vertex */
7155         numLeavesNew += 2 + 1;
7156       } else if ((p >= fMax) && (p < fEnd)) {
7157         /* Hybrid faces stay the same */
7158         ++numLeavesNew;
7159       } else if ((p >= cStart) && (p < cMax)) {
7160         /* Interior cells add new cells, interior faces, and vertex */
7161         numLeavesNew += 4 + 4 + 1;
7162       } else if ((p >= cMax) && (p < cEnd)) {
7163         /* Hybrid cells add new cells and hybrid face */
7164         numLeavesNew += 2 + 1;
7165       }
7166       break;
7167     case REFINER_SIMPLEX_3D:
7168     case REFINER_HYBRID_SIMPLEX_3D:
7169       if ((p >= vStart) && (p < vEnd)) {
7170         /* Interior vertices stay the same */
7171         ++numLeavesNew;
7172       } else if ((p >= eStart) && (p < eMax)) {
7173         /* Interior edges add new edges and vertex */
7174         numLeavesNew += 2 + 1;
7175       } else if ((p >= eMax) && (p < eEnd)) {
7176         /* Hybrid edges stay the same */
7177         ++numLeavesNew;
7178       } else if ((p >= fStart) && (p < fMax)) {
7179         /* Interior faces add new faces and edges */
7180         numLeavesNew += 4 + 3;
7181       } else if ((p >= fMax) && (p < fEnd)) {
7182         /* Hybrid faces add new faces and edges */
7183         numLeavesNew += 2 + 1;
7184       } else if ((p >= cStart) && (p < cMax)) {
7185         /* Interior cells add new cells, faces, and edges */
7186         numLeavesNew += 8 + 8 + 1;
7187       } else if ((p >= cMax) && (p < cEnd)) {
7188         /* Hybrid cells add new cells and faces */
7189         numLeavesNew += 4 + 3;
7190       }
7191       break;
7192     case REFINER_SIMPLEX_TO_HEX_3D:
7193       if ((p >= vStart) && (p < vEnd)) {
7194         /* Interior vertices stay the same */
7195         ++numLeavesNew;
7196       } else if ((p >= eStart) && (p < eEnd)) {
7197         /* Interior edges add new edges and vertex */
7198         numLeavesNew += 2 + 1;
7199       } else if ((p >= fStart) && (p < fEnd)) {
7200         /* Interior faces add new faces, edges and a vertex */
7201         numLeavesNew += 3 + 3 + 1;
7202       } else if ((p >= cStart) && (p < cEnd)) {
7203         /* Interior cells add new cells, faces, edges and a vertex */
7204         numLeavesNew += 4 + 6 + 4 + 1;
7205       }
7206       break;
7207     case REFINER_HEX_3D:
7208     case REFINER_HYBRID_HEX_3D:
7209       if ((p >= vStart) && (p < vEnd)) {
7210         /* Old vertices stay the same */
7211         ++numLeavesNew;
7212       } else if ((p >= eStart) && (p < eMax)) {
7213         /* Interior edges add new edges, and vertex */
7214         numLeavesNew += 2 + 1;
7215       } else if ((p >= eMax) && (p < eEnd)) {
7216         /* Hybrid edges stay the same */
7217         ++numLeavesNew;
7218       } else if ((p >= fStart) && (p < fMax)) {
7219         /* Interior faces add new faces, edges, and vertex */
7220         numLeavesNew += 4 + 4 + 1;
7221       } else if ((p >= fMax) && (p < fEnd)) {
7222         /* Hybrid faces add new faces and edges */
7223         numLeavesNew += 2 + 1;
7224       } else if ((p >= cStart) && (p < cMax)) {
7225         /* Interior cells add new cells, faces, edges, and vertex */
7226         numLeavesNew += 8 + 12 + 6 + 1;
7227       } else if ((p >= cStart) && (p < cEnd)) {
7228         /* Hybrid cells add new cells, faces, and edges */
7229         numLeavesNew += 4 + 4 + 1;
7230       }
7231       break;
7232     default:
7233       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7234     }
7235   }
7236   /* Communicate depthSizes for each remote rank */
7237   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
7238   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
7239   ierr = PetscMalloc5((depth+1)*numNeighbors,&rdepthSize,numNeighbors,&rvStartNew,numNeighbors,&reStartNew,numNeighbors,&rfStartNew,numNeighbors,&rcStartNew);CHKERRQ(ierr);
7240   ierr = PetscMalloc7(depth+1,&depthSizeOld,(depth+1)*numNeighbors,&rdepthSizeOld,(depth+1)*numNeighbors,&rdepthMaxOld,numNeighbors,&rvStart,numNeighbors,&reStart,numNeighbors,&rfStart,numNeighbors,&rcStart);CHKERRQ(ierr);
7241   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
7242   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
7243   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7244   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7245   for (n = 0; n < numNeighbors; ++n) {
7246     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
7247   }
7248   depthSizeOld[depth]   = cMax;
7249   depthSizeOld[0]       = vMax;
7250   depthSizeOld[depth-1] = fMax;
7251   depthSizeOld[1]       = eMax;
7252 
7253   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7254   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7255 
7256   depthSizeOld[depth]   = cEnd - cStart;
7257   depthSizeOld[0]       = vEnd - vStart;
7258   depthSizeOld[depth-1] = fEnd - fStart;
7259   depthSizeOld[1]       = eEnd - eStart;
7260 
7261   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7262   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7263   for (n = 0; n < numNeighbors; ++n) {
7264     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
7265     rdepthMaxOld[n*(depth+1)+depth]   = rdepthMaxOld[n*(depth+1)+depth]   < 0 ? rdepthSizeOld[n*(depth+1)+depth]  +rcStart[n]: rdepthMaxOld[n*(depth+1)+depth];
7266     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];
7267     rdepthMaxOld[n*(depth+1)+1]       = rdepthMaxOld[n*(depth+1)+1]       < 0 ? rdepthSizeOld[n*(depth+1)+1]      +reStart[n]: rdepthMaxOld[n*(depth+1)+1];
7268   }
7269   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
7270   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
7271   /* Calculate new point SF */
7272   ierr = PetscMalloc1(numLeavesNew, &localPointsNew);CHKERRQ(ierr);
7273   ierr = PetscMalloc1(numLeavesNew, &remotePointsNew);CHKERRQ(ierr);
7274   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
7275   for (l = 0, m = 0; l < numLeaves; ++l) {
7276     PetscInt    p     = localPoints[l];
7277     PetscInt    rp    = remotePoints[l].index, n;
7278     PetscMPIInt rrank = remotePoints[l].rank;
7279 
7280     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
7281     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
7282     switch (refiner) {
7283     case REFINER_SIMPLEX_1D:
7284       if ((p >= vStart) && (p < vEnd)) {
7285         /* Old vertices stay the same */
7286         localPointsNew[m]        = vStartNew     + (p  - vStart);
7287         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7288         remotePointsNew[m].rank  = rrank;
7289         ++m;
7290       } else if ((p >= cStart) && (p < cMax)) {
7291         /* Old interior cells add new cells and vertex */
7292         for (r = 0; r < 2; ++r, ++m) {
7293           localPointsNew[m]        = cStartNew     + (p  - cStart)*2     + r;
7294           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*2 + r;
7295           remotePointsNew[m].rank  = rrank;
7296         }
7297         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - cStart);
7298         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rcStart[n]);
7299         remotePointsNew[m].rank  = rrank;
7300         ++m;
7301       }
7302       break;
7303     case REFINER_SIMPLEX_2D:
7304     case REFINER_HYBRID_SIMPLEX_2D:
7305       if ((p >= vStart) && (p < vEnd)) {
7306         /* Old vertices stay the same */
7307         localPointsNew[m]        = vStartNew     + (p  - vStart);
7308         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7309         remotePointsNew[m].rank  = rrank;
7310         ++m;
7311       } else if ((p >= fStart) && (p < fMax)) {
7312         /* Old interior faces add new faces and vertex */
7313         for (r = 0; r < 2; ++r, ++m) {
7314           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7315           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7316           remotePointsNew[m].rank  = rrank;
7317         }
7318         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7319         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7320         remotePointsNew[m].rank  = rrank;
7321         ++m;
7322       } else if ((p >= fMax) && (p < fEnd)) {
7323         /* Old hybrid faces stay the same */
7324         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
7325         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
7326         remotePointsNew[m].rank  = rrank;
7327         ++m;
7328       } else if ((p >= cStart) && (p < cMax)) {
7329         /* Old interior cells add new cells and interior faces */
7330         for (r = 0; r < 4; ++r, ++m) {
7331           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7332           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7333           remotePointsNew[m].rank  = rrank;
7334         }
7335         for (r = 0; r < 3; ++r, ++m) {
7336           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
7337           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
7338           remotePointsNew[m].rank  = rrank;
7339         }
7340       } else if ((p >= cMax) && (p < cEnd)) {
7341         /* Old hybrid cells add new cells and hybrid face */
7342         for (r = 0; r < 2; ++r, ++m) {
7343           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7344           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7345           remotePointsNew[m].rank  = rrank;
7346         }
7347         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
7348         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]);
7349         remotePointsNew[m].rank  = rrank;
7350         ++m;
7351       }
7352       break;
7353     case REFINER_SIMPLEX_TO_HEX_2D:
7354       if ((p >= vStart) && (p < vEnd)) {
7355         /* Old vertices stay the same */
7356         localPointsNew[m]        = vStartNew     + (p  - vStart);
7357         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7358         remotePointsNew[m].rank  = rrank;
7359         ++m;
7360       } else if ((p >= fStart) && (p < fEnd)) {
7361         /* Old interior faces add new faces and vertex */
7362         for (r = 0; r < 2; ++r, ++m) {
7363           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7364           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7365           remotePointsNew[m].rank  = rrank;
7366         }
7367         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7368         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7369         remotePointsNew[m].rank  = rrank;
7370         ++m;
7371       } else if ((p >= cStart) && (p < cEnd)) {
7372         /* Old interior cells add new cells, interior faces, and a vertex */
7373         for (r = 0; r < 3; ++r, ++m) {
7374           localPointsNew[m]        = cStartNew     + (p  - cStart)*3     + r;
7375           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*3 + r;
7376           remotePointsNew[m].rank  = rrank;
7377         }
7378         for (r = 0; r < 3; ++r, ++m) {
7379           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
7380           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
7381           remotePointsNew[m].rank  = rrank;
7382         }
7383         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (fEnd - fStart)                    + (p  - cStart);
7384         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
7385         remotePointsNew[m].rank  = rrank;
7386         ++m;
7387       }
7388       break;
7389     case REFINER_HEX_2D:
7390     case REFINER_HYBRID_HEX_2D:
7391       if ((p >= vStart) && (p < vEnd)) {
7392         /* Old vertices stay the same */
7393         localPointsNew[m]        = vStartNew     + (p  - vStart);
7394         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7395         remotePointsNew[m].rank  = rrank;
7396         ++m;
7397       } else if ((p >= fStart) && (p < fMax)) {
7398         /* Old interior faces add new faces and vertex */
7399         for (r = 0; r < 2; ++r, ++m) {
7400           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7401           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7402           remotePointsNew[m].rank  = rrank;
7403         }
7404         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7405         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7406         remotePointsNew[m].rank  = rrank;
7407         ++m;
7408       } else if ((p >= fMax) && (p < fEnd)) {
7409         /* Old hybrid faces stay the same */
7410         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
7411         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
7412         remotePointsNew[m].rank  = rrank;
7413         ++m;
7414       } else if ((p >= cStart) && (p < cMax)) {
7415         /* Old interior cells add new cells, interior faces, and vertex */
7416         for (r = 0; r < 4; ++r, ++m) {
7417           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7418           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7419           remotePointsNew[m].rank  = rrank;
7420         }
7421         for (r = 0; r < 4; ++r, ++m) {
7422           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*4     + r;
7423           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*4 + r;
7424           remotePointsNew[m].rank  = rrank;
7425         }
7426         localPointsNew[m]        = vStartNew     + (vEnd - vStart)               + (fMax                              - fStart)     + (p  - cStart);
7427         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0]  + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]);
7428         remotePointsNew[m].rank  = rrank;
7429         ++m;
7430       } else if ((p >= cStart) && (p < cMax)) {
7431         /* Old hybrid cells add new cells and hybrid face */
7432         for (r = 0; r < 2; ++r, ++m) {
7433           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7434           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7435           remotePointsNew[m].rank  = rrank;
7436         }
7437         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*4     + (p  - cMax);
7438         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]);
7439         remotePointsNew[m].rank  = rrank;
7440         ++m;
7441       }
7442       break;
7443     case REFINER_SIMPLEX_3D:
7444     case REFINER_HYBRID_SIMPLEX_3D:
7445       if ((p >= vStart) && (p < vEnd)) {
7446         /* Interior vertices stay the same */
7447         localPointsNew[m]        = vStartNew     + (p  - vStart);
7448         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7449         remotePointsNew[m].rank  = rrank;
7450         ++m;
7451       } else if ((p >= eStart) && (p < eMax)) {
7452         /* Interior edges add new edges and vertex */
7453         for (r = 0; r < 2; ++r, ++m) {
7454           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
7455           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
7456           remotePointsNew[m].rank  = rrank;
7457         }
7458         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
7459         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
7460         remotePointsNew[m].rank  = rrank;
7461         ++m;
7462       } else if ((p >= eMax) && (p < eEnd)) {
7463         /* Hybrid edges stay the same */
7464         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - eMax);
7465         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]);
7466         remotePointsNew[m].rank  = rrank;
7467         ++m;
7468       } else if ((p >= fStart) && (p < fMax)) {
7469         /* Interior faces add new faces and edges */
7470         for (r = 0; r < 4; ++r, ++m) {
7471           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
7472           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
7473           remotePointsNew[m].rank  = rrank;
7474         }
7475         for (r = 0; r < 3; ++r, ++m) {
7476           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*3     + r;
7477           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
7478           remotePointsNew[m].rank  = rrank;
7479         }
7480       } else if ((p >= fMax) && (p < fEnd)) {
7481         /* Hybrid faces add new faces and edges */
7482         for (r = 0; r < 2; ++r, ++m) {
7483           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fMax)*2                              + r;
7484           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;
7485           remotePointsNew[m].rank  = rrank;
7486         }
7487         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (eEnd                                    - eMax)                        + (p  - fMax);
7488         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]);
7489         remotePointsNew[m].rank  = rrank;
7490         ++m;
7491       } else if ((p >= cStart) && (p < cMax)) {
7492         /* Interior cells add new cells, faces, and edges */
7493         for (r = 0; r < 8; ++r, ++m) {
7494           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
7495           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
7496           remotePointsNew[m].rank  = rrank;
7497         }
7498         for (r = 0; r < 8; ++r, ++m) {
7499           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*8     + r;
7500           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*8 + r;
7501           remotePointsNew[m].rank  = rrank;
7502         }
7503         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (p  - cStart)*1     + 0;
7504         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;
7505         remotePointsNew[m].rank  = rrank;
7506         ++m;
7507       } else if ((p >= cMax) && (p < cEnd)) {
7508         /* Hybrid cells add new cells and faces */
7509         for (r = 0; r < 4; ++r, ++m) {
7510           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
7511           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
7512           remotePointsNew[m].rank  = rrank;
7513         }
7514         for (r = 0; r < 3; ++r, ++m) {
7515           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*2                              + (p  - cMax)*3                            + r;
7516           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;
7517           remotePointsNew[m].rank  = rrank;
7518         }
7519       }
7520       break;
7521     case REFINER_SIMPLEX_TO_HEX_3D:
7522       if ((p >= vStart) && (p < vEnd)) {
7523         /* Interior vertices stay the same */
7524         localPointsNew[m]        = vStartNew     + (p  - vStart);
7525         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7526         remotePointsNew[m].rank  = rrank;
7527         ++m;
7528       } else if ((p >= eStart) && (p < eEnd)) {
7529         /* Interior edges add new edges and vertex */
7530         for (r = 0; r < 2; ++r, ++m) {
7531           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
7532           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
7533           remotePointsNew[m].rank  = rrank;
7534         }
7535         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
7536         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
7537         remotePointsNew[m].rank  = rrank;
7538         ++m;
7539       } else if ((p >= fStart) && (p < fEnd)) {
7540         /* Interior faces add new faces, edges and a vertex */
7541         for (r = 0; r < 3; ++r, ++m) {
7542           localPointsNew[m]        = fStartNew     + (p  - fStart)*3     + r;
7543           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*3 + r;
7544           remotePointsNew[m].rank  = rrank;
7545         }
7546         for (r = 0; r < 3; ++r, ++m) {
7547           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2                + (p  - fStart)*3     + r;
7548           remotePointsNew[m].index = reStartNew[n] + (rdepthSizeOld[n*(depth+1)+1])*2 + (rp - rfStart[n])*3 + r;
7549           remotePointsNew[m].rank  = rrank;
7550         }
7551         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eEnd - eStart)              + (p - fStart);
7552         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+1] + (rp - rfStart[n]);
7553         remotePointsNew[m].rank  = rrank;
7554         ++m;
7555       } else if ((p >= cStart) && (p < cEnd)) {
7556         /* Interior cells add new cells, faces, edges, and a vertex */
7557         for (r = 0; r < 4; ++r, ++m) {
7558           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7559           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7560           remotePointsNew[m].rank  = rrank;
7561         }
7562         for (r = 0; r < 6; ++r, ++m) {
7563           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*3                    + (p  - cStart)*6     + r;
7564           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*3 + (rp - rcStart[n])*6 + r;
7565           remotePointsNew[m].rank  = rrank;
7566         }
7567         for (r = 0; r < 4; ++r, ++m) {
7568           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (fEnd - fStart)*3                    + (p  - cStart)*4 + r;
7569           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + rdepthSizeOld[n*(depth+1)+depth-1]*3 + (rp - rcStart[n])*4 + r;
7570           remotePointsNew[m].rank  = rrank;
7571         }
7572         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eEnd - eStart)              + (fEnd - fStart)                    + (p - cStart);
7573         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+1] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
7574         remotePointsNew[m].rank  = rrank;
7575         ++m;
7576       }
7577       break;
7578     case REFINER_HEX_3D:
7579     case REFINER_HYBRID_HEX_3D:
7580       if ((p >= vStart) && (p < vEnd)) {
7581         /* Interior vertices stay the same */
7582         localPointsNew[m]        = vStartNew     + (p  - vStart);
7583         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7584         remotePointsNew[m].rank  = rrank;
7585         ++m;
7586       } else if ((p >= eStart) && (p < eMax)) {
7587         /* Interior edges add new edges and vertex */
7588         for (r = 0; r < 2; ++r, ++m) {
7589           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
7590           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
7591           remotePointsNew[m].rank  = rrank;
7592         }
7593         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
7594         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
7595         remotePointsNew[m].rank  = rrank;
7596         ++m;
7597       } else if ((p >= eMax) && (p < eEnd)) {
7598         /* Hybrid edges stay the same */
7599         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (p  - eMax);
7600         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]);
7601         remotePointsNew[m].rank  = rrank;
7602         ++m;
7603       } else if ((p >= fStart) && (p < fMax)) {
7604         /* Interior faces add new faces, edges, and vertex */
7605         for (r = 0; r < 4; ++r, ++m) {
7606           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
7607           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
7608           remotePointsNew[m].rank  = rrank;
7609         }
7610         for (r = 0; r < 4; ++r, ++m) {
7611           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*4     + r;
7612           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*4 + r;
7613           remotePointsNew[m].rank  = rrank;
7614         }
7615         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax                        - eStart)     + (p  - fStart);
7616         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
7617         remotePointsNew[m].rank  = rrank;
7618         ++m;
7619       } else if ((p >= fMax) && (p < fEnd)) {
7620         /* Hybrid faces add new faces and edges */
7621         for (r = 0; r < 2; ++r, ++m) {
7622           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (p  - fMax)*2                              + r;
7623           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;
7624           remotePointsNew[m].rank  = rrank;
7625         }
7626         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (p  - fMax);
7627         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]);
7628         remotePointsNew[m].rank  = rrank;
7629         ++m;
7630       } else if ((p >= cStart) && (p < cMax)) {
7631         /* Interior cells add new cells, faces, edges, and vertex */
7632         for (r = 0; r < 8; ++r, ++m) {
7633           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
7634           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
7635           remotePointsNew[m].rank  = rrank;
7636         }
7637         for (r = 0; r < 12; ++r, ++m) {
7638           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*12     + r;
7639           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*12 + r;
7640           remotePointsNew[m].rank  = rrank;
7641         }
7642         for (r = 0; r < 6; ++r, ++m) {
7643           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (p  - cStart)*6     + r;
7644           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;
7645           remotePointsNew[m].rank  = rrank;
7646         }
7647         for (r = 0; r < 1; ++r, ++m) {
7648           localPointsNew[m]        = vStartNew     + (eMax                        - eStart)     + (fMax                              - fStart)     + (p  - cStart)     + r;
7649           remotePointsNew[m].index = rvStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]) + r;
7650           remotePointsNew[m].rank  = rrank;
7651         }
7652       } else if ((p >= cMax) && (p < cEnd)) {
7653         /* Hybrid cells add new cells, faces, and edges */
7654         for (r = 0; r < 4; ++r, ++m) {
7655           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
7656           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
7657           remotePointsNew[m].rank  = rrank;
7658         }
7659         for (r = 0; r < 4; ++r, ++m) {
7660           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (fEnd                                          - fMax)*2                              + (p  - cMax)*4                            + r;
7661           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;
7662           remotePointsNew[m].rank  = rrank;
7663         }
7664         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (fEnd                                          - fMax)                              + (p  - cMax);
7665         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]);
7666         remotePointsNew[m].rank  = rrank;
7667         ++m;
7668       }
7669       break;
7670     default:
7671       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7672     }
7673   }
7674   if (m != numLeavesNew) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of leaf point %d should be %d", m, numLeavesNew);
7675   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
7676   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
7677   {
7678     PetscSFNode *rp, *rtmp;
7679     PetscInt    *lp, *idx, *ltmp, i;
7680 
7681     /* SF needs sorted leaves to correct calculate Gather */
7682     ierr = PetscMalloc1(numLeavesNew,&idx);CHKERRQ(ierr);
7683     ierr = PetscMalloc1(numLeavesNew, &lp);CHKERRQ(ierr);
7684     ierr = PetscMalloc1(numLeavesNew, &rp);CHKERRQ(ierr);
7685     for (i = 0; i < numLeavesNew; ++i) {
7686       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);
7687       idx[i] = i;
7688     }
7689     ierr = PetscSortIntWithPermutation(numLeavesNew, localPointsNew, idx);CHKERRQ(ierr);
7690     for (i = 0; i < numLeavesNew; ++i) {
7691       lp[i] = localPointsNew[idx[i]];
7692       rp[i] = remotePointsNew[idx[i]];
7693     }
7694     ltmp            = localPointsNew;
7695     localPointsNew  = lp;
7696     rtmp            = remotePointsNew;
7697     remotePointsNew = rp;
7698     ierr = PetscFree(idx);CHKERRQ(ierr);
7699     ierr = PetscFree(ltmp);CHKERRQ(ierr);
7700     ierr = PetscFree(rtmp);CHKERRQ(ierr);
7701   }
7702   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7703   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
7704   ierr = PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
7705   PetscFunctionReturn(0);
7706 }
7707 
7708 static PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7709 {
7710   PetscInt       numLabels, l;
7711   PetscInt       depth, newp, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r;
7712   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
7713   PetscErrorCode ierr;
7714 
7715   PetscFunctionBegin;
7716   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7717   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7718   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7719   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7720   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7721   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
7722   ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
7723   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7724   switch (refiner) {
7725   case REFINER_NOOP:
7726   case REFINER_SIMPLEX_1D:
7727   case REFINER_SIMPLEX_2D:
7728   case REFINER_SIMPLEX_TO_HEX_2D:
7729   case REFINER_HEX_2D:
7730   case REFINER_SIMPLEX_3D:
7731   case REFINER_HEX_3D:
7732   case REFINER_SIMPLEX_TO_HEX_3D:
7733     break;
7734   case REFINER_HYBRID_SIMPLEX_3D:
7735   case REFINER_HYBRID_HEX_3D:
7736     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
7737   case REFINER_HYBRID_SIMPLEX_2D:
7738   case REFINER_HYBRID_HEX_2D:
7739     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7740     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7741     break;
7742   default:
7743     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7744   }
7745   for (l = 0; l < numLabels; ++l) {
7746     DMLabel         label, labelNew;
7747     const char     *lname;
7748     PetscBool       isDepth;
7749     IS              valueIS;
7750     const PetscInt *values;
7751     PetscInt        defVal;
7752     PetscInt        numValues, val;
7753 
7754     ierr = DMGetLabelName(dm, l, &lname);CHKERRQ(ierr);
7755     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
7756     if (isDepth) continue;
7757     ierr = DMCreateLabel(rdm, lname);CHKERRQ(ierr);
7758     ierr = DMGetLabel(dm, lname, &label);CHKERRQ(ierr);
7759     ierr = DMGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
7760     ierr = DMLabelGetDefaultValue(label,&defVal);CHKERRQ(ierr);
7761     ierr = DMLabelSetDefaultValue(labelNew,defVal);CHKERRQ(ierr);
7762     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
7763     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
7764     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
7765     for (val = 0; val < numValues; ++val) {
7766       IS              pointIS;
7767       const PetscInt *points;
7768       PetscInt        numPoints, n;
7769 
7770       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
7771       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
7772       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
7773       /* Ensure refined label is created with same number of strata as
7774        * original (even if no entries here). */
7775       ierr = DMLabelAddStratum(labelNew, values[val]);CHKERRQ(ierr);
7776       for (n = 0; n < numPoints; ++n) {
7777         const PetscInt p = points[n];
7778         switch (refiner) {
7779         case REFINER_SIMPLEX_1D:
7780           if ((p >= vStart) && (p < vEnd)) {
7781             /* Old vertices stay the same */
7782             newp = vStartNew + (p - vStart);
7783             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7784           } else if ((p >= cStart) && (p < cEnd)) {
7785             /* Old cells add new cells and vertex */
7786             newp = vStartNew + (vEnd - vStart) + (p - cStart);
7787             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7788             for (r = 0; r < 2; ++r) {
7789               newp = cStartNew + (p - cStart)*2 + r;
7790               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7791             }
7792           }
7793           break;
7794         case REFINER_SIMPLEX_2D:
7795           if ((p >= vStart) && (p < vEnd)) {
7796             /* Old vertices stay the same */
7797             newp = vStartNew + (p - vStart);
7798             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7799           } else if ((p >= fStart) && (p < fEnd)) {
7800             /* Old faces add new faces and vertex */
7801             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7802             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7803             for (r = 0; r < 2; ++r) {
7804               newp = fStartNew + (p - fStart)*2 + r;
7805               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7806             }
7807           } else if ((p >= cStart) && (p < cEnd)) {
7808             /* Old cells add new cells and interior faces */
7809             for (r = 0; r < 4; ++r) {
7810               newp = cStartNew + (p - cStart)*4 + r;
7811               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7812             }
7813             for (r = 0; r < 3; ++r) {
7814               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7815               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7816             }
7817           }
7818           break;
7819         case REFINER_SIMPLEX_TO_HEX_2D:
7820           if ((p >= vStart) && (p < vEnd)) {
7821             /* Old vertices stay the same */
7822             newp = vStartNew + (p - vStart);
7823             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7824           } else if ((p >= fStart) && (p < fEnd)) {
7825             /* Old faces add new faces and vertex */
7826             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7827             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7828             for (r = 0; r < 2; ++r) {
7829               newp = fStartNew + (p - fStart)*2 + r;
7830               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7831             }
7832           } else if ((p >= cStart) && (p < cEnd)) {
7833             /* Old cells add new cells, interior faces, and a vertex */
7834             for (r = 0; r < 3; ++r) {
7835               newp = cStartNew + (p - cStart)*3 + r;
7836               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7837             }
7838             for (r = 0; r < 3; ++r) {
7839               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7840               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7841             }
7842             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + p;
7843             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7844           }
7845           break;
7846         case REFINER_HEX_2D:
7847           if ((p >= vStart) && (p < vEnd)) {
7848             /* Old vertices stay the same */
7849             newp = vStartNew + (p - vStart);
7850             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7851           } else if ((p >= fStart) && (p < fEnd)) {
7852             /* Old faces add new faces and vertex */
7853             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7854             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7855             for (r = 0; r < 2; ++r) {
7856               newp = fStartNew + (p - fStart)*2 + r;
7857               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7858             }
7859           } else if ((p >= cStart) && (p < cEnd)) {
7860             /* Old cells add new cells and interior faces and vertex */
7861             for (r = 0; r < 4; ++r) {
7862               newp = cStartNew + (p - cStart)*4 + r;
7863               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7864             }
7865             for (r = 0; r < 4; ++r) {
7866               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
7867               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7868             }
7869             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
7870             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7871           }
7872           break;
7873         case REFINER_HYBRID_SIMPLEX_2D:
7874           if ((p >= vStart) && (p < vEnd)) {
7875             /* Old vertices stay the same */
7876             newp = vStartNew + (p - vStart);
7877             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7878           } else if ((p >= fStart) && (p < fMax)) {
7879             /* Old interior faces add new faces and vertex */
7880             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7881             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7882             for (r = 0; r < 2; ++r) {
7883               newp = fStartNew + (p - fStart)*2 + r;
7884               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7885             }
7886           } else if ((p >= fMax) && (p < fEnd)) {
7887             /* Old hybrid faces stay the same */
7888             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7889             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7890           } else if ((p >= cStart) && (p < cMax)) {
7891             /* Old interior cells add new cells and interior faces */
7892             for (r = 0; r < 4; ++r) {
7893               newp = cStartNew + (p - cStart)*4 + r;
7894               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7895             }
7896             for (r = 0; r < 3; ++r) {
7897               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7898               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7899             }
7900           } else if ((p >= cMax) && (p < cEnd)) {
7901             /* Old hybrid cells add new cells and hybrid face */
7902             for (r = 0; r < 2; ++r) {
7903               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
7904               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7905             }
7906             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
7907             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7908           }
7909           break;
7910         case REFINER_HYBRID_HEX_2D:
7911           if ((p >= vStart) && (p < vEnd)) {
7912             /* Old vertices stay the same */
7913             newp = vStartNew + (p - vStart);
7914             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7915           } else if ((p >= fStart) && (p < fMax)) {
7916             /* Old interior faces add new faces and vertex */
7917             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7918             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7919             for (r = 0; r < 2; ++r) {
7920               newp = fStartNew + (p - fStart)*2 + r;
7921               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7922             }
7923           } else if ((p >= fMax) && (p < fEnd)) {
7924             /* Old hybrid faces stay the same */
7925             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7926             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7927           } else if ((p >= cStart) && (p < cMax)) {
7928             /* Old interior cells add new cells, interior faces, and vertex */
7929             for (r = 0; r < 4; ++r) {
7930               newp = cStartNew + (p - cStart)*4 + r;
7931               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7932             }
7933             for (r = 0; r < 4; ++r) {
7934               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
7935               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7936             }
7937             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
7938             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7939           } else if ((p >= cMax) && (p < cEnd)) {
7940             /* Old hybrid cells add new cells and hybrid face */
7941             for (r = 0; r < 2; ++r) {
7942               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
7943               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7944             }
7945             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (p - cMax);
7946             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7947           }
7948           break;
7949         case REFINER_SIMPLEX_3D:
7950           if ((p >= vStart) && (p < vEnd)) {
7951             /* Old vertices stay the same */
7952             newp = vStartNew + (p - vStart);
7953             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7954           } else if ((p >= eStart) && (p < eEnd)) {
7955             /* Old edges add new edges and vertex */
7956             for (r = 0; r < 2; ++r) {
7957               newp = eStartNew + (p - eStart)*2 + r;
7958               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7959             }
7960             newp = vStartNew + (vEnd - vStart) + (p - eStart);
7961             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7962           } else if ((p >= fStart) && (p < fEnd)) {
7963             /* Old faces add new faces and edges */
7964             for (r = 0; r < 4; ++r) {
7965               newp = fStartNew + (p - fStart)*4 + r;
7966               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7967             }
7968             for (r = 0; r < 3; ++r) {
7969               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
7970               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7971             }
7972           } else if ((p >= cStart) && (p < cEnd)) {
7973             /* Old cells add new cells and interior faces and edges */
7974             for (r = 0; r < 8; ++r) {
7975               newp = cStartNew + (p - cStart)*8 + r;
7976               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7977             }
7978             for (r = 0; r < 8; ++r) {
7979               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*8 + r;
7980               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7981             }
7982             for (r = 0; r < 1; ++r) {
7983               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*1 + r;
7984               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7985             }
7986           }
7987           break;
7988         case REFINER_SIMPLEX_TO_HEX_3D:
7989           if ((p >= vStart) && (p < vEnd)) {
7990             /* Old vertices stay the same */
7991             newp = vStartNew + (p - vStart);
7992             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7993           } else if ((p >= eStart) && (p < eEnd)) {
7994             /* Old edges add new edges and vertex */
7995             for (r = 0; r < 2; ++r) {
7996               newp = eStartNew + (p - eStart)*2 + r;
7997               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7998             }
7999             newp = vStartNew + (vEnd - vStart) + (p - eStart);
8000             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8001           } else if ((p >= fStart) && (p < fEnd)) {
8002             /* Old faces add new faces, edges and a vertex */
8003             for (r = 0; r < 3; ++r) {
8004               newp = fStartNew + (p - fStart)*3 + r;
8005               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8006             }
8007             for (r = 0; r < 3; ++r) {
8008               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
8009               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8010             }
8011           } else if ((p >= cStart) && (p < cEnd)) {
8012             /* Old cells add new cells and interior faces and edges and a vertex */
8013             for (r = 0; r < 4; ++r) {
8014               newp = cStartNew + (p - cStart)*4 + r;
8015               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8016             }
8017             for (r = 0; r < 6; ++r) {
8018               newp = fStartNew + (fEnd - fStart)*3 + (p - cStart)*6 + r;
8019               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8020             }
8021             for (r = 0; r < 4; ++r) {
8022               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*4 + r;
8023               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8024             }
8025             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + p - cStart;
8026             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8027           }
8028           break;
8029         case REFINER_HYBRID_SIMPLEX_3D:
8030           if ((p >= vStart) && (p < vEnd)) {
8031             /* Interior vertices stay the same */
8032             newp = vStartNew + (p - vStart);
8033             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8034           } else if ((p >= eStart) && (p < eMax)) {
8035             /* Interior edges add new edges and vertex */
8036             for (r = 0; r < 2; ++r) {
8037               newp = eStartNew + (p - eStart)*2 + r;
8038               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8039             }
8040             newp = vStartNew + (vEnd - vStart) + (p - eStart);
8041             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8042           } else if ((p >= eMax) && (p < eEnd)) {
8043             /* Hybrid edges stay the same */
8044             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - eMax);
8045             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8046           } else if ((p >= fStart) && (p < fMax)) {
8047             /* Interior faces add new faces and edges */
8048             for (r = 0; r < 4; ++r) {
8049               newp = fStartNew + (p - fStart)*4 + r;
8050               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8051             }
8052             for (r = 0; r < 3; ++r) {
8053               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
8054               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8055             }
8056           } else if ((p >= fMax) && (p < fEnd)) {
8057             /* Hybrid faces add new faces and edges */
8058             for (r = 0; r < 2; ++r) {
8059               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (p - fMax)*2 + r;
8060               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8061             }
8062             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - fMax);
8063             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8064           } else if ((p >= cStart) && (p < cMax)) {
8065             /* Interior cells add new cells, faces, and edges */
8066             for (r = 0; r < 8; ++r) {
8067               newp = cStartNew + (p - cStart)*8 + r;
8068               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8069             }
8070             for (r = 0; r < 8; ++r) {
8071               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*8 + r;
8072               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8073             }
8074             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart);
8075             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8076           } else if ((p >= cMax) && (p < cEnd)) {
8077             /* Hybrid cells add new cells and faces */
8078             for (r = 0; r < 4; ++r) {
8079               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
8080               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8081             }
8082             for (r = 0; r < 3; ++r) {
8083               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
8084               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8085             }
8086           }
8087           break;
8088         case REFINER_HEX_3D:
8089           if ((p >= vStart) && (p < vEnd)) {
8090             /* Old vertices stay the same */
8091             newp = vStartNew + (p - vStart);
8092             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8093           } else if ((p >= eStart) && (p < eEnd)) {
8094             /* Old edges add new edges and vertex */
8095             for (r = 0; r < 2; ++r) {
8096               newp = eStartNew + (p - eStart)*2 + r;
8097               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8098             }
8099             newp = vStartNew + (vEnd - vStart) + (p - eStart);
8100             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8101           } else if ((p >= fStart) && (p < fEnd)) {
8102             /* Old faces add new faces, edges, and vertex */
8103             for (r = 0; r < 4; ++r) {
8104               newp = fStartNew + (p - fStart)*4 + r;
8105               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8106             }
8107             for (r = 0; r < 4; ++r) {
8108               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*4 + r;
8109               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8110             }
8111             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (p - fStart);
8112             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8113           } else if ((p >= cStart) && (p < cEnd)) {
8114             /* Old cells add new cells, faces, edges, and vertex */
8115             for (r = 0; r < 8; ++r) {
8116               newp = cStartNew + (p - cStart)*8 + r;
8117               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8118             }
8119             for (r = 0; r < 12; ++r) {
8120               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*12 + r;
8121               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8122             }
8123             for (r = 0; r < 6; ++r) {
8124               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (p - cStart)*6 + r;
8125               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8126             }
8127             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (p - cStart);
8128             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8129           }
8130           break;
8131         case REFINER_HYBRID_HEX_3D:
8132           if ((p >= vStart) && (p < vEnd)) {
8133             /* Interior vertices stay the same */
8134             newp = vStartNew + (p - vStart);
8135             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8136           } else if ((p >= eStart) && (p < eMax)) {
8137             /* Interior edges add new edges and vertex */
8138             for (r = 0; r < 2; ++r) {
8139               newp = eStartNew + (p - eStart)*2 + r;
8140               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8141             }
8142             newp = vStartNew + (vEnd - vStart) + (p - eStart);
8143             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8144           } else if ((p >= eMax) && (p < eEnd)) {
8145             /* Hybrid edges stay the same */
8146             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - eMax);
8147             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8148           } else if ((p >= fStart) && (p < fMax)) {
8149             /* Interior faces add new faces, edges, and vertex */
8150             for (r = 0; r < 4; ++r) {
8151               newp = fStartNew + (p - fStart)*4 + r;
8152               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8153             }
8154             for (r = 0; r < 4; ++r) {
8155               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*4 + r;
8156               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8157             }
8158             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (p - fStart);
8159             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8160           } else if ((p >= fMax) && (p < fEnd)) {
8161             /* Hybrid faces add new faces and edges */
8162             for (r = 0; r < 2; ++r) {
8163               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (p - fMax)*2 + r;
8164               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8165             }
8166             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - fMax);
8167             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8168           } else if ((p >= cStart) && (p < cMax)) {
8169             /* Interior cells add new cells, faces, edges, and vertex */
8170             for (r = 0; r < 8; ++r) {
8171               newp = cStartNew + (p - cStart)*8 + r;
8172               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8173             }
8174             for (r = 0; r < 12; ++r) {
8175               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*12 + r;
8176               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8177             }
8178             for (r = 0; r < 6; ++r) {
8179               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (p - cStart)*6 + r;
8180               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8181             }
8182             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (p - cStart);
8183             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8184           } else if ((p >= cMax) && (p < cEnd)) {
8185             /* Hybrid cells add new cells, faces, and edges */
8186             for (r = 0; r < 4; ++r) {
8187               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
8188               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8189             }
8190             for (r = 0; r < 4; ++r) {
8191               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (p - cMax)*4 + r;
8192               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8193             }
8194             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (fEnd - fMax) + (p - cMax);
8195             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8196           }
8197           break;
8198         default:
8199           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
8200         }
8201       }
8202       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
8203       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
8204     }
8205     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
8206     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
8207     if (0) {
8208       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
8209     }
8210   }
8211   PetscFunctionReturn(0);
8212 }
8213 
8214 /* This will only work for interpolated meshes */
8215 PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
8216 {
8217   DM             rdm;
8218   PetscInt      *depthSize;
8219   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
8220   PetscErrorCode ierr;
8221 
8222   PetscFunctionBegin;
8223   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
8224   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
8225   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
8226   ierr = DMSetDimension(rdm, dim);CHKERRQ(ierr);
8227   /* Calculate number of new points of each depth */
8228   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
8229   if (depth >= 0 && dim != depth) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Mesh must be interpolated for regular refinement");
8230   ierr = PetscMalloc1(depth+1, &depthSize);CHKERRQ(ierr);
8231   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
8232   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
8233   /* Step 1: Set chart */
8234   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
8235   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
8236   /* Step 2: Set cone/support sizes */
8237   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
8238   /* Step 3: Setup refined DM */
8239   ierr = DMSetUp(rdm);CHKERRQ(ierr);
8240   /* Step 4: Set cones and supports */
8241   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
8242   /* Step 5: Stratify */
8243   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
8244   /* Step 6: Create pointSF */
8245   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
8246   /* Step 7: Create labels */
8247   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
8248   /* Step 8: Set coordinates */
8249   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
8250   ierr = PetscFree(depthSize);CHKERRQ(ierr);
8251 
8252   *dmRefined = rdm;
8253   PetscFunctionReturn(0);
8254 }
8255 
8256 /*@
8257   DMPlexCreateCoarsePointIS - Creates an IS covering the coarse DM chart with the fine points as data
8258 
8259   Input Parameter:
8260 . dm - The coarse DM
8261 
8262   Output Parameter:
8263 . fpointIS - The IS of all the fine points which exist in the original coarse mesh
8264 
8265   Level: developer
8266 
8267 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexCreateSubpointIS()
8268 @*/
8269 PetscErrorCode DMPlexCreateCoarsePointIS(DM dm, IS *fpointIS)
8270 {
8271   CellRefiner    cellRefiner;
8272   PetscInt      *depthSize, *fpoints;
8273   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
8274   PetscInt       depth, pStart, pEnd, p, vStart, vEnd, v;
8275   PetscErrorCode ierr;
8276 
8277   PetscFunctionBegin;
8278   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
8279   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
8280   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8281   ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr);
8282   ierr = PetscMalloc1(depth+1, &depthSize);CHKERRQ(ierr);
8283   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
8284   if (cellRefiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
8285   ierr = PetscMalloc1(pEnd-pStart,&fpoints);CHKERRQ(ierr);
8286   for (p = 0; p < pEnd-pStart; ++p) fpoints[p] = -1;
8287   switch (cellRefiner) {
8288   case REFINER_SIMPLEX_1D:
8289   case REFINER_SIMPLEX_2D:
8290   case REFINER_HYBRID_SIMPLEX_2D:
8291   case REFINER_HEX_2D:
8292   case REFINER_HYBRID_HEX_2D:
8293   case REFINER_SIMPLEX_3D:
8294   case REFINER_HYBRID_SIMPLEX_3D:
8295   case REFINER_HEX_3D:
8296   case REFINER_HYBRID_HEX_3D:
8297     for (v = vStart; v < vEnd; ++v) fpoints[v-pStart] = vStartNew + (v - vStart);
8298     break;
8299   default:
8300     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", cellRefiner);
8301   }
8302   ierr = ISCreateGeneral(PETSC_COMM_SELF, pEnd-pStart, fpoints, PETSC_OWN_POINTER, fpointIS);CHKERRQ(ierr);
8303   ierr = PetscFree(depthSize);CHKERRQ(ierr);
8304   PetscFunctionReturn(0);
8305 }
8306 
8307 /*@
8308   DMPlexSetRefinementUniform - Set the flag for uniform refinement
8309 
8310   Input Parameters:
8311 + dm - The DM
8312 - refinementUniform - The flag for uniform refinement
8313 
8314   Level: developer
8315 
8316 .seealso: DMRefine(), DMPlexGetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
8317 @*/
8318 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
8319 {
8320   DM_Plex *mesh = (DM_Plex*) dm->data;
8321 
8322   PetscFunctionBegin;
8323   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8324   mesh->refinementUniform = refinementUniform;
8325   PetscFunctionReturn(0);
8326 }
8327 
8328 /*@
8329   DMPlexGetRefinementUniform - Retrieve the flag for uniform refinement
8330 
8331   Input Parameter:
8332 . dm - The DM
8333 
8334   Output Parameter:
8335 . refinementUniform - The flag for uniform refinement
8336 
8337   Level: developer
8338 
8339 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
8340 @*/
8341 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
8342 {
8343   DM_Plex *mesh = (DM_Plex*) dm->data;
8344 
8345   PetscFunctionBegin;
8346   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8347   PetscValidPointer(refinementUniform,  2);
8348   *refinementUniform = mesh->refinementUniform;
8349   PetscFunctionReturn(0);
8350 }
8351 
8352 /*@
8353   DMPlexSetRefinementLimit - Set the maximum cell volume for refinement
8354 
8355   Input Parameters:
8356 + dm - The DM
8357 - refinementLimit - The maximum cell volume in the refined mesh
8358 
8359   Level: developer
8360 
8361 .seealso: DMRefine(), DMPlexGetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
8362 @*/
8363 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
8364 {
8365   DM_Plex *mesh = (DM_Plex*) dm->data;
8366 
8367   PetscFunctionBegin;
8368   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8369   mesh->refinementLimit = refinementLimit;
8370   PetscFunctionReturn(0);
8371 }
8372 
8373 /*@
8374   DMPlexGetRefinementLimit - Retrieve the maximum cell volume for refinement
8375 
8376   Input Parameter:
8377 . dm - The DM
8378 
8379   Output Parameter:
8380 . refinementLimit - The maximum cell volume in the refined mesh
8381 
8382   Level: developer
8383 
8384 .seealso: DMRefine(), DMPlexSetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
8385 @*/
8386 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
8387 {
8388   DM_Plex *mesh = (DM_Plex*) dm->data;
8389 
8390   PetscFunctionBegin;
8391   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8392   PetscValidPointer(refinementLimit,  2);
8393   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
8394   *refinementLimit = mesh->refinementLimit;
8395   PetscFunctionReturn(0);
8396 }
8397 
8398 /*@
8399   DMPlexSetRefinementFunction - Set the function giving the maximum cell volume for refinement
8400 
8401   Input Parameters:
8402 + dm - The DM
8403 - refinementFunc - Function giving the maximum cell volume in the refined mesh
8404 
8405   Note: The calling sequence is refinementFunc(coords, limit)
8406 $ coords - Coordinates of the current point, usually a cell centroid
8407 $ limit  - The maximum cell volume for a cell containing this point
8408 
8409   Level: developer
8410 
8411 .seealso: DMRefine(), DMPlexGetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
8412 @*/
8413 PetscErrorCode DMPlexSetRefinementFunction(DM dm, PetscErrorCode (*refinementFunc)(const PetscReal [], PetscReal *))
8414 {
8415   DM_Plex *mesh = (DM_Plex*) dm->data;
8416 
8417   PetscFunctionBegin;
8418   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8419   mesh->refinementFunc = refinementFunc;
8420   PetscFunctionReturn(0);
8421 }
8422 
8423 /*@
8424   DMPlexGetRefinementFunction - Get the function giving the maximum cell volume for refinement
8425 
8426   Input Parameter:
8427 . dm - The DM
8428 
8429   Output Parameter:
8430 . refinementFunc - Function giving the maximum cell volume in the refined mesh
8431 
8432   Note: The calling sequence is refinementFunc(coords, limit)
8433 $ coords - Coordinates of the current point, usually a cell centroid
8434 $ limit  - The maximum cell volume for a cell containing this point
8435 
8436   Level: developer
8437 
8438 .seealso: DMRefine(), DMPlexSetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
8439 @*/
8440 PetscErrorCode DMPlexGetRefinementFunction(DM dm, PetscErrorCode (**refinementFunc)(const PetscReal [], PetscReal *))
8441 {
8442   DM_Plex *mesh = (DM_Plex*) dm->data;
8443 
8444   PetscFunctionBegin;
8445   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8446   PetscValidPointer(refinementFunc,  2);
8447   *refinementFunc = mesh->refinementFunc;
8448   PetscFunctionReturn(0);
8449 }
8450 
8451 PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
8452 {
8453   PetscInt       dim, cStart, cEnd, coneSize, cMax, fMax;
8454   PetscErrorCode ierr;
8455 
8456   PetscFunctionBegin;
8457   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
8458   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8459   if (cEnd <= cStart) {*cellRefiner = REFINER_NOOP; PetscFunctionReturn(0);}
8460   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
8461   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, NULL, NULL);CHKERRQ(ierr);
8462   switch (dim) {
8463   case 1:
8464     switch (coneSize) {
8465     case 2:
8466       *cellRefiner = REFINER_SIMPLEX_1D;
8467       break;
8468     default:
8469       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
8470     }
8471     break;
8472   case 2:
8473     switch (coneSize) {
8474     case 3:
8475       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_2D;
8476       else *cellRefiner = REFINER_SIMPLEX_2D;
8477       break;
8478     case 4:
8479       if (cMax >= 0 && fMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_2D;
8480       else *cellRefiner = REFINER_HEX_2D;
8481       break;
8482     default:
8483       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
8484     }
8485     break;
8486   case 3:
8487     switch (coneSize) {
8488     case 4:
8489       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_3D;
8490       else *cellRefiner = REFINER_SIMPLEX_3D;
8491       break;
8492     case 6:
8493       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_3D;
8494       else *cellRefiner = REFINER_HEX_3D;
8495       break;
8496     default:
8497       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
8498     }
8499     break;
8500   default:
8501     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
8502   }
8503   PetscFunctionReturn(0);
8504 }
8505 
8506 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
8507 {
8508   PetscBool      isUniform;
8509   PetscErrorCode ierr;
8510 
8511   PetscFunctionBegin;
8512   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
8513   if (isUniform) {
8514     CellRefiner cellRefiner;
8515     PetscBool   localized;
8516 
8517     ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
8518     ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr);
8519     ierr = DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
8520     ierr = DMCopyBoundary(dm, *dmRefined);CHKERRQ(ierr);
8521     if (localized) {ierr = DMLocalizeCoordinates(*dmRefined);CHKERRQ(ierr);}
8522   } else {
8523     ierr = DMPlexRefine_Internal(dm, NULL, dmRefined);CHKERRQ(ierr);
8524   }
8525   PetscFunctionReturn(0);
8526 }
8527 
8528 PetscErrorCode DMRefineHierarchy_Plex(DM dm, PetscInt nlevels, DM dmRefined[])
8529 {
8530   DM             cdm = dm;
8531   PetscInt       r;
8532   PetscBool      isUniform, localized;
8533   PetscErrorCode ierr;
8534 
8535   PetscFunctionBegin;
8536   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
8537   ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
8538   if (isUniform) {
8539     for (r = 0; r < nlevels; ++r) {
8540       CellRefiner cellRefiner;
8541 
8542       ierr = DMPlexGetCellRefiner_Internal(cdm, &cellRefiner);CHKERRQ(ierr);
8543       ierr = DMPlexRefineUniform_Internal(cdm, cellRefiner, &dmRefined[r]);CHKERRQ(ierr);
8544       ierr = DMCopyBoundary(cdm, dmRefined[r]);CHKERRQ(ierr);
8545       if (localized) {ierr = DMLocalizeCoordinates(dmRefined[r]);CHKERRQ(ierr);}
8546       ierr = DMSetCoarseDM(dmRefined[r], cdm);CHKERRQ(ierr);
8547       ierr = DMPlexSetRegularRefinement(dmRefined[r], PETSC_TRUE);CHKERRQ(ierr);
8548       cdm  = dmRefined[r];
8549     }
8550   } else {
8551     for (r = 0; r < nlevels; ++r) {
8552       ierr = DMRefine(cdm, PetscObjectComm((PetscObject) dm), &dmRefined[r]);CHKERRQ(ierr);
8553       ierr = DMCopyBoundary(cdm, dmRefined[r]);CHKERRQ(ierr);
8554       if (localized) {ierr = DMLocalizeCoordinates(dmRefined[r]);CHKERRQ(ierr);}
8555       ierr = DMSetCoarseDM(dmRefined[r], cdm);CHKERRQ(ierr);
8556       cdm  = dmRefined[r];
8557     }
8558   }
8559   PetscFunctionReturn(0);
8560 }
8561