xref: /petsc/src/dm/impls/plex/plexrefine.c (revision efd4aadf157bf1ba2d80c2be092fcf4247860003)
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] = 0;
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] = -2;
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] = 0;
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] = -2;
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         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
1919         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
1920         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1921 #if 1
1922         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1923         for (p = 0; p < 2; ++p) {
1924           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);
1925         }
1926 #endif
1927         supportNew[0] = (c - cStart)*4 + r;
1928         supportNew[1] = (c - cStart)*4 + (r+1)%4;
1929         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1930 #if 1
1931         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1932         for (p = 0; p < 2; ++p) {
1933           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);
1934         }
1935 #endif
1936       }
1937     }
1938     /* Old vertices have identical supports */
1939     for (v = vStart; v < vEnd; ++v) {
1940       const PetscInt  newp = vStartNew + (v - vStart);
1941       const PetscInt *support, *cone;
1942       PetscInt        size, s;
1943 
1944       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1945       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1946       for (s = 0; s < size; ++s) {
1947         PetscInt r = 0;
1948 
1949         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1950         if (cone[1] == v) r = 1;
1951         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1952       }
1953       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1954 #if 1
1955       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1956       for (p = 0; p < size; ++p) {
1957         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);
1958       }
1959 #endif
1960     }
1961     /* Face vertices have 2 + cells supports */
1962     for (f = fStart; f < fEnd; ++f) {
1963       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1964       const PetscInt *cone, *support;
1965       PetscInt        size, s;
1966 
1967       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1968       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1969       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1970       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1971       for (s = 0; s < size; ++s) {
1972         PetscInt r = 0;
1973 
1974         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1975         if      (cone[1] == f) r = 1;
1976         else if (cone[2] == f) r = 2;
1977         else if (cone[3] == f) r = 3;
1978         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
1979       }
1980       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1981 #if 1
1982       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1983       for (p = 0; p < 2+size; ++p) {
1984         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);
1985       }
1986 #endif
1987     }
1988     /* Cell vertices have 4 supports */
1989     for (c = cStart; c < cEnd; ++c) {
1990       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
1991       PetscInt       supportNew[4];
1992 
1993       for (r = 0; r < 4; ++r) {
1994         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
1995       }
1996       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1997     }
1998     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1999     break;
2000   case REFINER_HYBRID_SIMPLEX_2D:
2001     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
2002     cMax = PetscMin(cEnd, cMax);
2003     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
2004     fMax = PetscMin(fEnd, fMax);
2005     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);CHKERRQ(ierr);
2006     /* Interior cells have 3 faces */
2007     for (c = cStart; c < cMax; ++c) {
2008       const PetscInt  newp = cStartNew + (c - cStart)*4;
2009       const PetscInt *cone, *ornt;
2010       PetscInt        coneNew[3], orntNew[3];
2011 
2012       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2013       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2014       /* A triangle */
2015       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2016       orntNew[0] = ornt[0];
2017       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
2018       orntNew[1] = -2;
2019       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2020       orntNew[2] = ornt[2];
2021       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2022       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2023 #if 1
2024       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);
2025       for (p = 0; p < 3; ++p) {
2026         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);
2027       }
2028 #endif
2029       /* B triangle */
2030       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2031       orntNew[0] = ornt[0];
2032       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2033       orntNew[1] = ornt[1];
2034       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
2035       orntNew[2] = -2;
2036       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2037       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2038 #if 1
2039       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);
2040       for (p = 0; p < 3; ++p) {
2041         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);
2042       }
2043 #endif
2044       /* C triangle */
2045       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
2046       orntNew[0] = -2;
2047       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2048       orntNew[1] = ornt[1];
2049       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2050       orntNew[2] = ornt[2];
2051       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2052       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2053 #if 1
2054       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);
2055       for (p = 0; p < 3; ++p) {
2056         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);
2057       }
2058 #endif
2059       /* D triangle */
2060       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
2061       orntNew[0] = 0;
2062       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
2063       orntNew[1] = 0;
2064       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
2065       orntNew[2] = 0;
2066       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2067       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2068 #if 1
2069       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);
2070       for (p = 0; p < 3; ++p) {
2071         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);
2072       }
2073 #endif
2074     }
2075     /*
2076      2----3----3
2077      |         |
2078      |    B    |
2079      |         |
2080      0----4--- 1
2081      |         |
2082      |    A    |
2083      |         |
2084      0----2----1
2085      */
2086     /* Hybrid cells have 4 faces */
2087     for (c = cMax; c < cEnd; ++c) {
2088       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
2089       const PetscInt *cone, *ornt;
2090       PetscInt        coneNew[4], orntNew[4], r;
2091 
2092       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2093       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2094       r    = (ornt[0] < 0 ? 1 : 0);
2095       /* A quad */
2096       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + r;
2097       orntNew[0]   = ornt[0];
2098       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + r;
2099       orntNew[1]   = ornt[1];
2100       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2+r] - fMax);
2101       orntNew[2+r] = 0;
2102       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
2103       orntNew[3-r] = 0;
2104       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2105       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2106 #if 1
2107       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);
2108       for (p = 0; p < 4; ++p) {
2109         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);
2110       }
2111 #endif
2112       /* B quad */
2113       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + 1-r;
2114       orntNew[0]   = ornt[0];
2115       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + 1-r;
2116       orntNew[1]   = ornt[1];
2117       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
2118       orntNew[2+r] = 0;
2119       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3-r] - fMax);
2120       orntNew[3-r] = 0;
2121       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2122       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2123 #if 1
2124       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);
2125       for (p = 0; p < 4; ++p) {
2126         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);
2127       }
2128 #endif
2129     }
2130     /* Interior split faces have 2 vertices and the same cells as the parent */
2131     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2132     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2133     for (f = fStart; f < fMax; ++f) {
2134       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
2135 
2136       for (r = 0; r < 2; ++r) {
2137         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2138         const PetscInt *cone, *ornt, *support;
2139         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2140 
2141         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2142         coneNew[0]       = vStartNew + (cone[0] - vStart);
2143         coneNew[1]       = vStartNew + (cone[1] - vStart);
2144         coneNew[(r+1)%2] = newv;
2145         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2146 #if 1
2147         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2148         for (p = 0; p < 2; ++p) {
2149           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);
2150         }
2151 #endif
2152         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2153         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2154         for (s = 0; s < supportSize; ++s) {
2155           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2156           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2157           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2158           for (c = 0; c < coneSize; ++c) if (cone[c] == f) break;
2159           if (support[s] >= cMax) {
2160             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[c] < 0 ? 1-r : r);
2161           } else {
2162             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
2163           }
2164         }
2165         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2166 #if 1
2167         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2168         for (p = 0; p < supportSize; ++p) {
2169           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);
2170         }
2171 #endif
2172       }
2173     }
2174     /* Interior cell faces have 2 vertices and 2 cells */
2175     for (c = cStart; c < cMax; ++c) {
2176       const PetscInt *cone;
2177 
2178       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2179       for (r = 0; r < 3; ++r) {
2180         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
2181         PetscInt       coneNew[2];
2182         PetscInt       supportNew[2];
2183 
2184         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
2185         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
2186         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2187 #if 1
2188         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2189         for (p = 0; p < 2; ++p) {
2190           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);
2191         }
2192 #endif
2193         supportNew[0] = (c - cStart)*4 + (r+1)%3;
2194         supportNew[1] = (c - cStart)*4 + 3;
2195         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2196 #if 1
2197         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2198         for (p = 0; p < 2; ++p) {
2199           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);
2200         }
2201 #endif
2202       }
2203     }
2204     /* Interior hybrid faces have 2 vertices and the same cells */
2205     for (f = fMax; f < fEnd; ++f) {
2206       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
2207       const PetscInt *cone, *ornt;
2208       const PetscInt *support;
2209       PetscInt        coneNew[2];
2210       PetscInt        supportNew[2];
2211       PetscInt        size, s, r;
2212 
2213       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2214       coneNew[0] = vStartNew + (cone[0] - vStart);
2215       coneNew[1] = vStartNew + (cone[1] - vStart);
2216       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2217 #if 1
2218       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2219       for (p = 0; p < 2; ++p) {
2220         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);
2221       }
2222 #endif
2223       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2224       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2225       for (s = 0; s < size; ++s) {
2226         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2227         ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2228         for (r = 0; r < 2; ++r) {
2229           if (cone[r+2] == f) break;
2230         }
2231         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[0] < 0 ? 1-r : r);
2232       }
2233       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2234 #if 1
2235       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2236       for (p = 0; p < size; ++p) {
2237         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);
2238       }
2239 #endif
2240     }
2241     /* Cell hybrid faces have 2 vertices and 2 cells */
2242     for (c = cMax; c < cEnd; ++c) {
2243       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
2244       const PetscInt *cone;
2245       PetscInt        coneNew[2];
2246       PetscInt        supportNew[2];
2247 
2248       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2249       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
2250       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
2251       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2252 #if 1
2253       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2254       for (p = 0; p < 2; ++p) {
2255         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);
2256       }
2257 #endif
2258       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
2259       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
2260       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2261 #if 1
2262       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2263       for (p = 0; p < 2; ++p) {
2264         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);
2265       }
2266 #endif
2267     }
2268     /* Old vertices have identical supports */
2269     for (v = vStart; v < vEnd; ++v) {
2270       const PetscInt  newp = vStartNew + (v - vStart);
2271       const PetscInt *support, *cone;
2272       PetscInt        size, s;
2273 
2274       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2275       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2276       for (s = 0; s < size; ++s) {
2277         if (support[s] >= fMax) {
2278           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
2279         } else {
2280           PetscInt r = 0;
2281 
2282           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2283           if (cone[1] == v) r = 1;
2284           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2285         }
2286       }
2287       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2288 #if 1
2289       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2290       for (p = 0; p < size; ++p) {
2291         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);
2292       }
2293 #endif
2294     }
2295     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
2296     for (f = fStart; f < fMax; ++f) {
2297       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2298       const PetscInt *cone, *support;
2299       PetscInt        size, newSize = 2, s;
2300 
2301       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2302       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2303       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2304       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2305       for (s = 0; s < size; ++s) {
2306         PetscInt r = 0;
2307 
2308         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2309         if (support[s] >= cMax) {
2310           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
2311 
2312           newSize += 1;
2313         } else {
2314           if      (cone[1] == f) r = 1;
2315           else if (cone[2] == f) r = 2;
2316           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
2317           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
2318 
2319           newSize += 2;
2320         }
2321       }
2322       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2323 #if 1
2324       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2325       for (p = 0; p < newSize; ++p) {
2326         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);
2327       }
2328 #endif
2329     }
2330     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2331     break;
2332   case REFINER_HYBRID_HEX_2D:
2333     /* Hybrid Hex 2D */
2334     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
2335     cMax = PetscMin(cEnd, cMax);
2336     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
2337     fMax = PetscMin(fEnd, fMax);
2338     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);CHKERRQ(ierr);
2339     /* Interior cells have 4 faces */
2340     for (c = cStart; c < cMax; ++c) {
2341       const PetscInt  newp = cStartNew + (c - cStart)*4;
2342       const PetscInt *cone, *ornt;
2343       PetscInt        coneNew[4], orntNew[4];
2344 
2345       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2346       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2347       /* A quad */
2348       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2349       orntNew[0] = ornt[0];
2350       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
2351       orntNew[1] = 0;
2352       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
2353       orntNew[2] = -2;
2354       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
2355       orntNew[3] = ornt[3];
2356       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2357       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2358 #if 1
2359       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);
2360       for (p = 0; p < 4; ++p) {
2361         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);
2362       }
2363 #endif
2364       /* B quad */
2365       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2366       orntNew[0] = ornt[0];
2367       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2368       orntNew[1] = ornt[1];
2369       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
2370       orntNew[2] = 0;
2371       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
2372       orntNew[3] = -2;
2373       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2374       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2375 #if 1
2376       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);
2377       for (p = 0; p < 4; ++p) {
2378         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);
2379       }
2380 #endif
2381       /* C quad */
2382       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
2383       orntNew[0] = -2;
2384       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2385       orntNew[1] = ornt[1];
2386       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2387       orntNew[2] = ornt[2];
2388       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
2389       orntNew[3] = 0;
2390       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2391       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2392 #if 1
2393       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);
2394       for (p = 0; p < 4; ++p) {
2395         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);
2396       }
2397 #endif
2398       /* D quad */
2399       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
2400       orntNew[0] = 0;
2401       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
2402       orntNew[1] = -2;
2403       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2404       orntNew[2] = ornt[2];
2405       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
2406       orntNew[3] = ornt[3];
2407       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2408       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2409 #if 1
2410       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);
2411       for (p = 0; p < 4; ++p) {
2412         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);
2413       }
2414 #endif
2415     }
2416     /*
2417      2----3----3
2418      |         |
2419      |    B    |
2420      |         |
2421      0----4--- 1
2422      |         |
2423      |    A    |
2424      |         |
2425      0----2----1
2426      */
2427     /* Hybrid cells have 4 faces */
2428     for (c = cMax; c < cEnd; ++c) {
2429       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
2430       const PetscInt *cone, *ornt;
2431       PetscInt        coneNew[4], orntNew[4];
2432 
2433       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2434       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2435       /* A quad */
2436       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2437       orntNew[0] = ornt[0];
2438       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2439       orntNew[1] = ornt[1];
2440       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[2] - fMax);
2441       orntNew[2] = 0;
2442       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
2443       orntNew[3] = 0;
2444       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2445       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2446 #if 1
2447       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);
2448       for (p = 0; p < 4; ++p) {
2449         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);
2450       }
2451 #endif
2452       /* B quad */
2453       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2454       orntNew[0] = ornt[0];
2455       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2456       orntNew[1] = ornt[1];
2457       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
2458       orntNew[2] = 0;
2459       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[3] - fMax);
2460       orntNew[3] = 0;
2461       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2462       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2463 #if 1
2464       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);
2465       for (p = 0; p < 4; ++p) {
2466         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);
2467       }
2468 #endif
2469     }
2470     /* Interior split faces have 2 vertices and the same cells as the parent */
2471     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2472     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2473     for (f = fStart; f < fMax; ++f) {
2474       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
2475 
2476       for (r = 0; r < 2; ++r) {
2477         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2478         const PetscInt *cone, *ornt, *support;
2479         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2480 
2481         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2482         coneNew[0]       = vStartNew + (cone[0] - vStart);
2483         coneNew[1]       = vStartNew + (cone[1] - vStart);
2484         coneNew[(r+1)%2] = newv;
2485         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2486 #if 1
2487         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2488         for (p = 0; p < 2; ++p) {
2489           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);
2490         }
2491 #endif
2492         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2493         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2494         for (s = 0; s < supportSize; ++s) {
2495           if (support[s] >= cMax) {
2496             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
2497           } else {
2498             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2499             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2500             ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2501             for (c = 0; c < coneSize; ++c) {
2502               if (cone[c] == f) break;
2503             }
2504             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
2505           }
2506         }
2507         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2508 #if 1
2509         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2510         for (p = 0; p < supportSize; ++p) {
2511           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);
2512         }
2513 #endif
2514       }
2515     }
2516     /* Interior cell faces have 2 vertices and 2 cells */
2517     for (c = cStart; c < cMax; ++c) {
2518       const PetscInt *cone;
2519 
2520       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2521       for (r = 0; r < 4; ++r) {
2522         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
2523         PetscInt       coneNew[2], supportNew[2];
2524 
2525         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2526         coneNew[1] = vStartNew + (vEnd - vStart) + (fMax    - fStart) + (c - cStart);
2527         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2528 #if 1
2529         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2530         for (p = 0; p < 2; ++p) {
2531           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);
2532         }
2533 #endif
2534         supportNew[0] = (c - cStart)*4 + r;
2535         supportNew[1] = (c - cStart)*4 + (r+1)%4;
2536         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2537 #if 1
2538         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2539         for (p = 0; p < 2; ++p) {
2540           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);
2541         }
2542 #endif
2543       }
2544     }
2545     /* Hybrid faces have 2 vertices and the same cells */
2546     for (f = fMax; f < fEnd; ++f) {
2547       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
2548       const PetscInt *cone, *support;
2549       PetscInt        coneNew[2], supportNew[2];
2550       PetscInt        size, s, r;
2551 
2552       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2553       coneNew[0] = vStartNew + (cone[0] - vStart);
2554       coneNew[1] = vStartNew + (cone[1] - vStart);
2555       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2556 #if 1
2557       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2558       for (p = 0; p < 2; ++p) {
2559         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);
2560       }
2561 #endif
2562       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2563       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2564       for (s = 0; s < size; ++s) {
2565         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2566         for (r = 0; r < 2; ++r) {
2567           if (cone[r+2] == f) break;
2568         }
2569         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
2570       }
2571       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2572 #if 1
2573       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2574       for (p = 0; p < size; ++p) {
2575         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);
2576       }
2577 #endif
2578     }
2579     /* Cell hybrid faces have 2 vertices and 2 cells */
2580     for (c = cMax; c < cEnd; ++c) {
2581       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
2582       const PetscInt *cone;
2583       PetscInt        coneNew[2], supportNew[2];
2584 
2585       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2586       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
2587       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
2588       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2589 #if 1
2590       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2591       for (p = 0; p < 2; ++p) {
2592         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);
2593       }
2594 #endif
2595       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
2596       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
2597       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2598 #if 1
2599       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2600       for (p = 0; p < 2; ++p) {
2601         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);
2602       }
2603 #endif
2604     }
2605     /* Old vertices have identical supports */
2606     for (v = vStart; v < vEnd; ++v) {
2607       const PetscInt  newp = vStartNew + (v - vStart);
2608       const PetscInt *support, *cone;
2609       PetscInt        size, s;
2610 
2611       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2612       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2613       for (s = 0; s < size; ++s) {
2614         if (support[s] >= fMax) {
2615           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (support[s] - fMax);
2616         } else {
2617           PetscInt r = 0;
2618 
2619           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2620           if (cone[1] == v) r = 1;
2621           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2622         }
2623       }
2624       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2625 #if 1
2626       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2627       for (p = 0; p < size; ++p) {
2628         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);
2629       }
2630 #endif
2631     }
2632     /* Face vertices have 2 + cells supports */
2633     for (f = fStart; f < fMax; ++f) {
2634       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2635       const PetscInt *cone, *support;
2636       PetscInt        size, s;
2637 
2638       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2639       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2640       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2641       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2642       for (s = 0; s < size; ++s) {
2643         PetscInt r = 0;
2644 
2645         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2646         if (support[s] >= cMax) {
2647           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (support[s] - cMax);
2648         } else {
2649           if      (cone[1] == f) r = 1;
2650           else if (cone[2] == f) r = 2;
2651           else if (cone[3] == f) r = 3;
2652           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*4 + r;
2653         }
2654       }
2655       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2656 #if 1
2657       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2658       for (p = 0; p < 2+size; ++p) {
2659         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);
2660       }
2661 #endif
2662     }
2663     /* Cell vertices have 4 supports */
2664     for (c = cStart; c < cMax; ++c) {
2665       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
2666       PetscInt       supportNew[4];
2667 
2668       for (r = 0; r < 4; ++r) {
2669         supportNew[r] = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
2670       }
2671       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2672     }
2673     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2674     break;
2675   case REFINER_SIMPLEX_3D:
2676     /* All cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
2677     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
2678     for (c = cStart; c < cEnd; ++c) {
2679       const PetscInt  newp = cStartNew + (c - cStart)*8;
2680       const PetscInt *cone, *ornt;
2681       PetscInt        coneNew[4], orntNew[4];
2682 
2683       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2684       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2685       /* A tetrahedron: {0, a, c, d} */
2686       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
2687       orntNew[0] = ornt[0];
2688       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
2689       orntNew[1] = ornt[1];
2690       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
2691       orntNew[2] = ornt[2];
2692       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
2693       orntNew[3] = 0;
2694       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2695       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2696 #if 1
2697       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);
2698       for (p = 0; p < 4; ++p) {
2699         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);
2700       }
2701 #endif
2702       /* B tetrahedron: {a, 1, b, e} */
2703       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
2704       orntNew[0] = ornt[0];
2705       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
2706       orntNew[1] = ornt[1];
2707       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
2708       orntNew[2] = 0;
2709       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
2710       orntNew[3] = ornt[3];
2711       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2712       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2713 #if 1
2714       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);
2715       for (p = 0; p < 4; ++p) {
2716         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);
2717       }
2718 #endif
2719       /* C tetrahedron: {c, b, 2, f} */
2720       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
2721       orntNew[0] = ornt[0];
2722       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
2723       orntNew[1] = 0;
2724       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
2725       orntNew[2] = ornt[2];
2726       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
2727       orntNew[3] = ornt[3];
2728       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2729       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2730 #if 1
2731       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);
2732       for (p = 0; p < 4; ++p) {
2733         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);
2734       }
2735 #endif
2736       /* D tetrahedron: {d, e, f, 3} */
2737       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
2738       orntNew[0] = 0;
2739       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
2740       orntNew[1] = ornt[1];
2741       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
2742       orntNew[2] = ornt[2];
2743       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
2744       orntNew[3] = ornt[3];
2745       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2746       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2747 #if 1
2748       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);
2749       for (p = 0; p < 4; ++p) {
2750         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);
2751       }
2752 #endif
2753       /* A' tetrahedron: {c, d, a, f} */
2754       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
2755       orntNew[0] = -3;
2756       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
2757       orntNew[1] = ornt[2] < 0 ? -(GetTriMidEdge_Static(ornt[2], 0)+1) : GetTriMidEdge_Static(ornt[2], 0);
2758       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
2759       orntNew[2] = 0;
2760       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
2761       orntNew[3] = 2;
2762       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
2763       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
2764 #if 1
2765       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);
2766       for (p = 0; p < 4; ++p) {
2767         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2768       }
2769 #endif
2770       /* B' tetrahedron: {e, b, a, f} */
2771       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
2772       orntNew[0] = -2;
2773       coneNew[1] = fStartNew + (cone[3] - fStart)*4 + 3;
2774       orntNew[1] = ornt[3] < 0 ? -(GetTriMidEdge_Static(ornt[3], 1)+1) : GetTriMidEdge_Static(ornt[3], 1);
2775       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
2776       orntNew[2] = 0;
2777       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
2778       orntNew[3] = 0;
2779       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
2780       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
2781 #if 1
2782       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);
2783       for (p = 0; p < 4; ++p) {
2784         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2785       }
2786 #endif
2787       /* C' tetrahedron: {f, a, c, b} */
2788       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
2789       orntNew[0] = -2;
2790       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
2791       orntNew[1] = -2;
2792       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
2793       orntNew[2] = -1;
2794       coneNew[3] = fStartNew + (cone[0] - fStart)*4 + 3;
2795       orntNew[3] = ornt[0] < 0 ? -(GetTriMidEdge_Static(ornt[0], 2)+1) : GetTriMidEdge_Static(ornt[0], 2);
2796       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
2797       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
2798 #if 1
2799       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);
2800       for (p = 0; p < 4; ++p) {
2801         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2802       }
2803 #endif
2804       /* D' tetrahedron: {f, a, e, d} */
2805       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
2806       orntNew[0] = -2;
2807       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
2808       orntNew[1] = -1;
2809       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
2810       orntNew[2] = -2;
2811       coneNew[3] = fStartNew + (cone[1] - fStart)*4 + 3;
2812       orntNew[3] = ornt[1] < 0 ? -(GetTriMidEdge_Static(ornt[1], 1)+1) : GetTriMidEdge_Static(ornt[1], 1);
2813       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
2814       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
2815 #if 1
2816       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);
2817       for (p = 0; p < 4; ++p) {
2818         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2819       }
2820 #endif
2821     }
2822     /* Split faces have 3 edges and the same cells as the parent */
2823     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2824     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2825     for (f = fStart; f < fEnd; ++f) {
2826       const PetscInt  newp = fStartNew + (f - fStart)*4;
2827       const PetscInt *cone, *ornt, *support;
2828       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
2829 
2830       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2831       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
2832       /* A triangle */
2833       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
2834       orntNew[0] = ornt[0];
2835       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
2836       orntNew[1] = -2;
2837       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
2838       orntNew[2] = ornt[2];
2839       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2840       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2841 #if 1
2842       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);
2843       for (p = 0; p < 3; ++p) {
2844         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);
2845       }
2846 #endif
2847       /* B triangle */
2848       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
2849       orntNew[0] = ornt[0];
2850       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
2851       orntNew[1] = ornt[1];
2852       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
2853       orntNew[2] = -2;
2854       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2855       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2856 #if 1
2857       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);
2858       for (p = 0; p < 3; ++p) {
2859         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);
2860       }
2861 #endif
2862       /* C triangle */
2863       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
2864       orntNew[0] = -2;
2865       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
2866       orntNew[1] = ornt[1];
2867       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
2868       orntNew[2] = ornt[2];
2869       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2870       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2871 #if 1
2872       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);
2873       for (p = 0; p < 3; ++p) {
2874         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);
2875       }
2876 #endif
2877       /* D triangle */
2878       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
2879       orntNew[0] = 0;
2880       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
2881       orntNew[1] = 0;
2882       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
2883       orntNew[2] = 0;
2884       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2885       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2886 #if 1
2887       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);
2888       for (p = 0; p < 3; ++p) {
2889         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);
2890       }
2891 #endif
2892       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2893       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2894       for (r = 0; r < 4; ++r) {
2895         for (s = 0; s < supportSize; ++s) {
2896           PetscInt subf;
2897           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2898           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2899           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2900           for (c = 0; c < coneSize; ++c) {
2901             if (cone[c] == f) break;
2902           }
2903           subf = GetTriSubfaceInverse_Static(ornt[c], r);
2904           supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
2905         }
2906         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
2907 #if 1
2908         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);
2909         for (p = 0; p < supportSize; ++p) {
2910           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);
2911         }
2912 #endif
2913       }
2914     }
2915     /* Interior faces have 3 edges and 2 cells */
2916     for (c = cStart; c < cEnd; ++c) {
2917       PetscInt        newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8;
2918       const PetscInt *cone, *ornt;
2919       PetscInt        coneNew[3], orntNew[3];
2920       PetscInt        supportNew[2];
2921 
2922       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2923       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2924       /* Face A: {c, a, d} */
2925       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
2926       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2927       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
2928       orntNew[1] = ornt[1] < 0 ? -2 : 0;
2929       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 2);
2930       orntNew[2] = ornt[2] < 0 ? -2 : 0;
2931       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2932       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2933 #if 1
2934       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2935       for (p = 0; p < 3; ++p) {
2936         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);
2937       }
2938 #endif
2939       supportNew[0] = (c - cStart)*8 + 0;
2940       supportNew[1] = (c - cStart)*8 + 0+4;
2941       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2942 #if 1
2943       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2944       for (p = 0; p < 2; ++p) {
2945         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);
2946       }
2947 #endif
2948       ++newp;
2949       /* Face B: {a, b, e} */
2950       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
2951       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2952       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 0);
2953       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2954       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
2955       orntNew[2] = ornt[1] < 0 ? -2 : 0;
2956       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2957       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2958 #if 1
2959       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2960       for (p = 0; p < 3; ++p) {
2961         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);
2962       }
2963 #endif
2964       supportNew[0] = (c - cStart)*8 + 1;
2965       supportNew[1] = (c - cStart)*8 + 1+4;
2966       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2967 #if 1
2968       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2969       for (p = 0; p < 2; ++p) {
2970         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);
2971       }
2972 #endif
2973       ++newp;
2974       /* Face C: {c, f, b} */
2975       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
2976       orntNew[0] = ornt[2] < 0 ? -2 : 0;
2977       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
2978       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2979       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 1);
2980       orntNew[2] = ornt[0] < 0 ? -2 : 0;
2981       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2982       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2983 #if 1
2984       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2985       for (p = 0; p < 3; ++p) {
2986         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);
2987       }
2988 #endif
2989       supportNew[0] = (c - cStart)*8 + 2;
2990       supportNew[1] = (c - cStart)*8 + 2+4;
2991       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2992 #if 1
2993       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2994       for (p = 0; p < 2; ++p) {
2995         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);
2996       }
2997 #endif
2998       ++newp;
2999       /* Face D: {d, e, f} */
3000       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 0);
3001       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3002       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3003       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3004       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3005       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3006       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3007       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3008 #if 1
3009       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3010       for (p = 0; p < 3; ++p) {
3011         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);
3012       }
3013 #endif
3014       supportNew[0] = (c - cStart)*8 + 3;
3015       supportNew[1] = (c - cStart)*8 + 3+4;
3016       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3017 #if 1
3018       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3019       for (p = 0; p < 2; ++p) {
3020         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);
3021       }
3022 #endif
3023       ++newp;
3024       /* Face E: {d, f, a} */
3025       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3026       orntNew[0] = ornt[2] < 0 ? 0 : -2;
3027       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3028       orntNew[1] = -2;
3029       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3030       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3031       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3032       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3033 #if 1
3034       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3035       for (p = 0; p < 3; ++p) {
3036         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);
3037       }
3038 #endif
3039       supportNew[0] = (c - cStart)*8 + 0+4;
3040       supportNew[1] = (c - cStart)*8 + 3+4;
3041       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3042 #if 1
3043       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3044       for (p = 0; p < 2; ++p) {
3045         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);
3046       }
3047 #endif
3048       ++newp;
3049       /* Face F: {c, a, f} */
3050       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3051       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3052       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3053       orntNew[1] = 0;
3054       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3055       orntNew[2] = ornt[2] < 0 ? 0 : -2;
3056       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3057       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3058 #if 1
3059       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3060       for (p = 0; p < 3; ++p) {
3061         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);
3062       }
3063 #endif
3064       supportNew[0] = (c - cStart)*8 + 0+4;
3065       supportNew[1] = (c - cStart)*8 + 2+4;
3066       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3067 #if 1
3068       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3069       for (p = 0; p < 2; ++p) {
3070         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);
3071       }
3072 #endif
3073       ++newp;
3074       /* Face G: {e, a, f} */
3075       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3076       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3077       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3078       orntNew[1] = 0;
3079       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3080       orntNew[2] = ornt[3] < 0 ? 0 : -2;
3081       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3082       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3083 #if 1
3084       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3085       for (p = 0; p < 3; ++p) {
3086         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);
3087       }
3088 #endif
3089       supportNew[0] = (c - cStart)*8 + 1+4;
3090       supportNew[1] = (c - cStart)*8 + 3+4;
3091       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3092 #if 1
3093       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3094       for (p = 0; p < 2; ++p) {
3095         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);
3096       }
3097 #endif
3098       ++newp;
3099       /* Face H: {a, b, f} */
3100       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3101       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3102       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3103       orntNew[1] = ornt[3] < 0 ? 0 : -2;
3104       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3105       orntNew[2] = -2;
3106       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3107       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3108 #if 1
3109       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3110       for (p = 0; p < 3; ++p) {
3111         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);
3112       }
3113 #endif
3114       supportNew[0] = (c - cStart)*8 + 1+4;
3115       supportNew[1] = (c - cStart)*8 + 2+4;
3116       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3117 #if 1
3118       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3119       for (p = 0; p < 2; ++p) {
3120         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);
3121       }
3122 #endif
3123       ++newp;
3124     }
3125     /* Split Edges have 2 vertices and the same faces as the parent */
3126     for (e = eStart; e < eEnd; ++e) {
3127       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
3128 
3129       for (r = 0; r < 2; ++r) {
3130         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
3131         const PetscInt *cone, *ornt, *support;
3132         PetscInt        coneNew[2], coneSize, c, supportSize, s;
3133 
3134         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3135         coneNew[0]       = vStartNew + (cone[0] - vStart);
3136         coneNew[1]       = vStartNew + (cone[1] - vStart);
3137         coneNew[(r+1)%2] = newv;
3138         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3139 #if 1
3140         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3141         for (p = 0; p < 2; ++p) {
3142           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);
3143         }
3144 #endif
3145         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
3146         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3147         for (s = 0; s < supportSize; ++s) {
3148           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3149           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3150           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3151           for (c = 0; c < coneSize; ++c) {
3152             if (cone[c] == e) break;
3153           }
3154           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
3155         }
3156         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3157 #if 1
3158         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3159         for (p = 0; p < supportSize; ++p) {
3160           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);
3161         }
3162 #endif
3163       }
3164     }
3165     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
3166     for (f = fStart; f < fEnd; ++f) {
3167       const PetscInt *cone, *ornt, *support;
3168       PetscInt        coneSize, supportSize, s;
3169 
3170       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3171       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3172       for (r = 0; r < 3; ++r) {
3173         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
3174         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
3175         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
3176                                     -1, -1,  1,  6,  0,  4,
3177                                      2,  5,  3,  4, -1, -1,
3178                                     -1, -1,  3,  6,  2,  7};
3179 
3180         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3181         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
3182         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
3183         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3184 #if 1
3185         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3186         for (p = 0; p < 2; ++p) {
3187           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);
3188         }
3189 #endif
3190         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
3191         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
3192         for (s = 0; s < supportSize; ++s) {
3193           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3194           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3195           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3196           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
3197           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
3198           er = GetTriMidEdgeInverse_Static(ornt[c], r);
3199           if (er == eint[c]) {
3200             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
3201           } else {
3202             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
3203             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
3204           }
3205         }
3206         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3207 #if 1
3208         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3209         for (p = 0; p < intFaces; ++p) {
3210           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);
3211         }
3212 #endif
3213       }
3214     }
3215     /* Interior edges have 2 vertices and 4 faces */
3216     for (c = cStart; c < cEnd; ++c) {
3217       const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3218       const PetscInt *cone, *ornt, *fcone;
3219       PetscInt        coneNew[2], supportNew[4], find;
3220 
3221       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3222       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3223       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
3224       find = GetTriEdge_Static(ornt[0], 0);
3225       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3226       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
3227       find = GetTriEdge_Static(ornt[2], 1);
3228       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3229       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3230 #if 1
3231       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3232       for (p = 0; p < 2; ++p) {
3233         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);
3234       }
3235 #endif
3236       supportNew[0] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 4;
3237       supportNew[1] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 5;
3238       supportNew[2] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 6;
3239       supportNew[3] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 7;
3240       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3241 #if 1
3242       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3243       for (p = 0; p < 4; ++p) {
3244         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);
3245       }
3246 #endif
3247     }
3248     /* Old vertices have identical supports */
3249     for (v = vStart; v < vEnd; ++v) {
3250       const PetscInt  newp = vStartNew + (v - vStart);
3251       const PetscInt *support, *cone;
3252       PetscInt        size, s;
3253 
3254       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
3255       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
3256       for (s = 0; s < size; ++s) {
3257         PetscInt r = 0;
3258 
3259         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3260         if (cone[1] == v) r = 1;
3261         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
3262       }
3263       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3264 #if 1
3265       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3266       for (p = 0; p < size; ++p) {
3267         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);
3268       }
3269 #endif
3270     }
3271     /* Edge vertices have 2 + face*2 + 0/1 supports */
3272     for (e = eStart; e < eEnd; ++e) {
3273       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
3274       const PetscInt *cone, *support;
3275       PetscInt       *star = NULL, starSize, cellSize = 0, coneSize, size, s;
3276 
3277       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
3278       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3279       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
3280       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
3281       for (s = 0; s < size; ++s) {
3282         PetscInt r = 0;
3283 
3284         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3285         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3286         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
3287         supportRef[2+s*2+0] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
3288         supportRef[2+s*2+1] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
3289       }
3290       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
3291       for (s = 0; s < starSize*2; s += 2) {
3292         const PetscInt *cone, *ornt;
3293         PetscInt        e01, e23;
3294 
3295         if ((star[s] >= cStart) && (star[s] < cEnd)) {
3296           /* Check edge 0-1 */
3297           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
3298           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
3299           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
3300           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
3301           /* Check edge 2-3 */
3302           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
3303           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
3304           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
3305           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
3306           if ((e01 == e) || (e23 == e)) {supportRef[2+size*2+cellSize++] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (star[s] - cStart);}
3307         }
3308       }
3309       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
3310       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3311 #if 1
3312       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3313       for (p = 0; p < 2+size*2+cellSize; ++p) {
3314         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);
3315       }
3316 #endif
3317     }
3318     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3319     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
3320     break;
3321   case REFINER_HYBRID_SIMPLEX_3D:
3322     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
3323     /* Interior cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
3324     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
3325     for (c = cStart; c < cMax; ++c) {
3326       const PetscInt  newp = cStartNew + (c - cStart)*8;
3327       const PetscInt *cone, *ornt;
3328       PetscInt        coneNew[4], orntNew[4];
3329 
3330       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3331       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3332       /* A tetrahedron: {0, a, c, d} */
3333       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
3334       orntNew[0] = ornt[0];
3335       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
3336       orntNew[1] = ornt[1];
3337       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
3338       orntNew[2] = ornt[2];
3339       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
3340       orntNew[3] = 0;
3341       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3342       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3343 #if 1
3344       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);
3345       for (p = 0; p < 4; ++p) {
3346         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);
3347       }
3348 #endif
3349       /* B tetrahedron: {a, 1, b, e} */
3350       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
3351       orntNew[0] = ornt[0];
3352       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
3353       orntNew[1] = ornt[1];
3354       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
3355       orntNew[2] = 0;
3356       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
3357       orntNew[3] = ornt[3];
3358       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3359       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3360 #if 1
3361       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);
3362       for (p = 0; p < 4; ++p) {
3363         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);
3364       }
3365 #endif
3366       /* C tetrahedron: {c, b, 2, f} */
3367       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
3368       orntNew[0] = ornt[0];
3369       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
3370       orntNew[1] = 0;
3371       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
3372       orntNew[2] = ornt[2];
3373       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
3374       orntNew[3] = ornt[3];
3375       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3376       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3377 #if 1
3378       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);
3379       for (p = 0; p < 4; ++p) {
3380         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);
3381       }
3382 #endif
3383       /* D tetrahedron: {d, e, f, 3} */
3384       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
3385       orntNew[0] = 0;
3386       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
3387       orntNew[1] = ornt[1];
3388       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
3389       orntNew[2] = ornt[2];
3390       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
3391       orntNew[3] = ornt[3];
3392       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3393       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3394 #if 1
3395       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);
3396       for (p = 0; p < 4; ++p) {
3397         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);
3398       }
3399 #endif
3400       /* A' tetrahedron: {d, a, c, f} */
3401       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
3402       orntNew[0] = -3;
3403       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
3404       orntNew[1] = ornt[2] < 0 ? -(GetTriMidEdge_Static(ornt[2], 0)+1) : GetTriMidEdge_Static(ornt[2], 0);
3405       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
3406       orntNew[2] = 0;
3407       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
3408       orntNew[3] = 2;
3409       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
3410       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
3411 #if 1
3412       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);
3413       for (p = 0; p < 4; ++p) {
3414         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3415       }
3416 #endif
3417       /* B' tetrahedron: {e, b, a, f} */
3418       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
3419       orntNew[0] = -3;
3420       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
3421       orntNew[1] = 1;
3422       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
3423       orntNew[2] = 0;
3424       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + 3;
3425       orntNew[3] = ornt[3] < 0 ? -(GetTriMidEdge_Static(ornt[3], 0)+1) : GetTriMidEdge_Static(ornt[3], 0);
3426       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
3427       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
3428 #if 1
3429       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);
3430       for (p = 0; p < 4; ++p) {
3431         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3432       }
3433 #endif
3434       /* C' tetrahedron: {b, f, c, a} */
3435       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
3436       orntNew[0] = -3;
3437       coneNew[1] = fStartNew + (cone[0] - fStart)*4 + 3;
3438       orntNew[1] = ornt[0] < 0 ? -(GetTriMidEdge_Static(ornt[0], 2)+1) : GetTriMidEdge_Static(ornt[0], 2);
3439       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
3440       orntNew[2] = -3;
3441       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
3442       orntNew[3] = -2;
3443       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
3444       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
3445 #if 1
3446       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);
3447       for (p = 0; p < 4; ++p) {
3448         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3449       }
3450 #endif
3451       /* D' tetrahedron: {f, e, d, a} */
3452       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
3453       orntNew[0] = -3;
3454       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
3455       orntNew[1] = -3;
3456       coneNew[2] = fStartNew + (cone[1] - fStart)*4 + 3;
3457       orntNew[2] = ornt[1] < 0 ? -(GetTriMidEdge_Static(ornt[1], 0)+1) : GetTriMidEdge_Static(ornt[1], 0);
3458       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
3459       orntNew[3] = -3;
3460       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
3461       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
3462 #if 1
3463       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);
3464       for (p = 0; p < 4; ++p) {
3465         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3466       }
3467 #endif
3468     }
3469     /* Hybrid cells have 5 faces */
3470     for (c = cMax; c < cEnd; ++c) {
3471       const PetscInt  newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4;
3472       const PetscInt *cone, *ornt, *fornt;
3473       PetscInt        coneNew[5], orntNew[5], o, of, i;
3474 
3475       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3476       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3477       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
3478       o = ornt[0] < 0 ? -1 : 1;
3479       for (r = 0; r < 3; ++r) {
3480         coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], r);
3481         orntNew[0] = ornt[0];
3482         coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], r);
3483         orntNew[1] = ornt[1];
3484         of = fornt[GetTriEdge_Static(ornt[0], r)]       < 0 ? -1 : 1;
3485         i  = GetTriEdgeInverse_Static(ornt[0], r)       + 2;
3486         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], r)]       - fMax)*2 + (o*of < 0 ? 1 : 0);
3487         orntNew[i] = 0;
3488         i  = GetTriEdgeInverse_Static(ornt[0], (r+1)%3) + 2;
3489         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + GetTriSubface_Static(ornt[0], r);
3490         orntNew[i] = 0;
3491         of = fornt[GetTriEdge_Static(ornt[0], (r+2)%3)] < 0 ? -1 : 1;
3492         i  = GetTriEdgeInverse_Static(ornt[0], (r+2)%3) + 2;
3493         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);
3494         orntNew[i] = 0;
3495         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
3496         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
3497 #if 1
3498         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);
3499         for (p = 0; p < 2; ++p) {
3500           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);
3501         }
3502         for (p = 2; p < 5; ++p) {
3503           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);
3504         }
3505 #endif
3506       }
3507       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + 3;
3508       orntNew[0] = 0;
3509       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + 3;
3510       orntNew[1] = 0;
3511       coneNew[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
3512       orntNew[2] = 0;
3513       coneNew[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
3514       orntNew[3] = 0;
3515       coneNew[4] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
3516       orntNew[4] = 0;
3517       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3518       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3519 #if 1
3520       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);
3521       for (p = 0; p < 2; ++p) {
3522         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);
3523       }
3524       for (p = 2; p < 5; ++p) {
3525         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);
3526       }
3527 #endif
3528     }
3529     /* Split faces have 3 edges and the same cells as the parent */
3530     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3531     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
3532     for (f = fStart; f < fMax; ++f) {
3533       const PetscInt  newp = fStartNew + (f - fStart)*4;
3534       const PetscInt *cone, *ornt, *support;
3535       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
3536 
3537       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3538       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3539       /* A triangle */
3540       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
3541       orntNew[0] = ornt[0];
3542       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
3543       orntNew[1] = -2;
3544       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
3545       orntNew[2] = ornt[2];
3546       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3547       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3548 #if 1
3549       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);
3550       for (p = 0; p < 3; ++p) {
3551         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);
3552       }
3553 #endif
3554       /* B triangle */
3555       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
3556       orntNew[0] = ornt[0];
3557       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
3558       orntNew[1] = ornt[1];
3559       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
3560       orntNew[2] = -2;
3561       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3562       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3563 #if 1
3564       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);
3565       for (p = 0; p < 3; ++p) {
3566         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);
3567       }
3568 #endif
3569       /* C triangle */
3570       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
3571       orntNew[0] = -2;
3572       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
3573       orntNew[1] = ornt[1];
3574       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
3575       orntNew[2] = ornt[2];
3576       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3577       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3578 #if 1
3579       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);
3580       for (p = 0; p < 3; ++p) {
3581         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);
3582       }
3583 #endif
3584       /* D triangle */
3585       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
3586       orntNew[0] = 0;
3587       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
3588       orntNew[1] = 0;
3589       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
3590       orntNew[2] = 0;
3591       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3592       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3593 #if 1
3594       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);
3595       for (p = 0; p < 3; ++p) {
3596         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);
3597       }
3598 #endif
3599       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3600       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3601       for (r = 0; r < 4; ++r) {
3602         for (s = 0; s < supportSize; ++s) {
3603           PetscInt subf;
3604           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3605           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3606           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3607           for (c = 0; c < coneSize; ++c) {
3608             if (cone[c] == f) break;
3609           }
3610           subf = GetTriSubfaceInverse_Static(ornt[c], r);
3611           if (support[s] < cMax) {
3612             supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
3613           } else {
3614             supportRef[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (r==3 ? r : subf);
3615           }
3616         }
3617         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
3618 #if 1
3619         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);
3620         for (p = 0; p < supportSize; ++p) {
3621           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);
3622         }
3623 #endif
3624       }
3625     }
3626     /* Interior cell faces have 3 edges and 2 cells */
3627     for (c = cStart; c < cMax; ++c) {
3628       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8;
3629       const PetscInt *cone, *ornt;
3630       PetscInt        coneNew[3], orntNew[3];
3631       PetscInt        supportNew[2];
3632 
3633       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3634       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3635       /* Face A: {c, a, d} */
3636       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3637       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3638       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3639       orntNew[1] = ornt[1] < 0 ? -2 : 0;
3640       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 2);
3641       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3642       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3643       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3644 #if 1
3645       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3646       for (p = 0; p < 3; ++p) {
3647         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);
3648       }
3649 #endif
3650       supportNew[0] = (c - cStart)*8 + 0;
3651       supportNew[1] = (c - cStart)*8 + 0+4;
3652       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3653 #if 1
3654       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3655       for (p = 0; p < 2; ++p) {
3656         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);
3657       }
3658 #endif
3659       ++newp;
3660       /* Face B: {a, b, e} */
3661       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3662       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3663       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 0);
3664       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3665       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3666       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3667       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3668       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3669 #if 1
3670       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);
3671       for (p = 0; p < 3; ++p) {
3672         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);
3673       }
3674 #endif
3675       supportNew[0] = (c - cStart)*8 + 1;
3676       supportNew[1] = (c - cStart)*8 + 1+4;
3677       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3678 #if 1
3679       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3680       for (p = 0; p < 2; ++p) {
3681         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);
3682       }
3683 #endif
3684       ++newp;
3685       /* Face C: {c, f, b} */
3686       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3687       orntNew[0] = ornt[2] < 0 ? -2 : 0;
3688       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3689       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3690       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 1);
3691       orntNew[2] = ornt[0] < 0 ? -2 : 0;
3692       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3693       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3694 #if 1
3695       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3696       for (p = 0; p < 3; ++p) {
3697         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);
3698       }
3699 #endif
3700       supportNew[0] = (c - cStart)*8 + 2;
3701       supportNew[1] = (c - cStart)*8 + 2+4;
3702       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3703 #if 1
3704       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3705       for (p = 0; p < 2; ++p) {
3706         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);
3707       }
3708 #endif
3709       ++newp;
3710       /* Face D: {d, e, f} */
3711       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 0);
3712       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3713       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3714       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3715       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3716       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3717       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3718       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3719 #if 1
3720       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3721       for (p = 0; p < 3; ++p) {
3722         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);
3723       }
3724 #endif
3725       supportNew[0] = (c - cStart)*8 + 3;
3726       supportNew[1] = (c - cStart)*8 + 3+4;
3727       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3728 #if 1
3729       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3730       for (p = 0; p < 2; ++p) {
3731         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);
3732       }
3733 #endif
3734       ++newp;
3735       /* Face E: {d, f, a} */
3736       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3737       orntNew[0] = ornt[2] < 0 ? 0 : -2;
3738       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3739       orntNew[1] = -2;
3740       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3741       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3742       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3743       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3744 #if 1
3745       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3746       for (p = 0; p < 3; ++p) {
3747         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);
3748       }
3749 #endif
3750       supportNew[0] = (c - cStart)*8 + 0+4;
3751       supportNew[1] = (c - cStart)*8 + 3+4;
3752       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3753 #if 1
3754       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3755       for (p = 0; p < 2; ++p) {
3756         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);
3757       }
3758 #endif
3759       ++newp;
3760       /* Face F: {c, a, f} */
3761       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3762       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3763       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3764       orntNew[1] = 0;
3765       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3766       orntNew[2] = ornt[2] < 0 ? 0 : -2;
3767       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3768       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3769 #if 1
3770       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3771       for (p = 0; p < 3; ++p) {
3772         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);
3773       }
3774 #endif
3775       supportNew[0] = (c - cStart)*8 + 0+4;
3776       supportNew[1] = (c - cStart)*8 + 2+4;
3777       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3778 #if 1
3779       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3780       for (p = 0; p < 2; ++p) {
3781         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);
3782       }
3783 #endif
3784       ++newp;
3785       /* Face G: {e, a, f} */
3786       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3787       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3788       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3789       orntNew[1] = 0;
3790       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3791       orntNew[2] = ornt[3] < 0 ? 0 : -2;
3792       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3793       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3794 #if 1
3795       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3796       for (p = 0; p < 3; ++p) {
3797         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);
3798       }
3799 #endif
3800       supportNew[0] = (c - cStart)*8 + 1+4;
3801       supportNew[1] = (c - cStart)*8 + 3+4;
3802       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3803 #if 1
3804       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3805       for (p = 0; p < 2; ++p) {
3806         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);
3807       }
3808 #endif
3809       ++newp;
3810       /* Face H: {a, b, f} */
3811       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3812       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3813       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3814       orntNew[1] = ornt[3] < 0 ? 0 : -2;
3815       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3816       orntNew[2] = -2;
3817       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3818       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3819 #if 1
3820       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3821       for (p = 0; p < 3; ++p) {
3822         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);
3823       }
3824 #endif
3825       supportNew[0] = (c - cStart)*8 + 1+4;
3826       supportNew[1] = (c - cStart)*8 + 2+4;
3827       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3828 #if 1
3829       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3830       for (p = 0; p < 2; ++p) {
3831         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);
3832       }
3833 #endif
3834       ++newp;
3835     }
3836     /* Hybrid split faces have 4 edges and same cells */
3837     for (f = fMax; f < fEnd; ++f) {
3838       const PetscInt *cone, *ornt, *support;
3839       PetscInt        coneNew[4], orntNew[4];
3840       PetscInt        supportNew[2], size, s, c;
3841 
3842       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3843       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3844       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3845       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3846       for (r = 0; r < 2; ++r) {
3847         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
3848 
3849         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
3850         orntNew[0]   = ornt[0];
3851         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
3852         orntNew[1]   = ornt[1];
3853         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (cone[2+r] - eMax);
3854         orntNew[2+r] = 0;
3855         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd      - eMax) + (f - fMax);
3856         orntNew[3-r] = 0;
3857         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3858         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3859 #if 1
3860         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
3861         for (p = 0; p < 2; ++p) {
3862           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);
3863         }
3864         for (p = 2; p < 4; ++p) {
3865           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);
3866         }
3867 #endif
3868         for (s = 0; s < size; ++s) {
3869           const PetscInt *coneCell, *orntCell, *fornt;
3870           PetscInt        o, of;
3871 
3872           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
3873           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
3874           o = orntCell[0] < 0 ? -1 : 1;
3875           for (c = 2; c < 5; ++c) if (coneCell[c] == f) break;
3876           if (c >= 5) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
3877           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
3878           of = fornt[c-2] < 0 ? -1 : 1;
3879           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetTriEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%3;
3880         }
3881         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3882 #if 1
3883         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
3884         for (p = 0; p < size; ++p) {
3885           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);
3886         }
3887 #endif
3888       }
3889     }
3890     /* Hybrid cell faces have 4 edges and 2 cells */
3891     for (c = cMax; c < cEnd; ++c) {
3892       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3;
3893       const PetscInt *cone, *ornt;
3894       PetscInt        coneNew[4], orntNew[4];
3895       PetscInt        supportNew[2];
3896 
3897       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3898       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3899       for (r = 0; r < 3; ++r) {
3900         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + (r+2)%3;
3901         orntNew[0] = 0;
3902         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + (r+2)%3;
3903         orntNew[1] = 0;
3904         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+(r+2)%3] - fMax);
3905         orntNew[2] = 0;
3906         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+r]       - fMax);
3907         orntNew[3] = 0;
3908         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
3909         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
3910 #if 1
3911         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);
3912         for (p = 0; p < 2; ++p) {
3913           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);
3914         }
3915         for (p = 2; p < 4; ++p) {
3916           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);
3917         }
3918 #endif
3919         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetTriSubface_Static(ornt[0], r);
3920         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + 3;
3921         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
3922 #if 1
3923         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);
3924         for (p = 0; p < 2; ++p) {
3925           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);
3926         }
3927 #endif
3928       }
3929     }
3930     /* Interior split edges have 2 vertices and the same faces as the parent */
3931     for (e = eStart; e < eMax; ++e) {
3932       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
3933 
3934       for (r = 0; r < 2; ++r) {
3935         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
3936         const PetscInt *cone, *ornt, *support;
3937         PetscInt        coneNew[2], coneSize, c, supportSize, s;
3938 
3939         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3940         coneNew[0]       = vStartNew + (cone[0] - vStart);
3941         coneNew[1]       = vStartNew + (cone[1] - vStart);
3942         coneNew[(r+1)%2] = newv;
3943         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3944 #if 1
3945         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3946         for (p = 0; p < 2; ++p) {
3947           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);
3948         }
3949 #endif
3950         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
3951         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3952         for (s = 0; s < supportSize; ++s) {
3953           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3954           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3955           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3956           for (c = 0; c < coneSize; ++c) if (cone[c] == e) break;
3957           if (support[s] < fMax) {
3958             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
3959           } else {
3960             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
3961           }
3962         }
3963         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3964 #if 1
3965         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3966         for (p = 0; p < supportSize; ++p) {
3967           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);
3968         }
3969 #endif
3970       }
3971     }
3972     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
3973     for (f = fStart; f < fMax; ++f) {
3974       const PetscInt *cone, *ornt, *support;
3975       PetscInt        coneSize, supportSize, s;
3976 
3977       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3978       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3979       for (r = 0; r < 3; ++r) {
3980         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
3981         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
3982         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
3983                                     -1, -1,  1,  6,  0,  4,
3984                                      2,  5,  3,  4, -1, -1,
3985                                     -1, -1,  3,  6,  2,  7};
3986 
3987         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3988         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
3989         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
3990         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3991 #if 1
3992         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3993         for (p = 0; p < 2; ++p) {
3994           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);
3995         }
3996 #endif
3997         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
3998         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
3999         for (s = 0; s < supportSize; ++s) {
4000           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4001           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4002           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4003           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
4004           if (support[s] < cMax) {
4005             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
4006             er = GetTriMidEdgeInverse_Static(ornt[c], r);
4007             if (er == eint[c]) {
4008               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
4009             } else {
4010               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
4011               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
4012             }
4013           } else {
4014             supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (r + 1)%3;
4015           }
4016         }
4017         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4018 #if 1
4019         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4020         for (p = 0; p < intFaces; ++p) {
4021           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);
4022         }
4023 #endif
4024       }
4025     }
4026     /* Interior cell edges have 2 vertices and 4 faces */
4027     for (c = cStart; c < cMax; ++c) {
4028       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4029       const PetscInt *cone, *ornt, *fcone;
4030       PetscInt        coneNew[2], supportNew[4], find;
4031 
4032       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4033       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4034       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
4035       find = GetTriEdge_Static(ornt[0], 0);
4036       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4037       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
4038       find = GetTriEdge_Static(ornt[2], 1);
4039       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4040       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4041 #if 1
4042       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4043       for (p = 0; p < 2; ++p) {
4044         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);
4045       }
4046 #endif
4047       supportNew[0] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 4;
4048       supportNew[1] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 5;
4049       supportNew[2] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 6;
4050       supportNew[3] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 7;
4051       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4052 #if 1
4053       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4054       for (p = 0; p < 4; ++p) {
4055         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);
4056       }
4057 #endif
4058     }
4059     /* Hybrid edges have two vertices and the same faces */
4060     for (e = eMax; e < eEnd; ++e) {
4061       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
4062       const PetscInt *cone, *support, *fcone;
4063       PetscInt        coneNew[2], size, fsize, s;
4064 
4065       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4066       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4067       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4068       coneNew[0] = vStartNew + (cone[0] - vStart);
4069       coneNew[1] = vStartNew + (cone[1] - vStart);
4070       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4071 #if 1
4072       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4073       for (p = 0; p < 2; ++p) {
4074         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);
4075       }
4076 #endif
4077       for (s = 0; s < size; ++s) {
4078         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
4079         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
4080         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
4081         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
4082         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + c-2;
4083       }
4084       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4085 #if 1
4086       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4087       for (p = 0; p < size; ++p) {
4088         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);
4089       }
4090 #endif
4091     }
4092     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
4093     for (f = fMax; f < fEnd; ++f) {
4094       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
4095       const PetscInt *cone, *support, *ccone, *cornt;
4096       PetscInt        coneNew[2], size, csize, s;
4097 
4098       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4099       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4100       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4101       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
4102       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
4103       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4104 #if 1
4105       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4106       for (p = 0; p < 2; ++p) {
4107         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);
4108       }
4109 #endif
4110       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 0;
4111       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 1;
4112       for (s = 0; s < size; ++s) {
4113         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
4114         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
4115         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
4116         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
4117         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]);
4118         supportRef[2+s*2+0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + c-2;
4119         supportRef[2+s*2+1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (c-1)%3;
4120       }
4121       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4122 #if 1
4123       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4124       for (p = 0; p < 2+size*2; ++p) {
4125         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);
4126       }
4127 #endif
4128     }
4129     /* Interior vertices have identical supports */
4130     for (v = vStart; v < vEnd; ++v) {
4131       const PetscInt  newp = vStartNew + (v - vStart);
4132       const PetscInt *support, *cone;
4133       PetscInt        size, s;
4134 
4135       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4136       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4137       for (s = 0; s < size; ++s) {
4138         PetscInt r = 0;
4139 
4140         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4141         if (cone[1] == v) r = 1;
4142         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4143         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (support[s] - eMax);
4144       }
4145       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4146 #if 1
4147       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4148       for (p = 0; p < size; ++p) {
4149         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);
4150       }
4151 #endif
4152     }
4153     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
4154     for (e = eStart; e < eMax; ++e) {
4155       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4156       const PetscInt *cone, *support;
4157       PetscInt       *star = NULL, starSize, faceSize = 0, cellSize = 0, coneSize, size, s;
4158 
4159       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4160       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4161       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4162       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4163       for (s = 0; s < size; ++s) {
4164         PetscInt r = 0;
4165 
4166         if (support[s] < fMax) {
4167           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4168           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4169           for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
4170           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
4171           supportRef[2+faceSize+1] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
4172           faceSize += 2;
4173         } else {
4174           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (support[s] - fMax);
4175           ++faceSize;
4176         }
4177       }
4178       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4179       for (s = 0; s < starSize*2; s += 2) {
4180         const PetscInt *cone, *ornt;
4181         PetscInt        e01, e23;
4182 
4183         if ((star[s] >= cStart) && (star[s] < cMax)) {
4184           /* Check edge 0-1 */
4185           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
4186           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
4187           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
4188           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
4189           /* Check edge 2-3 */
4190           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
4191           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
4192           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
4193           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
4194           if ((e01 == e) || (e23 == e)) {supportRef[2+faceSize+cellSize++] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (star[s] - cStart);}
4195         }
4196       }
4197       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4198       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4199 #if 1
4200       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4201       for (p = 0; p < 2+faceSize+cellSize; ++p) {
4202         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);
4203       }
4204 #endif
4205     }
4206     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4207     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
4208     break;
4209   case REFINER_SIMPLEX_TO_HEX_3D:
4210     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
4211     /* All cells have 6 faces */
4212     for (c = cStart; c < cEnd; ++c) {
4213       const PetscInt  newp = cStartNew + (c - cStart)*4;
4214       const PetscInt *cone, *ornt;
4215       PetscInt        coneNew[6];
4216       PetscInt        orntNew[6];
4217 
4218       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4219       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4220       /* A hex */
4221       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 0); /* B */
4222       orntNew[0] = ornt[0] < 0 ? -1 : 1;
4223       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 3;               /* T */
4224       orntNew[1] = -4;
4225       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 0); /* F */
4226       orntNew[2] = ornt[2] < 0 ? -1 : 1;
4227       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 0;               /* K */
4228       orntNew[3] = -1;
4229       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 2;               /* R */
4230       orntNew[4] = 0;
4231       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 0); /* L */
4232       orntNew[5] = ornt[1] < 0 ? -1 : 1;
4233       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4234       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4235 #if 1
4236       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);
4237       for (p = 0; p < 6; ++p) {
4238         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);
4239       }
4240 #endif
4241       /* B hex */
4242       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 1); /* B */
4243       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4244       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 4;               /* T */
4245       orntNew[1] = 0;
4246       coneNew[2] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 0;               /* F */
4247       orntNew[2] = 0;
4248       coneNew[3] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 1); /* K */
4249       orntNew[3] = ornt[3] < 0 ? -2 : 0;
4250       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 1;               /* R */
4251       orntNew[4] = 0;
4252       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 2); /* L */
4253       orntNew[5] = ornt[1] < 0 ? -4 : 2;
4254       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4255       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4256 #if 1
4257       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);
4258       for (p = 0; p < 6; ++p) {
4259         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);
4260       }
4261 #endif
4262       /* C hex */
4263       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 2); /* B */
4264       orntNew[0] = ornt[0] < 0 ? -4 : 2;
4265       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 5;               /* T */
4266       orntNew[1] = -4;
4267       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 1); /* F */
4268       orntNew[2] = ornt[2] < 0 ? -2 : 0;
4269       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 1;               /* K */
4270       orntNew[3] = -1;
4271       coneNew[4] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 0); /* R */
4272       orntNew[4] = ornt[3] < 0 ? -1 : 1;
4273       coneNew[5] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 2;               /* L */
4274       orntNew[5] = -4;
4275       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4276       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4277 #if 1
4278       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);
4279       for (p = 0; p < 6; ++p) {
4280         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);
4281       }
4282 #endif
4283       /* D hex */
4284       coneNew[0] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 3;               /* B */
4285       orntNew[0] = 0;
4286       coneNew[1] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 2); /* T */
4287       orntNew[1] = ornt[3] < 0 ? -1 : 1;
4288       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 2); /* F */
4289       orntNew[2] = ornt[2] < 0 ? -4 : 2;
4290       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 4;               /* K */
4291       orntNew[3] = -1;
4292       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 5;               /* R */
4293       orntNew[4] = 0;
4294       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 1); /* L */
4295       orntNew[5] = ornt[1] < 0 ? -2 : 0;
4296       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4297       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4298 #if 1
4299       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);
4300       for (p = 0; p < 6; ++p) {
4301         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);
4302       }
4303 #endif
4304     }
4305     /* Split faces have 4 edges and the same cells as the parent */
4306     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4307     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
4308     for (f = fStart; f < fEnd; ++f) {
4309       const PetscInt  newp = fStartNew + (f - fStart)*3;
4310       const PetscInt *cone, *ornt, *support;
4311       PetscInt        coneNew[4], orntNew[4], coneSize, supportSize, s;
4312 
4313       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4314       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4315       /* A quad */
4316       coneNew[0] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
4317       orntNew[0] = ornt[2];
4318       coneNew[1] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
4319       orntNew[1] = ornt[0];
4320       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
4321       orntNew[2] = 0;
4322       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
4323       orntNew[3] = -2;
4324       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4325       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4326 #if 1
4327       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);
4328       for (p = 0; p < 4; ++p) {
4329         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);
4330       }
4331 #endif
4332       /* B quad */
4333       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
4334       orntNew[0] = ornt[0];
4335       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
4336       orntNew[1] = ornt[1];
4337       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
4338       orntNew[2] = 0;
4339       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
4340       orntNew[3] = -2;
4341       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4342       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4343 #if 1
4344       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);
4345       for (p = 0; p < 4; ++p) {
4346         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);
4347       }
4348 #endif
4349       /* C quad */
4350       coneNew[0] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
4351       orntNew[0] = ornt[1];
4352       coneNew[1] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
4353       orntNew[1] = ornt[2];
4354       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
4355       orntNew[2] = 0;
4356       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
4357       orntNew[3] = -2;
4358       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4359       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4360 #if 1
4361       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);
4362       for (p = 0; p < 4; ++p) {
4363         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);
4364       }
4365 #endif
4366       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4367       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4368       for (r = 0; r < 3; ++r) {
4369         for (s = 0; s < supportSize; ++s) {
4370           PetscInt subf;
4371           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4372           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4373           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4374           for (c = 0; c < coneSize; ++c) {
4375             if (cone[c] == f) break;
4376           }
4377           subf = GetTriSubfaceInverse_Static(ornt[c], r);
4378           supportRef[s] = cStartNew + (support[s] - cStart)*4 + faces[c*3+subf];
4379         }
4380         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
4381 #if 1
4382         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);
4383         for (p = 0; p < supportSize; ++p) {
4384           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);
4385         }
4386 #endif
4387       }
4388     }
4389     /* Interior faces have 4 edges and 2 cells */
4390     for (c = cStart; c < cEnd; ++c) {
4391       PetscInt        newp = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6;
4392       const PetscInt *cone, *ornt;
4393       PetscInt        coneNew[4], orntNew[4];
4394       PetscInt        supportNew[2];
4395 
4396       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4397       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4398       /* Face {a, g, m, h} */
4399       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],0);
4400       orntNew[0] = 0;
4401       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
4402       orntNew[1] = 0;
4403       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
4404       orntNew[2] = -2;
4405       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],2);
4406       orntNew[3] = -2;
4407       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4408       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4409 #if 1
4410       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4411       for (p = 0; p < 4; ++p) {
4412         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);
4413       }
4414 #endif
4415       supportNew[0] = (c - cStart)*4 + 0;
4416       supportNew[1] = (c - cStart)*4 + 1;
4417       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4418 #if 1
4419       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4420       for (p = 0; p < 2; ++p) {
4421         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);
4422       }
4423 #endif
4424       ++newp;
4425       /* Face {g, b, l , m} */
4426       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],1);
4427       orntNew[0] = -2;
4428       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],0);
4429       orntNew[1] = 0;
4430       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
4431       orntNew[2] = 0;
4432       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
4433       orntNew[3] = -2;
4434       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4435       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4436 #if 1
4437       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4438       for (p = 0; p < 4; ++p) {
4439         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);
4440       }
4441 #endif
4442       supportNew[0] = (c - cStart)*4 + 1;
4443       supportNew[1] = (c - cStart)*4 + 2;
4444       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4445 #if 1
4446       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4447       for (p = 0; p < 2; ++p) {
4448         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);
4449       }
4450 #endif
4451       ++newp;
4452       /* Face {c, g, m, i} */
4453       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],2);
4454       orntNew[0] = 0;
4455       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
4456       orntNew[1] = 0;
4457       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
4458       orntNew[2] = -2;
4459       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],0);
4460       orntNew[3] = -2;
4461       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4462       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4463 #if 1
4464       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4465       for (p = 0; p < 4; ++p) {
4466         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);
4467       }
4468 #endif
4469       supportNew[0] = (c - cStart)*4 + 0;
4470       supportNew[1] = (c - cStart)*4 + 2;
4471       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4472 #if 1
4473       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4474       for (p = 0; p < 2; ++p) {
4475         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);
4476       }
4477 #endif
4478       ++newp;
4479       /* Face {d, h, m, i} */
4480       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],0);
4481       orntNew[0] = 0;
4482       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
4483       orntNew[1] = 0;
4484       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
4485       orntNew[2] = -2;
4486       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],2);
4487       orntNew[3] = -2;
4488       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4489       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4490 #if 1
4491       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4492       for (p = 0; p < 4; ++p) {
4493         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);
4494       }
4495 #endif
4496       supportNew[0] = (c - cStart)*4 + 0;
4497       supportNew[1] = (c - cStart)*4 + 3;
4498       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4499 #if 1
4500       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4501       for (p = 0; p < 2; ++p) {
4502         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);
4503       }
4504 #endif
4505       ++newp;
4506       /* Face {h, m, l, e} */
4507       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
4508       orntNew[0] = 0;
4509       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
4510       orntNew[1] = -2;
4511       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],1);
4512       orntNew[2] = -2;
4513       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],1);
4514       orntNew[3] = 0;
4515       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4516       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4517 #if 1
4518       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4519       for (p = 0; p < 4; ++p) {
4520         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);
4521       }
4522 #endif
4523       supportNew[0] = (c - cStart)*4 + 1;
4524       supportNew[1] = (c - cStart)*4 + 3;
4525       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4526 #if 1
4527       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4528       for (p = 0; p < 2; ++p) {
4529         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);
4530       }
4531 #endif
4532       ++newp;
4533       /* Face {i, m, l, f} */
4534       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
4535       orntNew[0] = 0;
4536       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
4537       orntNew[1] = -2;
4538       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],2);
4539       orntNew[2] = -2;
4540       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],1);
4541       orntNew[3] = 0;
4542       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4543       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4544 #if 1
4545       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4546       for (p = 0; p < 4; ++p) {
4547         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);
4548       }
4549 #endif
4550       supportNew[0] = (c - cStart)*4 + 2;
4551       supportNew[1] = (c - cStart)*4 + 3;
4552       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4553 #if 1
4554       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4555       for (p = 0; p < 2; ++p) {
4556         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);
4557       }
4558 #endif
4559       ++newp;
4560     }
4561     /* Split Edges have 2 vertices and the same faces as the parent */
4562     for (e = eStart; e < eEnd; ++e) {
4563       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
4564 
4565       for (r = 0; r < 2; ++r) {
4566         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
4567         const PetscInt *cone, *ornt, *support;
4568         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4569 
4570         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4571         coneNew[0]       = vStartNew + (cone[0] - vStart);
4572         coneNew[1]       = vStartNew + (cone[1] - vStart);
4573         coneNew[(r+1)%2] = newv;
4574         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4575 #if 1
4576         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4577         for (p = 0; p < 2; ++p) {
4578           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);
4579         }
4580 #endif
4581         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
4582         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4583         for (s = 0; s < supportSize; ++s) {
4584           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4585           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4586           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4587           for (c = 0; c < coneSize; ++c) {
4588             if (cone[c] == e) break;
4589           }
4590           supportRef[s] = fStartNew + (support[s] - fStart)*3 + (c + (ornt[c] < 0 ? 1-r : r))%3;
4591         }
4592         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4593 #if 1
4594         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4595         for (p = 0; p < supportSize; ++p) {
4596           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);
4597         }
4598 #endif
4599       }
4600     }
4601     /* Face edges have 2 vertices and 2 + cell faces supports */
4602     for (f = fStart; f < fEnd; ++f) {
4603       const PetscInt *cone, *ornt, *support;
4604       PetscInt        coneSize, supportSize, s;
4605 
4606       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4607       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4608       for (r = 0; r < 3; ++r) {
4609         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
4610         PetscInt        coneNew[2];
4611         PetscInt        fint[4][3] = { {0, 1, 2},
4612                                        {3, 4, 0},
4613                                        {2, 5, 3},
4614                                        {1, 4, 5} };
4615 
4616         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4617         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
4618         coneNew[1] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + f - fStart;
4619         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4620 #if 1
4621         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4622         for (p = 0; p < 2; ++p) {
4623           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);
4624         }
4625 #endif
4626         supportRef[0] = fStartNew + (f - fStart)*3 + (r+0)%3;
4627         supportRef[1] = fStartNew + (f - fStart)*3 + (r+1)%3;
4628         for (s = 0; s < supportSize; ++s) {
4629           PetscInt er;
4630           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4631           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4632           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4633           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
4634           er = GetTriInteriorEdgeInverse_Static(ornt[c], r);
4635           supportRef[2+s] = fStartNew + (fEnd - fStart)*3 + (support[s] - cStart)*6 + fint[c][er];
4636         }
4637         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4638 #if 1
4639         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4640         for (p = 0; p < supportSize + 2; ++p) {
4641           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);
4642         }
4643 #endif
4644       }
4645     }
4646     /* Interior cell edges have 2 vertices and 3 faces */
4647     for (c = cStart; c < cEnd; ++c) {
4648       const PetscInt *cone;
4649       PetscInt       fint[4][3] = { {0,1,2},
4650                                     {0,3,4},
4651                                     {2,3,5},
4652                                     {1,4,5} } ;
4653 
4654       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4655       for (r = 0; r < 4; r++) {
4656         PetscInt       coneNew[2], supportNew[3];
4657         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + r;
4658 
4659         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
4660         coneNew[1] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd -fStart) + c - cStart;
4661         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4662 #if 1
4663         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4664         for (p = 0; p < 2; ++p) {
4665           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);
4666         }
4667 #endif
4668         supportNew[0] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][0];
4669         supportNew[1] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][1];
4670         supportNew[2] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][2];
4671         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4672 #if 1
4673         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4674         for (p = 0; p < 3; ++p) {
4675           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);
4676         }
4677 #endif
4678       }
4679     }
4680     /* Old vertices have identical supports */
4681     for (v = vStart; v < vEnd; ++v) {
4682       const PetscInt  newp = vStartNew + (v - vStart);
4683       const PetscInt *support, *cone;
4684       PetscInt        size, s;
4685 
4686       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4687       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4688       for (s = 0; s < size; ++s) {
4689         PetscInt r = 0;
4690 
4691         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4692         if (cone[1] == v) r = 1;
4693         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4694       }
4695       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4696 #if 1
4697       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4698       for (p = 0; p < size; ++p) {
4699         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);
4700       }
4701 #endif
4702     }
4703     /* Edge vertices have 2 + faces supports */
4704     for (e = eStart; e < eEnd; ++e) {
4705       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4706       const PetscInt *cone, *support;
4707       PetscInt        size, s;
4708 
4709       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4710       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4711       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4712       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4713       for (s = 0; s < size; ++s) {
4714         PetscInt r = 0, coneSize;
4715 
4716         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4717         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4718         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
4719         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + r;
4720       }
4721       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4722 #if 1
4723       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4724       for (p = 0; p < 2+size; ++p) {
4725         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);
4726       }
4727 #endif
4728     }
4729     /* Face vertices have 3 + cells supports */
4730     for (f = fStart; f < fEnd; ++f) {
4731       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
4732       const PetscInt *cone, *support;
4733       PetscInt        size, s;
4734 
4735       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4736       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4737       supportRef[0] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 0;
4738       supportRef[1] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 1;
4739       supportRef[2] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 2;
4740       for (s = 0; s < size; ++s) {
4741         PetscInt r = 0, coneSize;
4742 
4743         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4744         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4745         for (r = 0; r < coneSize; ++r) {if (cone[r] == f) break;}
4746         supportRef[3+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (support[s] - cStart)*4 + r;
4747       }
4748       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4749 #if 1
4750       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4751       for (p = 0; p < 3+size; ++p) {
4752         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);
4753       }
4754 #endif
4755     }
4756     /* Interior cell vertices have 4 supports */
4757     for (c = cStart; c < cEnd; ++c) {
4758       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + c - cStart;
4759       supportRef[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
4760       supportRef[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
4761       supportRef[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
4762       supportRef[3] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
4763       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4764 #if 1
4765       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4766       for (p = 0; p < 4; ++p) {
4767         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
4768       }
4769 #endif
4770     }
4771     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4772     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
4773     break;
4774   case REFINER_HEX_3D:
4775     /*
4776      Bottom (viewed from top)    Top
4777      1---------2---------2       7---------2---------6
4778      |         |         |       |         |         |
4779      |    B    2    C    |       |    H    2    G    |
4780      |         |         |       |         |         |
4781      3----3----0----1----1       3----3----0----1----1
4782      |         |         |       |         |         |
4783      |    A    0    D    |       |    E    0    F    |
4784      |         |         |       |         |         |
4785      0---------0---------3       4---------0---------5
4786      */
4787     /* All cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
4788     for (c = cStart; c < cEnd; ++c) {
4789       const PetscInt  newp = (c - cStart)*8;
4790       const PetscInt *cone, *ornt;
4791       PetscInt        coneNew[6], orntNew[6];
4792 
4793       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4794       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4795       /* A hex */
4796       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
4797       orntNew[0] = ornt[0];
4798       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
4799       orntNew[1] = 0;
4800       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
4801       orntNew[2] = ornt[2];
4802       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
4803       orntNew[3] = 0;
4804       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
4805       orntNew[4] = 0;
4806       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
4807       orntNew[5] = ornt[5];
4808       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4809       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4810 #if 1
4811       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);
4812       for (p = 0; p < 6; ++p) {
4813         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);
4814       }
4815 #endif
4816       /* B hex */
4817       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
4818       orntNew[0] = ornt[0];
4819       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
4820       orntNew[1] = 0;
4821       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
4822       orntNew[2] = -1;
4823       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
4824       orntNew[3] = ornt[3];
4825       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
4826       orntNew[4] = 0;
4827       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
4828       orntNew[5] = ornt[5];
4829       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4830       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4831 #if 1
4832       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);
4833       for (p = 0; p < 6; ++p) {
4834         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);
4835       }
4836 #endif
4837       /* C hex */
4838       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
4839       orntNew[0] = ornt[0];
4840       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
4841       orntNew[1] = 0;
4842       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
4843       orntNew[2] = -1;
4844       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
4845       orntNew[3] = ornt[3];
4846       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
4847       orntNew[4] = ornt[4];
4848       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
4849       orntNew[5] = -4;
4850       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4851       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4852 #if 1
4853       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);
4854       for (p = 0; p < 6; ++p) {
4855         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);
4856       }
4857 #endif
4858       /* D hex */
4859       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
4860       orntNew[0] = ornt[0];
4861       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
4862       orntNew[1] = 0;
4863       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
4864       orntNew[2] = ornt[2];
4865       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
4866       orntNew[3] = 0;
4867       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
4868       orntNew[4] = ornt[4];
4869       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
4870       orntNew[5] = -4;
4871       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4872       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4873 #if 1
4874       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);
4875       for (p = 0; p < 6; ++p) {
4876         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);
4877       }
4878 #endif
4879       /* E hex */
4880       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
4881       orntNew[0] = -4;
4882       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
4883       orntNew[1] = ornt[1];
4884       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
4885       orntNew[2] = ornt[2];
4886       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
4887       orntNew[3] = 0;
4888       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
4889       orntNew[4] = -1;
4890       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
4891       orntNew[5] = ornt[5];
4892       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
4893       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
4894 #if 1
4895       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);
4896       for (p = 0; p < 6; ++p) {
4897         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);
4898       }
4899 #endif
4900       /* F hex */
4901       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
4902       orntNew[0] = -4;
4903       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
4904       orntNew[1] = ornt[1];
4905       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
4906       orntNew[2] = ornt[2];
4907       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4908       orntNew[3] = -1;
4909       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
4910       orntNew[4] = ornt[4];
4911       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
4912       orntNew[5] = 1;
4913       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
4914       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
4915 #if 1
4916       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);
4917       for (p = 0; p < 6; ++p) {
4918         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);
4919       }
4920 #endif
4921       /* G hex */
4922       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
4923       orntNew[0] = -4;
4924       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
4925       orntNew[1] = ornt[1];
4926       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4927       orntNew[2] = 0;
4928       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
4929       orntNew[3] = ornt[3];
4930       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
4931       orntNew[4] = ornt[4];
4932       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
4933       orntNew[5] = -3;
4934       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
4935       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
4936 #if 1
4937       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);
4938       for (p = 0; p < 6; ++p) {
4939         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);
4940       }
4941 #endif
4942       /* H hex */
4943       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
4944       orntNew[0] = -4;
4945       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
4946       orntNew[1] = ornt[1];
4947       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
4948       orntNew[2] = -1;
4949       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
4950       orntNew[3] = ornt[3];
4951       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
4952       orntNew[4] = 3;
4953       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
4954       orntNew[5] = ornt[5];
4955       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
4956       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
4957 #if 1
4958       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);
4959       for (p = 0; p < 6; ++p) {
4960         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);
4961       }
4962 #endif
4963     }
4964     /* Split faces have 4 edges and the same cells as the parent */
4965     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4966     ierr = PetscMalloc1(4 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
4967     for (f = fStart; f < fEnd; ++f) {
4968       for (r = 0; r < 4; ++r) {
4969         /* TODO: This can come from GetFaces_Internal() */
4970         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};
4971         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
4972         const PetscInt *cone, *ornt, *support;
4973         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
4974 
4975         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4976         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4977         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
4978         orntNew[(r+3)%4] = ornt[(r+3)%4];
4979         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
4980         orntNew[(r+0)%4] = ornt[r];
4981         coneNew[(r+1)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
4982         orntNew[(r+1)%4] = 0;
4983         coneNew[(r+2)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + (r+3)%4;
4984         orntNew[(r+2)%4] = -2;
4985         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4986         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4987 #if 1
4988         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4989         for (p = 0; p < 4; ++p) {
4990           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);
4991         }
4992 #endif
4993         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4994         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4995         for (s = 0; s < supportSize; ++s) {
4996           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4997           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4998           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4999           for (c = 0; c < coneSize; ++c) {
5000             if (cone[c] == f) break;
5001           }
5002           supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+GetQuadSubfaceInverse_Static(ornt[c], r)];
5003         }
5004         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5005 #if 1
5006         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5007         for (p = 0; p < supportSize; ++p) {
5008           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);
5009         }
5010 #endif
5011       }
5012     }
5013     /* Interior faces have 4 edges and 2 cells */
5014     for (c = cStart; c < cEnd; ++c) {
5015       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};
5016       const PetscInt *cone, *ornt;
5017       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
5018 
5019       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5020       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5021       /* A-D face */
5022       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 0;
5023       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
5024       orntNew[0] = 0;
5025       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
5026       orntNew[1] = 0;
5027       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
5028       orntNew[2] = -2;
5029       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
5030       orntNew[3] = -2;
5031       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5032       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5033 #if 1
5034       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5035       for (p = 0; p < 4; ++p) {
5036         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);
5037       }
5038 #endif
5039       /* C-D face */
5040       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 1;
5041       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
5042       orntNew[0] = 0;
5043       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
5044       orntNew[1] = 0;
5045       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
5046       orntNew[2] = -2;
5047       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
5048       orntNew[3] = -2;
5049       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5050       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5051 #if 1
5052       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5053       for (p = 0; p < 4; ++p) {
5054         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);
5055       }
5056 #endif
5057       /* B-C face */
5058       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 2;
5059       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
5060       orntNew[0] = -2;
5061       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
5062       orntNew[1] = 0;
5063       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
5064       orntNew[2] = 0;
5065       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
5066       orntNew[3] = -2;
5067       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5068       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5069 #if 1
5070       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5071       for (p = 0; p < 4; ++p) {
5072         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);
5073       }
5074 #endif
5075       /* A-B face */
5076       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 3;
5077       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
5078       orntNew[0] = -2;
5079       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
5080       orntNew[1] = 0;
5081       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
5082       orntNew[2] = 0;
5083       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
5084       orntNew[3] = -2;
5085       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5086       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5087 #if 1
5088       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5089       for (p = 0; p < 4; ++p) {
5090         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);
5091       }
5092 #endif
5093       /* E-F face */
5094       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 4;
5095       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
5096       orntNew[0] = -2;
5097       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
5098       orntNew[1] = -2;
5099       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
5100       orntNew[2] = 0;
5101       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
5102       orntNew[3] = 0;
5103       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5104       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5105 #if 1
5106       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5107       for (p = 0; p < 4; ++p) {
5108         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);
5109       }
5110 #endif
5111       /* F-G face */
5112       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 5;
5113       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
5114       orntNew[0] = -2;
5115       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
5116       orntNew[1] = -2;
5117       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
5118       orntNew[2] = 0;
5119       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
5120       orntNew[3] = 0;
5121       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5122       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5123 #if 1
5124       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5125       for (p = 0; p < 4; ++p) {
5126         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);
5127       }
5128 #endif
5129       /* G-H face */
5130       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 6;
5131       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
5132       orntNew[0] = -2;
5133       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
5134       orntNew[1] = 0;
5135       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
5136       orntNew[2] = 0;
5137       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
5138       orntNew[3] = -2;
5139       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5140       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5141 #if 1
5142       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5143       for (p = 0; p < 4; ++p) {
5144         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);
5145       }
5146 #endif
5147       /* E-H face */
5148       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 7;
5149       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
5150       orntNew[0] = -2;
5151       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
5152       orntNew[1] = -2;
5153       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
5154       orntNew[2] = 0;
5155       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
5156       orntNew[3] = 0;
5157       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5158       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5159 #if 1
5160       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5161       for (p = 0; p < 4; ++p) {
5162         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);
5163       }
5164 #endif
5165       /* A-E face */
5166       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 8;
5167       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
5168       orntNew[0] = 0;
5169       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
5170       orntNew[1] = 0;
5171       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
5172       orntNew[2] = -2;
5173       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
5174       orntNew[3] = -2;
5175       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5176       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5177 #if 1
5178       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5179       for (p = 0; p < 4; ++p) {
5180         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);
5181       }
5182 #endif
5183       /* D-F face */
5184       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 9;
5185       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
5186       orntNew[0] = -2;
5187       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
5188       orntNew[1] = 0;
5189       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
5190       orntNew[2] = 0;
5191       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
5192       orntNew[3] = -2;
5193       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5194       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5195 #if 1
5196       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5197       for (p = 0; p < 4; ++p) {
5198         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);
5199       }
5200 #endif
5201       /* C-G face */
5202       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 10;
5203       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
5204       orntNew[0] = -2;
5205       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
5206       orntNew[1] = -2;
5207       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
5208       orntNew[2] = 0;
5209       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
5210       orntNew[3] = 0;
5211       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5212       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5213 #if 1
5214       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5215       for (p = 0; p < 4; ++p) {
5216         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);
5217       }
5218 #endif
5219       /* B-H face */
5220       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 11;
5221       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
5222       orntNew[0] = 0;
5223       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
5224       orntNew[1] = -2;
5225       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
5226       orntNew[2] = -2;
5227       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
5228       orntNew[3] = 0;
5229       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5230       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5231 #if 1
5232       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5233       for (p = 0; p < 4; ++p) {
5234         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);
5235       }
5236 #endif
5237       for (r = 0; r < 12; ++r) {
5238         newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
5239         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
5240         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
5241         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5242 #if 1
5243         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5244         for (p = 0; p < 2; ++p) {
5245           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);
5246         }
5247 #endif
5248       }
5249     }
5250     /* Split edges have 2 vertices and the same faces as the parent */
5251     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5252     for (e = eStart; e < eEnd; ++e) {
5253       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
5254 
5255       for (r = 0; r < 2; ++r) {
5256         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
5257         const PetscInt *cone, *ornt, *support;
5258         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5259 
5260         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
5261         coneNew[0]       = vStartNew + (cone[0] - vStart);
5262         coneNew[1]       = vStartNew + (cone[1] - vStart);
5263         coneNew[(r+1)%2] = newv;
5264         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5265 #if 1
5266         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5267         for (p = 0; p < 2; ++p) {
5268           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);
5269         }
5270 #endif
5271         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
5272         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5273         for (s = 0; s < supportSize; ++s) {
5274           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5275           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5276           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5277           for (c = 0; c < coneSize; ++c) {
5278             if (cone[c] == e) break;
5279           }
5280           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
5281         }
5282         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5283 #if 1
5284         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5285         for (p = 0; p < supportSize; ++p) {
5286           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);
5287         }
5288 #endif
5289       }
5290     }
5291     /* Face edges have 2 vertices and 2+cells faces */
5292     for (f = fStart; f < fEnd; ++f) {
5293       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};
5294       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
5295       const PetscInt *cone, *coneCell, *orntCell, *support;
5296       PetscInt        coneNew[2], coneSize, c, supportSize, s;
5297 
5298       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5299       for (r = 0; r < 4; ++r) {
5300         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
5301 
5302         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
5303         coneNew[1] = newv;
5304         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5305 #if 1
5306         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5307         for (p = 0; p < 2; ++p) {
5308           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);
5309         }
5310 #endif
5311         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5312         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5313         supportRef[0] = fStartNew + (f - fStart)*4 + r;
5314         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
5315         for (s = 0; s < supportSize; ++s) {
5316           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5317           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
5318           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
5319           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
5320           supportRef[2+s] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
5321         }
5322         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5323 #if 1
5324         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5325         for (p = 0; p < 2+supportSize; ++p) {
5326           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);
5327         }
5328 #endif
5329       }
5330     }
5331     /* Cell edges have 2 vertices and 4 faces */
5332     for (c = cStart; c < cEnd; ++c) {
5333       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};
5334       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
5335       const PetscInt *cone;
5336       PetscInt        coneNew[2], supportNew[4];
5337 
5338       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5339       for (r = 0; r < 6; ++r) {
5340         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
5341 
5342         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
5343         coneNew[1] = newv;
5344         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5345 #if 1
5346         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5347         for (p = 0; p < 2; ++p) {
5348           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);
5349         }
5350 #endif
5351         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
5352         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5353 #if 1
5354         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5355         for (p = 0; p < 4; ++p) {
5356           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);
5357         }
5358 #endif
5359       }
5360     }
5361     /* Old vertices have identical supports */
5362     for (v = vStart; v < vEnd; ++v) {
5363       const PetscInt  newp = vStartNew + (v - vStart);
5364       const PetscInt *support, *cone;
5365       PetscInt        size, s;
5366 
5367       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5368       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5369       for (s = 0; s < size; ++s) {
5370         PetscInt r = 0;
5371 
5372         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5373         if (cone[1] == v) r = 1;
5374         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
5375       }
5376       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5377 #if 1
5378       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5379       for (p = 0; p < size; ++p) {
5380         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);
5381       }
5382 #endif
5383     }
5384     /* Edge vertices have 2 + faces supports */
5385     for (e = eStart; e < eEnd; ++e) {
5386       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
5387       const PetscInt *cone, *support;
5388       PetscInt        size, s;
5389 
5390       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
5391       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5392       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
5393       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
5394       for (s = 0; s < size; ++s) {
5395         PetscInt r;
5396 
5397         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5398         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
5399         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*4 + r;
5400       }
5401       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5402 #if 1
5403       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5404       for (p = 0; p < 2+size; ++p) {
5405         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);
5406       }
5407 #endif
5408     }
5409     /* Face vertices have 4 + cells supports */
5410     for (f = fStart; f < fEnd; ++f) {
5411       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
5412       const PetscInt *cone, *support;
5413       PetscInt        size, s;
5414 
5415       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5416       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5417       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eEnd - eStart)*2 +  (f - fStart)*4 + r;
5418       for (s = 0; s < size; ++s) {
5419         PetscInt r;
5420 
5421         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5422         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
5423         supportRef[4+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (support[s] - cStart)*6 + r;
5424       }
5425       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5426 #if 1
5427       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5428       for (p = 0; p < 4+size; ++p) {
5429         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);
5430       }
5431 #endif
5432     }
5433     /* Cell vertices have 6 supports */
5434     for (c = cStart; c < cEnd; ++c) {
5435       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
5436       PetscInt       supportNew[6];
5437 
5438       for (r = 0; r < 6; ++r) {
5439         supportNew[r] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
5440       }
5441       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5442     }
5443     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5444     break;
5445   case REFINER_HYBRID_HEX_3D:
5446     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
5447     /*
5448      Bottom (viewed from top)    Top
5449      1---------2---------2       7---------2---------6
5450      |         |         |       |         |         |
5451      |    B    2    C    |       |    H    2    G    |
5452      |         |         |       |         |         |
5453      3----3----0----1----1       3----3----0----1----1
5454      |         |         |       |         |         |
5455      |    A    0    D    |       |    E    0    F    |
5456      |         |         |       |         |         |
5457      0---------0---------3       4---------0---------5
5458      */
5459     /* Interior cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
5460     for (c = cStart; c < cMax; ++c) {
5461       const PetscInt  newp = (c - cStart)*8;
5462       const PetscInt *cone, *ornt;
5463       PetscInt        coneNew[6], orntNew[6];
5464 
5465       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5466       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5467       /* A hex */
5468       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
5469       orntNew[0] = ornt[0];
5470       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
5471       orntNew[1] = 0;
5472       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
5473       orntNew[2] = ornt[2];
5474       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
5475       orntNew[3] = 0;
5476       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
5477       orntNew[4] = 0;
5478       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
5479       orntNew[5] = ornt[5];
5480       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5481       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5482 #if 1
5483       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);
5484       for (p = 0; p < 6; ++p) {
5485         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);
5486       }
5487 #endif
5488       /* B hex */
5489       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
5490       orntNew[0] = ornt[0];
5491       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
5492       orntNew[1] = 0;
5493       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
5494       orntNew[2] = -1;
5495       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
5496       orntNew[3] = ornt[3];
5497       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
5498       orntNew[4] = 0;
5499       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
5500       orntNew[5] = ornt[5];
5501       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5502       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5503 #if 1
5504       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);
5505       for (p = 0; p < 6; ++p) {
5506         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);
5507       }
5508 #endif
5509       /* C hex */
5510       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
5511       orntNew[0] = ornt[0];
5512       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
5513       orntNew[1] = 0;
5514       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
5515       orntNew[2] = -1;
5516       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
5517       orntNew[3] = ornt[3];
5518       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
5519       orntNew[4] = ornt[4];
5520       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
5521       orntNew[5] = -4;
5522       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5523       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5524 #if 1
5525       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);
5526       for (p = 0; p < 6; ++p) {
5527         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);
5528       }
5529 #endif
5530       /* D hex */
5531       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
5532       orntNew[0] = ornt[0];
5533       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
5534       orntNew[1] = 0;
5535       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
5536       orntNew[2] = ornt[2];
5537       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
5538       orntNew[3] = 0;
5539       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
5540       orntNew[4] = ornt[4];
5541       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
5542       orntNew[5] = -4;
5543       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5544       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5545 #if 1
5546       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);
5547       for (p = 0; p < 6; ++p) {
5548         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);
5549       }
5550 #endif
5551       /* E hex */
5552       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
5553       orntNew[0] = -4;
5554       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
5555       orntNew[1] = ornt[1];
5556       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
5557       orntNew[2] = ornt[2];
5558       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
5559       orntNew[3] = 0;
5560       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
5561       orntNew[4] = -1;
5562       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
5563       orntNew[5] = ornt[5];
5564       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
5565       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
5566 #if 1
5567       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);
5568       for (p = 0; p < 6; ++p) {
5569         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);
5570       }
5571 #endif
5572       /* F hex */
5573       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
5574       orntNew[0] = -4;
5575       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
5576       orntNew[1] = ornt[1];
5577       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
5578       orntNew[2] = ornt[2];
5579       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
5580       orntNew[3] = -1;
5581       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
5582       orntNew[4] = ornt[4];
5583       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
5584       orntNew[5] = 1;
5585       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
5586       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
5587 #if 1
5588       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);
5589       for (p = 0; p < 6; ++p) {
5590         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);
5591       }
5592 #endif
5593       /* G hex */
5594       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
5595       orntNew[0] = -4;
5596       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
5597       orntNew[1] = ornt[1];
5598       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
5599       orntNew[2] = 0;
5600       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
5601       orntNew[3] = ornt[3];
5602       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
5603       orntNew[4] = ornt[4];
5604       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
5605       orntNew[5] = -3;
5606       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
5607       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
5608 #if 1
5609       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);
5610       for (p = 0; p < 6; ++p) {
5611         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);
5612       }
5613 #endif
5614       /* H hex */
5615       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
5616       orntNew[0] = -4;
5617       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
5618       orntNew[1] = ornt[1];
5619       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
5620       orntNew[2] = -1;
5621       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
5622       orntNew[3] = ornt[3];
5623       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
5624       orntNew[4] = 3;
5625       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
5626       orntNew[5] = ornt[5];
5627       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
5628       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
5629 #if 1
5630       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);
5631       for (p = 0; p < 6; ++p) {
5632         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);
5633       }
5634 #endif
5635     }
5636     /* Hybrid cells have 6 faces: Front, Back, Sides */
5637     /*
5638      3---------2---------2
5639      |         |         |
5640      |    D    2    C    |
5641      |         |         |
5642      3----3----0----1----1
5643      |         |         |
5644      |    A    0    B    |
5645      |         |         |
5646      0---------0---------1
5647      */
5648     for (c = cMax; c < cEnd; ++c) {
5649       const PetscInt  newp = (cMax - cStart)*8 + (c - cMax)*4;
5650       const PetscInt *cone, *ornt, *fornt;
5651       PetscInt        coneNew[6], orntNew[6], o, of, i;
5652 
5653       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5654       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5655       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
5656       o = ornt[0] < 0 ? -1 : 1;
5657       for (r = 0; r < 4; ++r) {
5658         PetscInt subfA = GetQuadSubface_Static(ornt[0], r);
5659         PetscInt edgeA = GetQuadEdge_Static(ornt[0], r);
5660         PetscInt edgeB = GetQuadEdge_Static(ornt[0], (r+3)%4);
5661         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]);
5662         coneNew[0]         = fStartNew + (cone[0] - fStart)*4 + subfA;
5663         orntNew[0]         = ornt[0];
5664         coneNew[1]         = fStartNew + (cone[1] - fStart)*4 + subfA;
5665         orntNew[1]         = ornt[0];
5666         of = fornt[edgeA] < 0 ? -1 : 1;
5667         i  = GetQuadEdgeInverse_Static(ornt[0], r) + 2;
5668         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeA] - fMax)*2 + (o*of < 0 ? 1 : 0);
5669         orntNew[i] = ornt[edgeA];
5670         i  = GetQuadEdgeInverse_Static(ornt[0], (r+1)%4) + 2;
5671         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeA;
5672         orntNew[i] = 0;
5673         i  = GetQuadEdgeInverse_Static(ornt[0], (r+2)%4) + 2;
5674         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeB;
5675         orntNew[i] = -2;
5676         of = fornt[edgeB] < 0 ? -1 : 1;
5677         i  = GetQuadEdgeInverse_Static(ornt[0], (r+3)%4) + 2;
5678         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeB] - fMax)*2 + (o*of < 0 ? 0 : 1);
5679         orntNew[i] = ornt[edgeB];
5680         ierr       = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
5681         ierr       = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
5682 #if 1
5683         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);
5684         for (p = 0; p < 2; ++p) {
5685           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);
5686         }
5687         for (p = 2; p < 6; ++p) {
5688           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);
5689         }
5690 #endif
5691       }
5692     }
5693     /* Interior split faces have 4 edges and the same cells as the parent */
5694     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5695     ierr = PetscMalloc1(4 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
5696     for (f = fStart; f < fMax; ++f) {
5697       for (r = 0; r < 4; ++r) {
5698         /* TODO: This can come from GetFaces_Internal() */
5699         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};
5700         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
5701         const PetscInt *cone, *ornt, *support;
5702         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
5703 
5704         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5705         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
5706         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
5707         orntNew[(r+3)%4] = ornt[(r+3)%4];
5708         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
5709         orntNew[(r+0)%4] = ornt[r];
5710         coneNew[(r+1)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
5711         orntNew[(r+1)%4] = 0;
5712         coneNew[(r+2)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + (r+3)%4;
5713         orntNew[(r+2)%4] = -2;
5714         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5715         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5716 #if 1
5717         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5718         for (p = 0; p < 4; ++p) {
5719           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);
5720         }
5721 #endif
5722         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5723         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5724         for (s = 0; s < supportSize; ++s) {
5725           PetscInt subf;
5726           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5727           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5728           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5729           for (c = 0; c < coneSize; ++c) {
5730             if (cone[c] == f) break;
5731           }
5732           subf = GetQuadSubfaceInverse_Static(ornt[c], r);
5733           if (support[s] < cMax) {
5734             supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+subf];
5735           } else {
5736             supportRef[s] = cStartNew + (cMax       - cStart)*8 + (support[s] - cMax)*4 + subf;
5737           }
5738         }
5739         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5740 #if 1
5741         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5742         for (p = 0; p < supportSize; ++p) {
5743           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);
5744         }
5745 #endif
5746       }
5747     }
5748     /* Interior cell faces have 4 edges and 2 cells */
5749     for (c = cStart; c < cMax; ++c) {
5750       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};
5751       const PetscInt *cone, *ornt;
5752       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
5753 
5754       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5755       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5756       /* A-D face */
5757       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 0;
5758       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
5759       orntNew[0] = 0;
5760       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
5761       orntNew[1] = 0;
5762       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
5763       orntNew[2] = -2;
5764       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
5765       orntNew[3] = -2;
5766       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5767       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5768 #if 1
5769       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5770       for (p = 0; p < 4; ++p) {
5771         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);
5772       }
5773 #endif
5774       /* C-D face */
5775       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 1;
5776       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
5777       orntNew[0] = 0;
5778       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
5779       orntNew[1] = 0;
5780       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
5781       orntNew[2] = -2;
5782       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
5783       orntNew[3] = -2;
5784       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5785       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5786 #if 1
5787       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5788       for (p = 0; p < 4; ++p) {
5789         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);
5790       }
5791 #endif
5792       /* B-C face */
5793       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 2;
5794       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
5795       orntNew[0] = -2;
5796       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
5797       orntNew[1] = 0;
5798       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
5799       orntNew[2] = 0;
5800       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
5801       orntNew[3] = -2;
5802       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5803       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5804 #if 1
5805       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5806       for (p = 0; p < 4; ++p) {
5807         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);
5808       }
5809 #endif
5810       /* A-B face */
5811       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 3;
5812       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
5813       orntNew[0] = -2;
5814       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
5815       orntNew[1] = 0;
5816       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
5817       orntNew[2] = 0;
5818       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
5819       orntNew[3] = -2;
5820       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5821       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5822 #if 1
5823       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5824       for (p = 0; p < 4; ++p) {
5825         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);
5826       }
5827 #endif
5828       /* E-F face */
5829       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 4;
5830       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
5831       orntNew[0] = -2;
5832       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
5833       orntNew[1] = -2;
5834       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
5835       orntNew[2] = 0;
5836       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
5837       orntNew[3] = 0;
5838       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5839       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5840 #if 1
5841       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5842       for (p = 0; p < 4; ++p) {
5843         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);
5844       }
5845 #endif
5846       /* F-G face */
5847       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 5;
5848       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
5849       orntNew[0] = -2;
5850       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
5851       orntNew[1] = -2;
5852       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
5853       orntNew[2] = 0;
5854       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
5855       orntNew[3] = 0;
5856       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5857       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5858 #if 1
5859       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5860       for (p = 0; p < 4; ++p) {
5861         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);
5862       }
5863 #endif
5864       /* G-H face */
5865       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 6;
5866       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
5867       orntNew[0] = -2;
5868       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
5869       orntNew[1] = 0;
5870       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
5871       orntNew[2] = 0;
5872       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
5873       orntNew[3] = -2;
5874       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5875       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5876 #if 1
5877       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5878       for (p = 0; p < 4; ++p) {
5879         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);
5880       }
5881 #endif
5882       /* E-H face */
5883       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 7;
5884       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
5885       orntNew[0] = -2;
5886       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
5887       orntNew[1] = -2;
5888       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
5889       orntNew[2] = 0;
5890       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
5891       orntNew[3] = 0;
5892       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5893       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5894 #if 1
5895       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5896       for (p = 0; p < 4; ++p) {
5897         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);
5898       }
5899 #endif
5900       /* A-E face */
5901       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 8;
5902       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
5903       orntNew[0] = 0;
5904       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
5905       orntNew[1] = 0;
5906       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
5907       orntNew[2] = -2;
5908       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
5909       orntNew[3] = -2;
5910       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5911       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5912 #if 1
5913       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5914       for (p = 0; p < 4; ++p) {
5915         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);
5916       }
5917 #endif
5918       /* D-F face */
5919       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 9;
5920       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
5921       orntNew[0] = -2;
5922       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
5923       orntNew[1] = 0;
5924       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
5925       orntNew[2] = 0;
5926       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
5927       orntNew[3] = -2;
5928       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5929       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5930 #if 1
5931       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5932       for (p = 0; p < 4; ++p) {
5933         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);
5934       }
5935 #endif
5936       /* C-G face */
5937       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 10;
5938       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
5939       orntNew[0] = -2;
5940       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
5941       orntNew[1] = -2;
5942       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
5943       orntNew[2] = 0;
5944       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
5945       orntNew[3] = 0;
5946       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5947       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5948 #if 1
5949       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5950       for (p = 0; p < 4; ++p) {
5951         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);
5952       }
5953 #endif
5954       /* B-H face */
5955       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 11;
5956       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
5957       orntNew[0] = 0;
5958       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
5959       orntNew[1] = -2;
5960       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
5961       orntNew[2] = -2;
5962       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
5963       orntNew[3] = 0;
5964       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5965       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5966 #if 1
5967       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5968       for (p = 0; p < 4; ++p) {
5969         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);
5970       }
5971 #endif
5972       for (r = 0; r < 12; ++r) {
5973         newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
5974         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
5975         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
5976         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5977 #if 1
5978         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5979         for (p = 0; p < 2; ++p) {
5980           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);
5981         }
5982 #endif
5983       }
5984     }
5985     /* Hybrid split faces have 4 edges and same cells */
5986     for (f = fMax; f < fEnd; ++f) {
5987       const PetscInt *cone, *ornt, *support;
5988       PetscInt        coneNew[4], orntNew[4];
5989       PetscInt        supportNew[2], size, s, c;
5990 
5991       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5992       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
5993       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5994       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5995       for (r = 0; r < 2; ++r) {
5996         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
5997 
5998         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
5999         orntNew[0]   = ornt[0];
6000         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
6001         orntNew[1]   = ornt[1];
6002         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (cone[2+r] - eMax);
6003         orntNew[2+r] = 0;
6004         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd      - eMax) + (f - fMax);
6005         orntNew[3-r] = 0;
6006         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6007         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6008 #if 1
6009         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
6010         for (p = 0; p < 2; ++p) {
6011           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);
6012         }
6013         for (p = 2; p < 4; ++p) {
6014           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);
6015         }
6016 #endif
6017         for (s = 0; s < size; ++s) {
6018           const PetscInt *coneCell, *orntCell, *fornt;
6019           PetscInt        o, of;
6020 
6021           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
6022           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
6023           o = orntCell[0] < 0 ? -1 : 1;
6024           for (c = 2; c < 6; ++c) if (coneCell[c] == f) break;
6025           if (c >= 6) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
6026           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
6027           of = fornt[c-2] < 0 ? -1 : 1;
6028           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetQuadEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%4;
6029         }
6030         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6031 #if 1
6032         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
6033         for (p = 0; p < size; ++p) {
6034           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);
6035         }
6036 #endif
6037       }
6038     }
6039     /* Hybrid cell faces have 4 edges and 2 cells */
6040     for (c = cMax; c < cEnd; ++c) {
6041       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4;
6042       const PetscInt *cone, *ornt;
6043       PetscInt        coneNew[4], orntNew[4];
6044       PetscInt        supportNew[2];
6045 
6046       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6047       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6048       for (r = 0; r < 4; ++r) {
6049 #if 0
6050         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], r);
6051         orntNew[0] = 0;
6052         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], r);
6053         orntNew[1] = 0;
6054         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+GetQuadEdge_Static(ornt[0], r)] - fMax);
6055         orntNew[2] = 0;
6056         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd                                   - fMax) + (c - cMax);
6057         orntNew[3] = 0;
6058 #else
6059         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + r;
6060         orntNew[0] = 0;
6061         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + r;
6062         orntNew[1] = 0;
6063         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+r] - fMax);
6064         orntNew[2] = 0;
6065         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd      - fMax) + (c - cMax);
6066         orntNew[3] = 0;
6067 #endif
6068         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
6069         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
6070 #if 1
6071         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);
6072         for (p = 0; p < 2; ++p) {
6073           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);
6074         }
6075         for (p = 2; p < 4; ++p) {
6076           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);
6077         }
6078 #endif
6079         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], r);
6080         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], (r+1)%4);
6081         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
6082 #if 1
6083         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);
6084         for (p = 0; p < 2; ++p) {
6085           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);
6086         }
6087 #endif
6088       }
6089     }
6090     /* Interior split edges have 2 vertices and the same faces as the parent */
6091     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6092     for (e = eStart; e < eMax; ++e) {
6093       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
6094 
6095       for (r = 0; r < 2; ++r) {
6096         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
6097         const PetscInt *cone, *ornt, *support;
6098         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6099 
6100         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6101         coneNew[0]       = vStartNew + (cone[0] - vStart);
6102         coneNew[1]       = vStartNew + (cone[1] - vStart);
6103         coneNew[(r+1)%2] = newv;
6104         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6105 #if 1
6106         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6107         for (p = 0; p < 2; ++p) {
6108           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);
6109         }
6110 #endif
6111         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
6112         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
6113         for (s = 0; s < supportSize; ++s) {
6114           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6115           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6116           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
6117           for (c = 0; c < coneSize; ++c) {
6118             if (cone[c] == e) break;
6119           }
6120           if (support[s] < fMax) {
6121             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%4;
6122           } else {
6123             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
6124           }
6125         }
6126         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6127 #if 1
6128         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6129         for (p = 0; p < supportSize; ++p) {
6130           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);
6131         }
6132 #endif
6133       }
6134     }
6135     /* Interior face edges have 2 vertices and 2+cells faces */
6136     for (f = fStart; f < fMax; ++f) {
6137       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};
6138       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
6139       const PetscInt *cone, *coneCell, *orntCell, *support;
6140       PetscInt        coneNew[2], coneSize, c, supportSize, s;
6141 
6142       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6143       for (r = 0; r < 4; ++r) {
6144         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
6145 
6146         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
6147         coneNew[1] = newv;
6148         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6149 #if 1
6150         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6151         for (p = 0; p < 2; ++p) {
6152           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);
6153         }
6154 #endif
6155         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6156         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6157         supportRef[0] = fStartNew + (f - fStart)*4 + r;
6158         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
6159         for (s = 0; s < supportSize; ++s) {
6160           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6161           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
6162           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
6163           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
6164           if (support[s] < cMax) {
6165             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
6166           } else {
6167             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + r;
6168           }
6169         }
6170         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6171 #if 1
6172         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6173         for (p = 0; p < 2+supportSize; ++p) {
6174           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);
6175         }
6176 #endif
6177       }
6178     }
6179     /* Interior cell edges have 2 vertices and 4 faces */
6180     for (c = cStart; c < cMax; ++c) {
6181       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};
6182       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
6183       const PetscInt *cone;
6184       PetscInt        coneNew[2], supportNew[4];
6185 
6186       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6187       for (r = 0; r < 6; ++r) {
6188         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
6189 
6190         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
6191         coneNew[1] = newv;
6192         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6193 #if 1
6194         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6195         for (p = 0; p < 2; ++p) {
6196           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);
6197         }
6198 #endif
6199         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
6200         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6201 #if 1
6202         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6203         for (p = 0; p < 4; ++p) {
6204           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);
6205         }
6206 #endif
6207       }
6208     }
6209     /* Hybrid edges have two vertices and the same faces */
6210     for (e = eMax; e < eEnd; ++e) {
6211       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
6212       const PetscInt *cone, *support, *fcone;
6213       PetscInt        coneNew[2], size, fsize, s;
6214 
6215       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6216       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
6217       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
6218       coneNew[0] = vStartNew + (cone[0] - vStart);
6219       coneNew[1] = vStartNew + (cone[1] - vStart);
6220       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6221 #if 1
6222       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6223       for (p = 0; p < 2; ++p) {
6224         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);
6225       }
6226 #endif
6227       for (s = 0; s < size; ++s) {
6228         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
6229         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
6230         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
6231         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
6232         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + c-2;
6233       }
6234       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6235 #if 1
6236       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6237       for (p = 0; p < size; ++p) {
6238         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);
6239       }
6240 #endif
6241     }
6242     /* Hybrid face edges have 2 vertices and 2+cells faces */
6243     for (f = fMax; f < fEnd; ++f) {
6244       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
6245       const PetscInt *cone, *support, *ccone, *cornt;
6246       PetscInt        coneNew[2], size, csize, s;
6247 
6248       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6249       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6250       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6251       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
6252       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
6253       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6254 #if 1
6255       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6256       for (p = 0; p < 2; ++p) {
6257         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);
6258       }
6259 #endif
6260       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 0;
6261       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 1;
6262       for (s = 0; s < size; ++s) {
6263         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
6264         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
6265         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
6266         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
6267         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]);
6268         supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + c-2;
6269       }
6270       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6271 #if 1
6272       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6273       for (p = 0; p < 2+size; ++p) {
6274         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);
6275       }
6276 #endif
6277     }
6278     /* Hybrid cell edges have 2 vertices and 4 faces */
6279     for (c = cMax; c < cEnd; ++c) {
6280       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
6281       const PetscInt *cone, *support;
6282       PetscInt        coneNew[2], size;
6283 
6284       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6285       ierr = DMPlexGetSupportSize(dm, c, &size);CHKERRQ(ierr);
6286       ierr = DMPlexGetSupport(dm, c, &support);CHKERRQ(ierr);
6287       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
6288       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
6289       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6290 #if 1
6291       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6292       for (p = 0; p < 2; ++p) {
6293         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);
6294       }
6295 #endif
6296       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 0;
6297       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 1;
6298       supportRef[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 2;
6299       supportRef[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 3;
6300       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6301 #if 1
6302       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6303       for (p = 0; p < 4; ++p) {
6304         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);
6305       }
6306 #endif
6307     }
6308     /* Interior vertices have identical supports */
6309     for (v = vStart; v < vEnd; ++v) {
6310       const PetscInt  newp = vStartNew + (v - vStart);
6311       const PetscInt *support, *cone;
6312       PetscInt        size, s;
6313 
6314       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6315       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6316       for (s = 0; s < size; ++s) {
6317         PetscInt r = 0;
6318 
6319         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6320         if (cone[1] == v) r = 1;
6321         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
6322         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (support[s] - eMax);
6323       }
6324       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6325 #if 1
6326       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6327       for (p = 0; p < size; ++p) {
6328         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);
6329       }
6330 #endif
6331     }
6332     /* Interior edge vertices have 2 + faces supports */
6333     for (e = eStart; e < eMax; ++e) {
6334       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
6335       const PetscInt *cone, *support;
6336       PetscInt        size, s;
6337 
6338       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
6339       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
6340       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
6341       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
6342       for (s = 0; s < size; ++s) {
6343         PetscInt r;
6344 
6345         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6346         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
6347         if (support[s] < fMax) {
6348           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*4 + r;
6349         } else {
6350           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (support[s] - fMax);
6351         }
6352       }
6353       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6354 #if 1
6355       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6356       for (p = 0; p < 2+size; ++p) {
6357         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);
6358       }
6359 #endif
6360     }
6361     /* Interior face vertices have 4 + cells supports */
6362     for (f = fStart; f < fMax; ++f) {
6363       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
6364       const PetscInt *cone, *support;
6365       PetscInt        size, s;
6366 
6367       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6368       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6369       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eMax - eStart)*2 +  (f - fStart)*4 + r;
6370       for (s = 0; s < size; ++s) {
6371         PetscInt r;
6372 
6373         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6374         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
6375         if (support[s] < cMax) {
6376           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (support[s] - cStart)*6 + r;
6377         } else {
6378           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax       - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (support[s] - cMax);
6379         }
6380       }
6381       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6382 #if 1
6383       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6384       for (p = 0; p < 4+size; ++p) {
6385         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);
6386       }
6387 #endif
6388     }
6389     /* Cell vertices have 6 supports */
6390     for (c = cStart; c < cMax; ++c) {
6391       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
6392       PetscInt       supportNew[6];
6393 
6394       for (r = 0; r < 6; ++r) {
6395         supportNew[r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
6396       }
6397       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6398     }
6399     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6400     break;
6401   default:
6402     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6403   }
6404   PetscFunctionReturn(0);
6405 }
6406 
6407 static PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6408 {
6409   PetscSection   coordSection, coordSectionNew;
6410   Vec            coordinates, coordinatesNew;
6411   PetscScalar   *coords, *coordsNew;
6412   const PetscInt numVertices = depthSize ? depthSize[0] : 0;
6413   PetscInt       dim, spaceDim, depth, bs, coordSizeNew, cStart, cEnd, cMax, c, vStart, vStartNew, vEnd, v, eStart, eEnd, eMax, e, fStart, fEnd, fMax, f;
6414   VecType        vtype;
6415   PetscErrorCode ierr;
6416 
6417   PetscFunctionBegin;
6418   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6419   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6420   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6421   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6422   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6423   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6424   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, NULL);CHKERRQ(ierr);
6425   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);}
6426   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
6427   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6428   ierr = PetscSectionGetFieldComponents(coordSection, 0, &spaceDim);CHKERRQ(ierr);
6429   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
6430   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
6431   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, spaceDim);CHKERRQ(ierr);
6432   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+numVertices);CHKERRQ(ierr);
6433   if (cMax < 0) cMax = cEnd;
6434   if (fMax < 0) fMax = fEnd;
6435   if (eMax < 0) eMax = eEnd;
6436   /* All vertices have the spaceDim coordinates */
6437   for (v = vStartNew; v < vStartNew+numVertices; ++v) {
6438     ierr = PetscSectionSetDof(coordSectionNew, v, spaceDim);CHKERRQ(ierr);
6439     ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, spaceDim);CHKERRQ(ierr);
6440   }
6441   ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
6442   ierr = DMSetCoordinateSection(rdm, PETSC_DETERMINE, coordSectionNew);CHKERRQ(ierr);
6443   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6444   ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
6445   ierr = VecCreate(PETSC_COMM_SELF, &coordinatesNew);CHKERRQ(ierr);
6446   ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
6447   ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
6448   ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr);
6449   ierr = VecSetBlockSize(coordinatesNew, bs);CHKERRQ(ierr);
6450   ierr = VecGetType(coordinates, &vtype);CHKERRQ(ierr);
6451   ierr = VecSetType(coordinatesNew, vtype);CHKERRQ(ierr);
6452   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
6453   ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6454   switch (refiner) {
6455   case REFINER_NOOP: break;
6456   case REFINER_SIMPLEX_TO_HEX_3D:
6457   case REFINER_HEX_3D:
6458   case REFINER_HYBRID_HEX_3D:
6459     /* Face vertices have the average of corner coordinates */
6460     for (f = fStart; f < fMax; ++f) {
6461       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
6462       PetscInt      *cone = NULL;
6463       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
6464 
6465       ierr = DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6466       for (p = 0; p < closureSize*2; p += 2) {
6467         const PetscInt point = cone[p];
6468         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
6469       }
6470       for (v = 0; v < coneSize; ++v) {
6471         ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
6472       }
6473       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6474       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
6475       for (v = 0; v < coneSize; ++v) {ierr = DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);CHKERRQ(ierr);}
6476       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
6477       ierr = DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6478     }
6479   case REFINER_SIMPLEX_TO_HEX_2D:
6480   case REFINER_HEX_2D:
6481   case REFINER_HYBRID_HEX_2D:
6482   case REFINER_SIMPLEX_1D:
6483     /* Cell vertices have the average of corner coordinates */
6484     for (c = cStart; c < cMax; ++c) {
6485       const PetscInt newv = vStartNew + (vEnd - vStart) + (dim > 1 ? (eMax - eStart) : 0) + (c - cStart) + (dim > 2 ? (fMax - fStart) : 0);
6486       PetscInt      *cone = NULL;
6487       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
6488 
6489       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6490       for (p = 0; p < closureSize*2; p += 2) {
6491         const PetscInt point = cone[p];
6492         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
6493       }
6494       for (v = 0; v < coneSize; ++v) {
6495         ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
6496       }
6497       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6498       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
6499       for (v = 0; v < coneSize; ++v) {ierr = DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);CHKERRQ(ierr);}
6500       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
6501       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6502     }
6503   case REFINER_SIMPLEX_2D:
6504   case REFINER_HYBRID_SIMPLEX_2D:
6505   case REFINER_SIMPLEX_3D:
6506   case REFINER_HYBRID_SIMPLEX_3D:
6507     /* Edge vertices have the average of endpoint coordinates */
6508     for (e = eStart; e < eMax; ++e) {
6509       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
6510       const PetscInt *cone;
6511       PetscInt        coneSize, offA, offB, offnew, d;
6512 
6513       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
6514       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
6515       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6516       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6517       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6518       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6519       ierr = DMLocalizeCoordinate_Internal(dm, spaceDim, &coords[offA], &coords[offB], &coordsNew[offnew]);CHKERRQ(ierr);
6520       for (d = 0; d < spaceDim; ++d) {
6521         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coordsNew[offnew+d]);
6522       }
6523     }
6524     /* Old vertices have the same coordinates */
6525     for (v = vStart; v < vEnd; ++v) {
6526       const PetscInt newv = vStartNew + (v - vStart);
6527       PetscInt       off, offnew, d;
6528 
6529       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6530       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6531       for (d = 0; d < spaceDim; ++d) {
6532         coordsNew[offnew+d] = coords[off+d];
6533       }
6534     }
6535     break;
6536   default:
6537     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6538   }
6539   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
6540   ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6541   ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
6542   ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
6543   ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
6544   if (dm->maxCell) {
6545     const PetscReal *maxCell, *L;
6546     const DMBoundaryType *bd;
6547     ierr = DMGetPeriodicity(dm,  &maxCell, &L, &bd);CHKERRQ(ierr);
6548     ierr = DMSetPeriodicity(rdm,  maxCell,  L,  bd);CHKERRQ(ierr);
6549   }
6550   PetscFunctionReturn(0);
6551 }
6552 
6553 /*@
6554   DMPlexCreateProcessSF - Create an SF which just has process connectivity
6555 
6556   Collective on DM
6557 
6558   Input Parameters:
6559 + dm      - The DM
6560 - sfPoint - The PetscSF which encodes point connectivity
6561 
6562   Output Parameters:
6563 + processRanks - A list of process neighbors, or NULL
6564 - sfProcess    - An SF encoding the process connectivity, or NULL
6565 
6566   Level: developer
6567 
6568 .seealso: PetscSFCreate(), DMPlexCreateTwoSidedProcessSF()
6569 @*/
6570 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
6571 {
6572   PetscInt           numRoots, numLeaves, l;
6573   const PetscInt    *localPoints;
6574   const PetscSFNode *remotePoints;
6575   PetscInt          *localPointsNew;
6576   PetscSFNode       *remotePointsNew;
6577   PetscInt          *ranks, *ranksNew;
6578   PetscMPIInt        size;
6579   PetscErrorCode     ierr;
6580 
6581   PetscFunctionBegin;
6582   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6583   PetscValidHeaderSpecific(sfPoint, PETSCSF_CLASSID, 2);
6584   if (processRanks) {PetscValidPointer(processRanks, 3);}
6585   if (sfProcess)    {PetscValidPointer(sfProcess, 4);}
6586   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) dm), &size);CHKERRQ(ierr);
6587   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6588   ierr = PetscMalloc1(numLeaves, &ranks);CHKERRQ(ierr);
6589   for (l = 0; l < numLeaves; ++l) {
6590     ranks[l] = remotePoints[l].rank;
6591   }
6592   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
6593   ierr = PetscMalloc1(numLeaves, &ranksNew);CHKERRQ(ierr);
6594   ierr = PetscMalloc1(numLeaves, &localPointsNew);CHKERRQ(ierr);
6595   ierr = PetscMalloc1(numLeaves, &remotePointsNew);CHKERRQ(ierr);
6596   for (l = 0; l < numLeaves; ++l) {
6597     ranksNew[l]              = ranks[l];
6598     localPointsNew[l]        = l;
6599     remotePointsNew[l].index = 0;
6600     remotePointsNew[l].rank  = ranksNew[l];
6601   }
6602   ierr = PetscFree(ranks);CHKERRQ(ierr);
6603   if (processRanks) {ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);}
6604   else              {ierr = PetscFree(ranksNew);CHKERRQ(ierr);}
6605   if (sfProcess) {
6606     ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
6607     ierr = PetscObjectSetName((PetscObject) *sfProcess, "Process SF");CHKERRQ(ierr);
6608     ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
6609     ierr = PetscSFSetGraph(*sfProcess, size, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6610   }
6611   PetscFunctionReturn(0);
6612 }
6613 
6614 static PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6615 {
6616   PetscSF            sf, sfNew, sfProcess;
6617   IS                 processRanks;
6618   MPI_Datatype       depthType;
6619   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
6620   const PetscInt    *localPoints, *neighbors;
6621   const PetscSFNode *remotePoints;
6622   PetscInt          *localPointsNew;
6623   PetscSFNode       *remotePointsNew;
6624   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
6625   PetscInt           ldepth, depth, numNeighbors, pStartNew, pEndNew, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r, n;
6626   PetscInt           cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
6627   PetscErrorCode     ierr;
6628 
6629   PetscFunctionBegin;
6630   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
6631   ierr = DMPlexGetDepth(dm, &ldepth);CHKERRQ(ierr);
6632   ierr = MPIU_Allreduce(&ldepth, &depth, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
6633   if ((ldepth >= 0) && (depth != ldepth)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent Plex depth %d != %d", ldepth, depth);
6634   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6635   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6636   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6637   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6638   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6639   cMax = cMax < 0 ? cEnd : cMax;
6640   fMax = fMax < 0 ? fEnd : fMax;
6641   eMax = eMax < 0 ? eEnd : eMax;
6642   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
6643   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
6644   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
6645   /* Calculate size of new SF */
6646   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6647   if (numRoots < 0) PetscFunctionReturn(0);
6648   for (l = 0; l < numLeaves; ++l) {
6649     const PetscInt p = localPoints[l];
6650 
6651     switch (refiner) {
6652     case REFINER_SIMPLEX_1D:
6653       if ((p >= vStart) && (p < vEnd)) {
6654         /* Interior vertices stay the same */
6655         ++numLeavesNew;
6656       } else if ((p >= cStart && p < cMax)) {
6657         /* Interior cells add new cells and interior vertices */
6658         numLeavesNew += 2 + 1;
6659       }
6660       break;
6661     case REFINER_SIMPLEX_2D:
6662     case REFINER_HYBRID_SIMPLEX_2D:
6663       if ((p >= vStart) && (p < vEnd)) {
6664         /* Interior vertices stay the same */
6665         ++numLeavesNew;
6666       } else if ((p >= fStart) && (p < fMax)) {
6667         /* Interior faces add new faces and vertex */
6668         numLeavesNew += 2 + 1;
6669       } else if ((p >= fMax) && (p < fEnd)) {
6670         /* Hybrid faces stay the same */
6671         ++numLeavesNew;
6672       } else if ((p >= cStart) && (p < cMax)) {
6673         /* Interior cells add new cells and interior faces */
6674         numLeavesNew += 4 + 3;
6675       } else if ((p >= cMax) && (p < cEnd)) {
6676         /* Hybrid cells add new cells and hybrid face */
6677         numLeavesNew += 2 + 1;
6678       }
6679       break;
6680     case REFINER_SIMPLEX_TO_HEX_2D:
6681       if ((p >= vStart) && (p < vEnd)) {
6682         /* Interior vertices stay the same */
6683         ++numLeavesNew;
6684       } else if ((p >= fStart) && (p < fEnd)) {
6685         /* Interior faces add new faces and vertex */
6686         numLeavesNew += 2 + 1;
6687       } else if ((p >= cStart) && (p < cEnd)) {
6688         /* Interior cells add new cells, interior faces, and vertex */
6689         numLeavesNew += 3 + 3 + 1;
6690       }
6691       break;
6692     case REFINER_HEX_2D:
6693     case REFINER_HYBRID_HEX_2D:
6694       if ((p >= vStart) && (p < vEnd)) {
6695         /* Interior vertices stay the same */
6696         ++numLeavesNew;
6697       } else if ((p >= fStart) && (p < fMax)) {
6698         /* Interior faces add new faces and vertex */
6699         numLeavesNew += 2 + 1;
6700       } else if ((p >= fMax) && (p < fEnd)) {
6701         /* Hybrid faces stay the same */
6702         ++numLeavesNew;
6703       } else if ((p >= cStart) && (p < cMax)) {
6704         /* Interior cells add new cells, interior faces, and vertex */
6705         numLeavesNew += 4 + 4 + 1;
6706       } else if ((p >= cMax) && (p < cEnd)) {
6707         /* Hybrid cells add new cells and hybrid face */
6708         numLeavesNew += 2 + 1;
6709       }
6710       break;
6711     case REFINER_SIMPLEX_3D:
6712     case REFINER_HYBRID_SIMPLEX_3D:
6713       if ((p >= vStart) && (p < vEnd)) {
6714         /* Interior vertices stay the same */
6715         ++numLeavesNew;
6716       } else if ((p >= eStart) && (p < eMax)) {
6717         /* Interior edges add new edges and vertex */
6718         numLeavesNew += 2 + 1;
6719       } else if ((p >= eMax) && (p < eEnd)) {
6720         /* Hybrid edges stay the same */
6721         ++numLeavesNew;
6722       } else if ((p >= fStart) && (p < fMax)) {
6723         /* Interior faces add new faces and edges */
6724         numLeavesNew += 4 + 3;
6725       } else if ((p >= fMax) && (p < fEnd)) {
6726         /* Hybrid faces add new faces and edges */
6727         numLeavesNew += 2 + 1;
6728       } else if ((p >= cStart) && (p < cMax)) {
6729         /* Interior cells add new cells, faces, and edges */
6730         numLeavesNew += 8 + 8 + 1;
6731       } else if ((p >= cMax) && (p < cEnd)) {
6732         /* Hybrid cells add new cells and faces */
6733         numLeavesNew += 4 + 3;
6734       }
6735       break;
6736     case REFINER_SIMPLEX_TO_HEX_3D:
6737       if ((p >= vStart) && (p < vEnd)) {
6738         /* Interior vertices stay the same */
6739         ++numLeavesNew;
6740       } else if ((p >= eStart) && (p < eEnd)) {
6741         /* Interior edges add new edges and vertex */
6742         numLeavesNew += 2 + 1;
6743       } else if ((p >= fStart) && (p < fEnd)) {
6744         /* Interior faces add new faces, edges and a vertex */
6745         numLeavesNew += 3 + 3 + 1;
6746       } else if ((p >= cStart) && (p < cEnd)) {
6747         /* Interior cells add new cells, faces, edges and a vertex */
6748         numLeavesNew += 4 + 6 + 4 + 1;
6749       }
6750       break;
6751     case REFINER_HEX_3D:
6752     case REFINER_HYBRID_HEX_3D:
6753       if ((p >= vStart) && (p < vEnd)) {
6754         /* Old vertices stay the same */
6755         ++numLeavesNew;
6756       } else if ((p >= eStart) && (p < eMax)) {
6757         /* Interior edges add new edges, and vertex */
6758         numLeavesNew += 2 + 1;
6759       } else if ((p >= eMax) && (p < eEnd)) {
6760         /* Hybrid edges stay the same */
6761         ++numLeavesNew;
6762       } else if ((p >= fStart) && (p < fMax)) {
6763         /* Interior faces add new faces, edges, and vertex */
6764         numLeavesNew += 4 + 4 + 1;
6765       } else if ((p >= fMax) && (p < fEnd)) {
6766         /* Hybrid faces add new faces and edges */
6767         numLeavesNew += 2 + 1;
6768       } else if ((p >= cStart) && (p < cMax)) {
6769         /* Interior cells add new cells, faces, edges, and vertex */
6770         numLeavesNew += 8 + 12 + 6 + 1;
6771       } else if ((p >= cStart) && (p < cEnd)) {
6772         /* Hybrid cells add new cells, faces, and edges */
6773         numLeavesNew += 4 + 4 + 1;
6774       }
6775       break;
6776     default:
6777       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6778     }
6779   }
6780   /* Communicate depthSizes for each remote rank */
6781   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
6782   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
6783   ierr = PetscMalloc5((depth+1)*numNeighbors,&rdepthSize,numNeighbors,&rvStartNew,numNeighbors,&reStartNew,numNeighbors,&rfStartNew,numNeighbors,&rcStartNew);CHKERRQ(ierr);
6784   ierr = PetscMalloc7(depth+1,&depthSizeOld,(depth+1)*numNeighbors,&rdepthSizeOld,(depth+1)*numNeighbors,&rdepthMaxOld,numNeighbors,&rvStart,numNeighbors,&reStart,numNeighbors,&rfStart,numNeighbors,&rcStart);CHKERRQ(ierr);
6785   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
6786   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
6787   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
6788   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
6789   for (n = 0; n < numNeighbors; ++n) {
6790     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
6791   }
6792   depthSizeOld[depth]   = cMax;
6793   depthSizeOld[0]       = vMax;
6794   depthSizeOld[depth-1] = fMax;
6795   depthSizeOld[1]       = eMax;
6796 
6797   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
6798   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
6799 
6800   depthSizeOld[depth]   = cEnd - cStart;
6801   depthSizeOld[0]       = vEnd - vStart;
6802   depthSizeOld[depth-1] = fEnd - fStart;
6803   depthSizeOld[1]       = eEnd - eStart;
6804 
6805   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
6806   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
6807   for (n = 0; n < numNeighbors; ++n) {
6808     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
6809     rdepthMaxOld[n*(depth+1)+depth]   = rdepthMaxOld[n*(depth+1)+depth]   < 0 ? rdepthSizeOld[n*(depth+1)+depth]  +rcStart[n]: rdepthMaxOld[n*(depth+1)+depth];
6810     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];
6811     rdepthMaxOld[n*(depth+1)+1]       = rdepthMaxOld[n*(depth+1)+1]       < 0 ? rdepthSizeOld[n*(depth+1)+1]      +reStart[n]: rdepthMaxOld[n*(depth+1)+1];
6812   }
6813   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
6814   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
6815   /* Calculate new point SF */
6816   ierr = PetscMalloc1(numLeavesNew, &localPointsNew);CHKERRQ(ierr);
6817   ierr = PetscMalloc1(numLeavesNew, &remotePointsNew);CHKERRQ(ierr);
6818   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
6819   for (l = 0, m = 0; l < numLeaves; ++l) {
6820     PetscInt    p     = localPoints[l];
6821     PetscInt    rp    = remotePoints[l].index, n;
6822     PetscMPIInt rrank = remotePoints[l].rank;
6823 
6824     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
6825     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
6826     switch (refiner) {
6827     case REFINER_SIMPLEX_1D:
6828       if ((p >= vStart) && (p < vEnd)) {
6829         /* Old vertices stay the same */
6830         localPointsNew[m]        = vStartNew     + (p  - vStart);
6831         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6832         remotePointsNew[m].rank  = rrank;
6833         ++m;
6834       } else if ((p >= cStart) && (p < cMax)) {
6835         /* Old interior cells add new cells and vertex */
6836         for (r = 0; r < 2; ++r, ++m) {
6837           localPointsNew[m]        = cStartNew     + (p  - cStart)*2     + r;
6838           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*2 + r;
6839           remotePointsNew[m].rank  = rrank;
6840         }
6841         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - cStart);
6842         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rcStart[n]);
6843         remotePointsNew[m].rank  = rrank;
6844         ++m;
6845       }
6846       break;
6847     case REFINER_SIMPLEX_2D:
6848     case REFINER_HYBRID_SIMPLEX_2D:
6849       if ((p >= vStart) && (p < vEnd)) {
6850         /* Old vertices stay the same */
6851         localPointsNew[m]        = vStartNew     + (p  - vStart);
6852         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6853         remotePointsNew[m].rank  = rrank;
6854         ++m;
6855       } else if ((p >= fStart) && (p < fMax)) {
6856         /* Old interior faces add new faces and vertex */
6857         for (r = 0; r < 2; ++r, ++m) {
6858           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6859           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6860           remotePointsNew[m].rank  = rrank;
6861         }
6862         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6863         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6864         remotePointsNew[m].rank  = rrank;
6865         ++m;
6866       } else if ((p >= fMax) && (p < fEnd)) {
6867         /* Old hybrid faces stay the same */
6868         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
6869         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
6870         remotePointsNew[m].rank  = rrank;
6871         ++m;
6872       } else if ((p >= cStart) && (p < cMax)) {
6873         /* Old interior cells add new cells and interior faces */
6874         for (r = 0; r < 4; ++r, ++m) {
6875           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6876           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6877           remotePointsNew[m].rank  = rrank;
6878         }
6879         for (r = 0; r < 3; ++r, ++m) {
6880           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
6881           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
6882           remotePointsNew[m].rank  = rrank;
6883         }
6884       } else if ((p >= cMax) && (p < cEnd)) {
6885         /* Old hybrid cells add new cells and hybrid face */
6886         for (r = 0; r < 2; ++r, ++m) {
6887           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6888           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6889           remotePointsNew[m].rank  = rrank;
6890         }
6891         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
6892         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]);
6893         remotePointsNew[m].rank  = rrank;
6894         ++m;
6895       }
6896       break;
6897     case REFINER_SIMPLEX_TO_HEX_2D:
6898       if ((p >= vStart) && (p < vEnd)) {
6899         /* Old vertices stay the same */
6900         localPointsNew[m]        = vStartNew     + (p  - vStart);
6901         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6902         remotePointsNew[m].rank  = rrank;
6903         ++m;
6904       } else if ((p >= fStart) && (p < fEnd)) {
6905         /* Old interior faces add new faces and vertex */
6906         for (r = 0; r < 2; ++r, ++m) {
6907           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6908           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6909           remotePointsNew[m].rank  = rrank;
6910         }
6911         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6912         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6913         remotePointsNew[m].rank  = rrank;
6914         ++m;
6915       } else if ((p >= cStart) && (p < cEnd)) {
6916         /* Old interior cells add new cells, interior faces, and a vertex */
6917         for (r = 0; r < 3; ++r, ++m) {
6918           localPointsNew[m]        = cStartNew     + (p  - cStart)*3     + r;
6919           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*3 + r;
6920           remotePointsNew[m].rank  = rrank;
6921         }
6922         for (r = 0; r < 3; ++r, ++m) {
6923           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
6924           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
6925           remotePointsNew[m].rank  = rrank;
6926         }
6927         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (fEnd - fStart)                    + (p  - cStart);
6928         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
6929         remotePointsNew[m].rank  = rrank;
6930         ++m;
6931       }
6932       break;
6933     case REFINER_HEX_2D:
6934     case REFINER_HYBRID_HEX_2D:
6935       if ((p >= vStart) && (p < vEnd)) {
6936         /* Old vertices stay the same */
6937         localPointsNew[m]        = vStartNew     + (p  - vStart);
6938         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6939         remotePointsNew[m].rank  = rrank;
6940         ++m;
6941       } else if ((p >= fStart) && (p < fMax)) {
6942         /* Old interior faces add new faces and vertex */
6943         for (r = 0; r < 2; ++r, ++m) {
6944           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6945           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6946           remotePointsNew[m].rank  = rrank;
6947         }
6948         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6949         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6950         remotePointsNew[m].rank  = rrank;
6951         ++m;
6952       } else if ((p >= fMax) && (p < fEnd)) {
6953         /* Old hybrid faces stay the same */
6954         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
6955         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
6956         remotePointsNew[m].rank  = rrank;
6957         ++m;
6958       } else if ((p >= cStart) && (p < cMax)) {
6959         /* Old interior cells add new cells, interior faces, and vertex */
6960         for (r = 0; r < 4; ++r, ++m) {
6961           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6962           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6963           remotePointsNew[m].rank  = rrank;
6964         }
6965         for (r = 0; r < 4; ++r, ++m) {
6966           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*4     + r;
6967           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*4 + r;
6968           remotePointsNew[m].rank  = rrank;
6969         }
6970         localPointsNew[m]        = vStartNew     + (vEnd - vStart)               + (fMax                              - fStart)     + (p  - cStart);
6971         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0]  + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]);
6972         remotePointsNew[m].rank  = rrank;
6973         ++m;
6974       } else if ((p >= cStart) && (p < cMax)) {
6975         /* Old hybrid cells add new cells and hybrid face */
6976         for (r = 0; r < 2; ++r, ++m) {
6977           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6978           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6979           remotePointsNew[m].rank  = rrank;
6980         }
6981         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*4     + (p  - cMax);
6982         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]);
6983         remotePointsNew[m].rank  = rrank;
6984         ++m;
6985       }
6986       break;
6987     case REFINER_SIMPLEX_3D:
6988     case REFINER_HYBRID_SIMPLEX_3D:
6989       if ((p >= vStart) && (p < vEnd)) {
6990         /* Interior vertices stay the same */
6991         localPointsNew[m]        = vStartNew     + (p  - vStart);
6992         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6993         remotePointsNew[m].rank  = rrank;
6994         ++m;
6995       } else if ((p >= eStart) && (p < eMax)) {
6996         /* Interior edges add new edges and vertex */
6997         for (r = 0; r < 2; ++r, ++m) {
6998           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
6999           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
7000           remotePointsNew[m].rank  = rrank;
7001         }
7002         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
7003         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
7004         remotePointsNew[m].rank  = rrank;
7005         ++m;
7006       } else if ((p >= eMax) && (p < eEnd)) {
7007         /* Hybrid edges stay the same */
7008         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - eMax);
7009         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]);
7010         remotePointsNew[m].rank  = rrank;
7011         ++m;
7012       } else if ((p >= fStart) && (p < fMax)) {
7013         /* Interior faces add new faces and edges */
7014         for (r = 0; r < 4; ++r, ++m) {
7015           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
7016           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
7017           remotePointsNew[m].rank  = rrank;
7018         }
7019         for (r = 0; r < 3; ++r, ++m) {
7020           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*3     + r;
7021           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
7022           remotePointsNew[m].rank  = rrank;
7023         }
7024       } else if ((p >= fMax) && (p < fEnd)) {
7025         /* Hybrid faces add new faces and edges */
7026         for (r = 0; r < 2; ++r, ++m) {
7027           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fMax)*2                              + r;
7028           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;
7029           remotePointsNew[m].rank  = rrank;
7030         }
7031         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (eEnd                                    - eMax)                        + (p  - fMax);
7032         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]);
7033         remotePointsNew[m].rank  = rrank;
7034         ++m;
7035       } else if ((p >= cStart) && (p < cMax)) {
7036         /* Interior cells add new cells, faces, and edges */
7037         for (r = 0; r < 8; ++r, ++m) {
7038           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
7039           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
7040           remotePointsNew[m].rank  = rrank;
7041         }
7042         for (r = 0; r < 8; ++r, ++m) {
7043           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*8     + r;
7044           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*8 + r;
7045           remotePointsNew[m].rank  = rrank;
7046         }
7047         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (p  - cStart)*1     + 0;
7048         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;
7049         remotePointsNew[m].rank  = rrank;
7050         ++m;
7051       } else if ((p >= cMax) && (p < cEnd)) {
7052         /* Hybrid cells add new cells and faces */
7053         for (r = 0; r < 4; ++r, ++m) {
7054           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
7055           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
7056           remotePointsNew[m].rank  = rrank;
7057         }
7058         for (r = 0; r < 3; ++r, ++m) {
7059           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*2                              + (p  - cMax)*3                            + r;
7060           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;
7061           remotePointsNew[m].rank  = rrank;
7062         }
7063       }
7064       break;
7065     case REFINER_SIMPLEX_TO_HEX_3D:
7066       if ((p >= vStart) && (p < vEnd)) {
7067         /* Interior vertices stay the same */
7068         localPointsNew[m]        = vStartNew     + (p  - vStart);
7069         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7070         remotePointsNew[m].rank  = rrank;
7071         ++m;
7072       } else if ((p >= eStart) && (p < eEnd)) {
7073         /* Interior edges add new edges and vertex */
7074         for (r = 0; r < 2; ++r, ++m) {
7075           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
7076           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
7077           remotePointsNew[m].rank  = rrank;
7078         }
7079         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
7080         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
7081         remotePointsNew[m].rank  = rrank;
7082         ++m;
7083       } else if ((p >= fStart) && (p < fEnd)) {
7084         /* Interior faces add new faces, edges and a vertex */
7085         for (r = 0; r < 3; ++r, ++m) {
7086           localPointsNew[m]        = fStartNew     + (p  - fStart)*3     + r;
7087           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*3 + r;
7088           remotePointsNew[m].rank  = rrank;
7089         }
7090         for (r = 0; r < 3; ++r, ++m) {
7091           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2                + (p  - fStart)*3     + r;
7092           remotePointsNew[m].index = reStartNew[n] + (rdepthSizeOld[n*(depth+1)+1])*2 + (rp - rfStart[n])*3 + r;
7093           remotePointsNew[m].rank  = rrank;
7094         }
7095         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eEnd - eStart)              + (p - fStart);
7096         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+1] + (rp - rfStart[n]);
7097         remotePointsNew[m].rank  = rrank;
7098         ++m;
7099       } else if ((p >= cStart) && (p < cEnd)) {
7100         /* Interior cells add new cells, faces, edges, and a vertex */
7101         for (r = 0; r < 4; ++r, ++m) {
7102           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7103           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7104           remotePointsNew[m].rank  = rrank;
7105         }
7106         for (r = 0; r < 6; ++r, ++m) {
7107           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*3                    + (p  - cStart)*6     + r;
7108           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*3 + (rp - rcStart[n])*6 + r;
7109           remotePointsNew[m].rank  = rrank;
7110         }
7111         for (r = 0; r < 4; ++r, ++m) {
7112           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (fEnd - fStart)*3                    + (p  - cStart)*4 + r;
7113           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + rdepthSizeOld[n*(depth+1)+depth-1]*3 + (rp - rcStart[n])*4 + r;
7114           remotePointsNew[m].rank  = rrank;
7115         }
7116         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eEnd - eStart)              + (fEnd - fStart)                    + (p - cStart);
7117         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+1] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
7118         remotePointsNew[m].rank  = rrank;
7119         ++m;
7120       }
7121       break;
7122     case REFINER_HEX_3D:
7123     case REFINER_HYBRID_HEX_3D:
7124       if ((p >= vStart) && (p < vEnd)) {
7125         /* Interior vertices stay the same */
7126         localPointsNew[m]        = vStartNew     + (p  - vStart);
7127         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7128         remotePointsNew[m].rank  = rrank;
7129         ++m;
7130       } else if ((p >= eStart) && (p < eMax)) {
7131         /* Interior edges add new edges and vertex */
7132         for (r = 0; r < 2; ++r, ++m) {
7133           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
7134           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
7135           remotePointsNew[m].rank  = rrank;
7136         }
7137         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
7138         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
7139         remotePointsNew[m].rank  = rrank;
7140         ++m;
7141       } else if ((p >= eMax) && (p < eEnd)) {
7142         /* Hybrid edges stay the same */
7143         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (p  - eMax);
7144         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]);
7145         remotePointsNew[m].rank  = rrank;
7146         ++m;
7147       } else if ((p >= fStart) && (p < fMax)) {
7148         /* Interior faces add new faces, edges, and vertex */
7149         for (r = 0; r < 4; ++r, ++m) {
7150           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
7151           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
7152           remotePointsNew[m].rank  = rrank;
7153         }
7154         for (r = 0; r < 4; ++r, ++m) {
7155           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*4     + r;
7156           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*4 + r;
7157           remotePointsNew[m].rank  = rrank;
7158         }
7159         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax                        - eStart)     + (p  - fStart);
7160         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
7161         remotePointsNew[m].rank  = rrank;
7162         ++m;
7163       } else if ((p >= fMax) && (p < fEnd)) {
7164         /* Hybrid faces add new faces and edges */
7165         for (r = 0; r < 2; ++r, ++m) {
7166           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (p  - fMax)*2                              + r;
7167           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;
7168           remotePointsNew[m].rank  = rrank;
7169         }
7170         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (p  - fMax);
7171         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]);
7172         remotePointsNew[m].rank  = rrank;
7173         ++m;
7174       } else if ((p >= cStart) && (p < cMax)) {
7175         /* Interior cells add new cells, faces, edges, and vertex */
7176         for (r = 0; r < 8; ++r, ++m) {
7177           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
7178           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
7179           remotePointsNew[m].rank  = rrank;
7180         }
7181         for (r = 0; r < 12; ++r, ++m) {
7182           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*12     + r;
7183           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*12 + r;
7184           remotePointsNew[m].rank  = rrank;
7185         }
7186         for (r = 0; r < 6; ++r, ++m) {
7187           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (p  - cStart)*6     + r;
7188           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;
7189           remotePointsNew[m].rank  = rrank;
7190         }
7191         for (r = 0; r < 1; ++r, ++m) {
7192           localPointsNew[m]        = vStartNew     + (eMax                        - eStart)     + (fMax                              - fStart)     + (p  - cStart)     + r;
7193           remotePointsNew[m].index = rvStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]) + r;
7194           remotePointsNew[m].rank  = rrank;
7195         }
7196       } else if ((p >= cMax) && (p < cEnd)) {
7197         /* Hybrid cells add new cells, faces, and edges */
7198         for (r = 0; r < 4; ++r, ++m) {
7199           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
7200           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
7201           remotePointsNew[m].rank  = rrank;
7202         }
7203         for (r = 0; r < 4; ++r, ++m) {
7204           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (fEnd                                          - fMax)*2                              + (p  - cMax)*4                            + r;
7205           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;
7206           remotePointsNew[m].rank  = rrank;
7207         }
7208         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (fEnd                                          - fMax)                              + (p  - cMax);
7209         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]);
7210         remotePointsNew[m].rank  = rrank;
7211         ++m;
7212       }
7213       break;
7214     default:
7215       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7216     }
7217   }
7218   if (m != numLeavesNew) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of leaf point %d should be %d", m, numLeavesNew);
7219   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
7220   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
7221   {
7222     PetscSFNode *rp, *rtmp;
7223     PetscInt    *lp, *idx, *ltmp, i;
7224 
7225     /* SF needs sorted leaves to correct calculate Gather */
7226     ierr = PetscMalloc1(numLeavesNew,&idx);CHKERRQ(ierr);
7227     ierr = PetscMalloc1(numLeavesNew, &lp);CHKERRQ(ierr);
7228     ierr = PetscMalloc1(numLeavesNew, &rp);CHKERRQ(ierr);
7229     for (i = 0; i < numLeavesNew; ++i) {
7230       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);
7231       idx[i] = i;
7232     }
7233     ierr = PetscSortIntWithPermutation(numLeavesNew, localPointsNew, idx);CHKERRQ(ierr);
7234     for (i = 0; i < numLeavesNew; ++i) {
7235       lp[i] = localPointsNew[idx[i]];
7236       rp[i] = remotePointsNew[idx[i]];
7237     }
7238     ltmp            = localPointsNew;
7239     localPointsNew  = lp;
7240     rtmp            = remotePointsNew;
7241     remotePointsNew = rp;
7242     ierr = PetscFree(idx);CHKERRQ(ierr);
7243     ierr = PetscFree(ltmp);CHKERRQ(ierr);
7244     ierr = PetscFree(rtmp);CHKERRQ(ierr);
7245   }
7246   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7247   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
7248   ierr = PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
7249   PetscFunctionReturn(0);
7250 }
7251 
7252 static PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7253 {
7254   PetscInt       numLabels, l;
7255   PetscInt       depth, newp, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r;
7256   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
7257   PetscErrorCode ierr;
7258 
7259   PetscFunctionBegin;
7260   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7261   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7262   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7263   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7264   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7265   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
7266   ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
7267   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7268   switch (refiner) {
7269   case REFINER_NOOP:
7270   case REFINER_SIMPLEX_1D:
7271   case REFINER_SIMPLEX_2D:
7272   case REFINER_SIMPLEX_TO_HEX_2D:
7273   case REFINER_HEX_2D:
7274   case REFINER_SIMPLEX_3D:
7275   case REFINER_HEX_3D:
7276   case REFINER_SIMPLEX_TO_HEX_3D:
7277     break;
7278   case REFINER_HYBRID_SIMPLEX_3D:
7279   case REFINER_HYBRID_HEX_3D:
7280     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
7281   case REFINER_HYBRID_SIMPLEX_2D:
7282   case REFINER_HYBRID_HEX_2D:
7283     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7284     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7285     break;
7286   default:
7287     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7288   }
7289   for (l = 0; l < numLabels; ++l) {
7290     DMLabel         label, labelNew;
7291     const char     *lname;
7292     PetscBool       isDepth;
7293     IS              valueIS;
7294     const PetscInt *values;
7295     PetscInt        defVal;
7296     PetscInt        numValues, val;
7297 
7298     ierr = DMGetLabelName(dm, l, &lname);CHKERRQ(ierr);
7299     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
7300     if (isDepth) continue;
7301     ierr = DMCreateLabel(rdm, lname);CHKERRQ(ierr);
7302     ierr = DMGetLabel(dm, lname, &label);CHKERRQ(ierr);
7303     ierr = DMGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
7304     ierr = DMLabelGetDefaultValue(label,&defVal);CHKERRQ(ierr);
7305     ierr = DMLabelSetDefaultValue(labelNew,defVal);CHKERRQ(ierr);
7306     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
7307     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
7308     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
7309     for (val = 0; val < numValues; ++val) {
7310       IS              pointIS;
7311       const PetscInt *points;
7312       PetscInt        numPoints, n;
7313 
7314       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
7315       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
7316       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
7317       /* Ensure refined label is created with same number of strata as
7318        * original (even if no entries here). */
7319       ierr = DMLabelAddStratum(labelNew, values[val]);CHKERRQ(ierr);
7320       for (n = 0; n < numPoints; ++n) {
7321         const PetscInt p = points[n];
7322         switch (refiner) {
7323         case REFINER_SIMPLEX_1D:
7324           if ((p >= vStart) && (p < vEnd)) {
7325             /* Old vertices stay the same */
7326             newp = vStartNew + (p - vStart);
7327             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7328           } else if ((p >= cStart) && (p < cEnd)) {
7329             /* Old cells add new cells and vertex */
7330             newp = vStartNew + (vEnd - vStart) + (p - cStart);
7331             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7332             for (r = 0; r < 2; ++r) {
7333               newp = cStartNew + (p - cStart)*2 + r;
7334               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7335             }
7336           }
7337           break;
7338         case REFINER_SIMPLEX_2D:
7339           if ((p >= vStart) && (p < vEnd)) {
7340             /* Old vertices stay the same */
7341             newp = vStartNew + (p - vStart);
7342             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7343           } else if ((p >= fStart) && (p < fEnd)) {
7344             /* Old faces add new faces and vertex */
7345             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7346             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7347             for (r = 0; r < 2; ++r) {
7348               newp = fStartNew + (p - fStart)*2 + r;
7349               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7350             }
7351           } else if ((p >= cStart) && (p < cEnd)) {
7352             /* Old cells add new cells and interior faces */
7353             for (r = 0; r < 4; ++r) {
7354               newp = cStartNew + (p - cStart)*4 + r;
7355               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7356             }
7357             for (r = 0; r < 3; ++r) {
7358               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7359               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7360             }
7361           }
7362           break;
7363         case REFINER_SIMPLEX_TO_HEX_2D:
7364           if ((p >= vStart) && (p < vEnd)) {
7365             /* Old vertices stay the same */
7366             newp = vStartNew + (p - vStart);
7367             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7368           } else if ((p >= fStart) && (p < fEnd)) {
7369             /* Old faces add new faces and vertex */
7370             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7371             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7372             for (r = 0; r < 2; ++r) {
7373               newp = fStartNew + (p - fStart)*2 + r;
7374               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7375             }
7376           } else if ((p >= cStart) && (p < cEnd)) {
7377             /* Old cells add new cells, interior faces, and a vertex */
7378             for (r = 0; r < 3; ++r) {
7379               newp = cStartNew + (p - cStart)*3 + r;
7380               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7381             }
7382             for (r = 0; r < 3; ++r) {
7383               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7384               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7385             }
7386             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + p;
7387             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7388           }
7389           break;
7390         case REFINER_HEX_2D:
7391           if ((p >= vStart) && (p < vEnd)) {
7392             /* Old vertices stay the same */
7393             newp = vStartNew + (p - vStart);
7394             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7395           } else if ((p >= fStart) && (p < fEnd)) {
7396             /* Old faces add new faces and vertex */
7397             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7398             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7399             for (r = 0; r < 2; ++r) {
7400               newp = fStartNew + (p - fStart)*2 + r;
7401               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7402             }
7403           } else if ((p >= cStart) && (p < cEnd)) {
7404             /* Old cells add new cells and interior faces and vertex */
7405             for (r = 0; r < 4; ++r) {
7406               newp = cStartNew + (p - cStart)*4 + r;
7407               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7408             }
7409             for (r = 0; r < 4; ++r) {
7410               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
7411               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7412             }
7413             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
7414             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7415           }
7416           break;
7417         case REFINER_HYBRID_SIMPLEX_2D:
7418           if ((p >= vStart) && (p < vEnd)) {
7419             /* Old vertices stay the same */
7420             newp = vStartNew + (p - vStart);
7421             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7422           } else if ((p >= fStart) && (p < fMax)) {
7423             /* Old interior faces add new faces and vertex */
7424             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7425             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7426             for (r = 0; r < 2; ++r) {
7427               newp = fStartNew + (p - fStart)*2 + r;
7428               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7429             }
7430           } else if ((p >= fMax) && (p < fEnd)) {
7431             /* Old hybrid faces stay the same */
7432             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7433             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7434           } else if ((p >= cStart) && (p < cMax)) {
7435             /* Old interior cells add new cells and interior faces */
7436             for (r = 0; r < 4; ++r) {
7437               newp = cStartNew + (p - cStart)*4 + r;
7438               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7439             }
7440             for (r = 0; r < 3; ++r) {
7441               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7442               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7443             }
7444           } else if ((p >= cMax) && (p < cEnd)) {
7445             /* Old hybrid cells add new cells and hybrid face */
7446             for (r = 0; r < 2; ++r) {
7447               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
7448               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7449             }
7450             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
7451             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7452           }
7453           break;
7454         case REFINER_HYBRID_HEX_2D:
7455           if ((p >= vStart) && (p < vEnd)) {
7456             /* Old vertices stay the same */
7457             newp = vStartNew + (p - vStart);
7458             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7459           } else if ((p >= fStart) && (p < fMax)) {
7460             /* Old interior faces add new faces and vertex */
7461             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7462             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7463             for (r = 0; r < 2; ++r) {
7464               newp = fStartNew + (p - fStart)*2 + r;
7465               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7466             }
7467           } else if ((p >= fMax) && (p < fEnd)) {
7468             /* Old hybrid faces stay the same */
7469             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7470             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7471           } else if ((p >= cStart) && (p < cMax)) {
7472             /* Old interior cells add new cells, interior faces, and vertex */
7473             for (r = 0; r < 4; ++r) {
7474               newp = cStartNew + (p - cStart)*4 + r;
7475               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7476             }
7477             for (r = 0; r < 4; ++r) {
7478               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
7479               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7480             }
7481             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
7482             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7483           } else if ((p >= cMax) && (p < cEnd)) {
7484             /* Old hybrid cells add new cells and hybrid face */
7485             for (r = 0; r < 2; ++r) {
7486               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
7487               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7488             }
7489             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (p - cMax);
7490             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7491           }
7492           break;
7493         case REFINER_SIMPLEX_3D:
7494           if ((p >= vStart) && (p < vEnd)) {
7495             /* Old vertices stay the same */
7496             newp = vStartNew + (p - vStart);
7497             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7498           } else if ((p >= eStart) && (p < eEnd)) {
7499             /* Old edges add new edges and vertex */
7500             for (r = 0; r < 2; ++r) {
7501               newp = eStartNew + (p - eStart)*2 + r;
7502               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7503             }
7504             newp = vStartNew + (vEnd - vStart) + (p - eStart);
7505             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7506           } else if ((p >= fStart) && (p < fEnd)) {
7507             /* Old faces add new faces and edges */
7508             for (r = 0; r < 4; ++r) {
7509               newp = fStartNew + (p - fStart)*4 + r;
7510               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7511             }
7512             for (r = 0; r < 3; ++r) {
7513               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
7514               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7515             }
7516           } else if ((p >= cStart) && (p < cEnd)) {
7517             /* Old cells add new cells and interior faces and edges */
7518             for (r = 0; r < 8; ++r) {
7519               newp = cStartNew + (p - cStart)*8 + r;
7520               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7521             }
7522             for (r = 0; r < 8; ++r) {
7523               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*8 + r;
7524               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7525             }
7526             for (r = 0; r < 1; ++r) {
7527               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*1 + r;
7528               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7529             }
7530           }
7531           break;
7532         case REFINER_SIMPLEX_TO_HEX_3D:
7533           if ((p >= vStart) && (p < vEnd)) {
7534             /* Old vertices stay the same */
7535             newp = vStartNew + (p - vStart);
7536             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7537           } else if ((p >= eStart) && (p < eEnd)) {
7538             /* Old edges add new edges and vertex */
7539             for (r = 0; r < 2; ++r) {
7540               newp = eStartNew + (p - eStart)*2 + r;
7541               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7542             }
7543             newp = vStartNew + (vEnd - vStart) + (p - eStart);
7544             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7545           } else if ((p >= fStart) && (p < fEnd)) {
7546             /* Old faces add new faces, edges and a vertex */
7547             for (r = 0; r < 3; ++r) {
7548               newp = fStartNew + (p - fStart)*3 + r;
7549               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7550             }
7551             for (r = 0; r < 3; ++r) {
7552               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
7553               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7554             }
7555           } else if ((p >= cStart) && (p < cEnd)) {
7556             /* Old cells add new cells and interior faces and edges and a vertex */
7557             for (r = 0; r < 4; ++r) {
7558               newp = cStartNew + (p - cStart)*4 + r;
7559               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7560             }
7561             for (r = 0; r < 6; ++r) {
7562               newp = fStartNew + (fEnd - fStart)*3 + (p - cStart)*6 + r;
7563               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7564             }
7565             for (r = 0; r < 4; ++r) {
7566               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*4 + r;
7567               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7568             }
7569             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + p - cStart;
7570             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7571           }
7572           break;
7573         case REFINER_HYBRID_SIMPLEX_3D:
7574           if ((p >= vStart) && (p < vEnd)) {
7575             /* Interior vertices stay the same */
7576             newp = vStartNew + (p - vStart);
7577             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7578           } else if ((p >= eStart) && (p < eMax)) {
7579             /* Interior edges add new edges and vertex */
7580             for (r = 0; r < 2; ++r) {
7581               newp = eStartNew + (p - eStart)*2 + r;
7582               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7583             }
7584             newp = vStartNew + (vEnd - vStart) + (p - eStart);
7585             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7586           } else if ((p >= eMax) && (p < eEnd)) {
7587             /* Hybrid edges stay the same */
7588             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - eMax);
7589             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7590           } else if ((p >= fStart) && (p < fMax)) {
7591             /* Interior faces add new faces and edges */
7592             for (r = 0; r < 4; ++r) {
7593               newp = fStartNew + (p - fStart)*4 + r;
7594               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7595             }
7596             for (r = 0; r < 3; ++r) {
7597               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
7598               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7599             }
7600           } else if ((p >= fMax) && (p < fEnd)) {
7601             /* Hybrid faces add new faces and edges */
7602             for (r = 0; r < 2; ++r) {
7603               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (p - fMax)*2 + r;
7604               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7605             }
7606             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - fMax);
7607             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7608           } else if ((p >= cStart) && (p < cMax)) {
7609             /* Interior cells add new cells, faces, and edges */
7610             for (r = 0; r < 8; ++r) {
7611               newp = cStartNew + (p - cStart)*8 + r;
7612               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7613             }
7614             for (r = 0; r < 8; ++r) {
7615               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*8 + r;
7616               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7617             }
7618             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart);
7619             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7620           } else if ((p >= cMax) && (p < cEnd)) {
7621             /* Hybrid cells add new cells and faces */
7622             for (r = 0; r < 4; ++r) {
7623               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
7624               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7625             }
7626             for (r = 0; r < 3; ++r) {
7627               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
7628               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7629             }
7630           }
7631           break;
7632         case REFINER_HEX_3D:
7633           if ((p >= vStart) && (p < vEnd)) {
7634             /* Old vertices stay the same */
7635             newp = vStartNew + (p - vStart);
7636             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7637           } else if ((p >= eStart) && (p < eEnd)) {
7638             /* Old edges add new edges and vertex */
7639             for (r = 0; r < 2; ++r) {
7640               newp = eStartNew + (p - eStart)*2 + r;
7641               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7642             }
7643             newp = vStartNew + (vEnd - vStart) + (p - eStart);
7644             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7645           } else if ((p >= fStart) && (p < fEnd)) {
7646             /* Old faces add new faces, edges, and vertex */
7647             for (r = 0; r < 4; ++r) {
7648               newp = fStartNew + (p - fStart)*4 + r;
7649               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7650             }
7651             for (r = 0; r < 4; ++r) {
7652               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*4 + r;
7653               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7654             }
7655             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (p - fStart);
7656             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7657           } else if ((p >= cStart) && (p < cEnd)) {
7658             /* Old cells add new cells, faces, edges, and vertex */
7659             for (r = 0; r < 8; ++r) {
7660               newp = cStartNew + (p - cStart)*8 + r;
7661               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7662             }
7663             for (r = 0; r < 12; ++r) {
7664               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*12 + r;
7665               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7666             }
7667             for (r = 0; r < 6; ++r) {
7668               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (p - cStart)*6 + r;
7669               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7670             }
7671             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (p - cStart);
7672             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7673           }
7674           break;
7675         case REFINER_HYBRID_HEX_3D:
7676           if ((p >= vStart) && (p < vEnd)) {
7677             /* Interior vertices stay the same */
7678             newp = vStartNew + (p - vStart);
7679             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7680           } else if ((p >= eStart) && (p < eMax)) {
7681             /* Interior edges add new edges and vertex */
7682             for (r = 0; r < 2; ++r) {
7683               newp = eStartNew + (p - eStart)*2 + r;
7684               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7685             }
7686             newp = vStartNew + (vEnd - vStart) + (p - eStart);
7687             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7688           } else if ((p >= eMax) && (p < eEnd)) {
7689             /* Hybrid edges stay the same */
7690             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - eMax);
7691             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7692           } else if ((p >= fStart) && (p < fMax)) {
7693             /* Interior faces add new faces, edges, and vertex */
7694             for (r = 0; r < 4; ++r) {
7695               newp = fStartNew + (p - fStart)*4 + r;
7696               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7697             }
7698             for (r = 0; r < 4; ++r) {
7699               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*4 + r;
7700               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7701             }
7702             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (p - fStart);
7703             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7704           } else if ((p >= fMax) && (p < fEnd)) {
7705             /* Hybrid faces add new faces and edges */
7706             for (r = 0; r < 2; ++r) {
7707               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (p - fMax)*2 + r;
7708               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7709             }
7710             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - fMax);
7711             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7712           } else if ((p >= cStart) && (p < cMax)) {
7713             /* Interior cells add new cells, faces, edges, and vertex */
7714             for (r = 0; r < 8; ++r) {
7715               newp = cStartNew + (p - cStart)*8 + r;
7716               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7717             }
7718             for (r = 0; r < 12; ++r) {
7719               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*12 + r;
7720               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7721             }
7722             for (r = 0; r < 6; ++r) {
7723               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (p - cStart)*6 + r;
7724               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7725             }
7726             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (p - cStart);
7727             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7728           } else if ((p >= cMax) && (p < cEnd)) {
7729             /* Hybrid cells add new cells, faces, and edges */
7730             for (r = 0; r < 4; ++r) {
7731               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
7732               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7733             }
7734             for (r = 0; r < 4; ++r) {
7735               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (p - cMax)*4 + r;
7736               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7737             }
7738             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (fEnd - fMax) + (p - cMax);
7739             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7740           }
7741           break;
7742         default:
7743           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7744         }
7745       }
7746       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
7747       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
7748     }
7749     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
7750     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
7751     if (0) {
7752       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7753     }
7754   }
7755   PetscFunctionReturn(0);
7756 }
7757 
7758 /* This will only work for interpolated meshes */
7759 PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
7760 {
7761   DM             rdm;
7762   PetscInt      *depthSize;
7763   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
7764   PetscErrorCode ierr;
7765 
7766   PetscFunctionBegin;
7767   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
7768   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
7769   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
7770   ierr = DMSetDimension(rdm, dim);CHKERRQ(ierr);
7771   /* Calculate number of new points of each depth */
7772   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7773   if (depth >= 0 && dim != depth) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Mesh must be interpolated for regular refinement");
7774   ierr = PetscMalloc1(depth+1, &depthSize);CHKERRQ(ierr);
7775   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
7776   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
7777   /* Step 1: Set chart */
7778   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
7779   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
7780   /* Step 2: Set cone/support sizes */
7781   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7782   /* Step 3: Setup refined DM */
7783   ierr = DMSetUp(rdm);CHKERRQ(ierr);
7784   /* Step 4: Set cones and supports */
7785   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7786   /* Step 5: Stratify */
7787   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
7788   /* Step 6: Create pointSF */
7789   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7790   /* Step 7: Set coordinates for vertices */
7791   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7792   /* Step 8: Create labels */
7793   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7794   ierr = PetscFree(depthSize);CHKERRQ(ierr);
7795 
7796   *dmRefined = rdm;
7797   PetscFunctionReturn(0);
7798 }
7799 
7800 /*@
7801   DMPlexCreateCoarsePointIS - Creates an IS covering the coarse DM chart with the fine points as data
7802 
7803   Input Parameter:
7804 . dm - The coarse DM
7805 
7806   Output Parameter:
7807 . fpointIS - The IS of all the fine points which exist in the original coarse mesh
7808 
7809   Level: developer
7810 
7811 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexCreateSubpointIS()
7812 @*/
7813 PetscErrorCode DMPlexCreateCoarsePointIS(DM dm, IS *fpointIS)
7814 {
7815   CellRefiner    cellRefiner;
7816   PetscInt      *depthSize, *fpoints;
7817   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
7818   PetscInt       depth, pStart, pEnd, p, vStart, vEnd, v;
7819   PetscErrorCode ierr;
7820 
7821   PetscFunctionBegin;
7822   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7823   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7824   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7825   ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr);
7826   ierr = PetscMalloc1(depth+1, &depthSize);CHKERRQ(ierr);
7827   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
7828   if (cellRefiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
7829   ierr = PetscMalloc1(pEnd-pStart,&fpoints);CHKERRQ(ierr);
7830   for (p = 0; p < pEnd-pStart; ++p) fpoints[p] = -1;
7831   switch (cellRefiner) {
7832   case REFINER_SIMPLEX_1D:
7833   case REFINER_SIMPLEX_2D:
7834   case REFINER_HYBRID_SIMPLEX_2D:
7835   case REFINER_HEX_2D:
7836   case REFINER_HYBRID_HEX_2D:
7837   case REFINER_SIMPLEX_3D:
7838   case REFINER_HYBRID_SIMPLEX_3D:
7839   case REFINER_HEX_3D:
7840   case REFINER_HYBRID_HEX_3D:
7841     for (v = vStart; v < vEnd; ++v) fpoints[v-pStart] = vStartNew + (v - vStart);
7842     break;
7843   default:
7844     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", cellRefiner);
7845   }
7846   ierr = ISCreateGeneral(PETSC_COMM_SELF, pEnd-pStart, fpoints, PETSC_OWN_POINTER, fpointIS);CHKERRQ(ierr);
7847   ierr = PetscFree(depthSize);CHKERRQ(ierr);
7848   PetscFunctionReturn(0);
7849 }
7850 
7851 /*@
7852   DMPlexSetRefinementUniform - Set the flag for uniform refinement
7853 
7854   Input Parameters:
7855 + dm - The DM
7856 - refinementUniform - The flag for uniform refinement
7857 
7858   Level: developer
7859 
7860 .seealso: DMRefine(), DMPlexGetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
7861 @*/
7862 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
7863 {
7864   DM_Plex *mesh = (DM_Plex*) dm->data;
7865 
7866   PetscFunctionBegin;
7867   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7868   mesh->refinementUniform = refinementUniform;
7869   PetscFunctionReturn(0);
7870 }
7871 
7872 /*@
7873   DMPlexGetRefinementUniform - Retrieve the flag for uniform refinement
7874 
7875   Input Parameter:
7876 . dm - The DM
7877 
7878   Output Parameter:
7879 . refinementUniform - The flag for uniform refinement
7880 
7881   Level: developer
7882 
7883 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
7884 @*/
7885 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
7886 {
7887   DM_Plex *mesh = (DM_Plex*) dm->data;
7888 
7889   PetscFunctionBegin;
7890   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7891   PetscValidPointer(refinementUniform,  2);
7892   *refinementUniform = mesh->refinementUniform;
7893   PetscFunctionReturn(0);
7894 }
7895 
7896 /*@
7897   DMPlexSetRefinementLimit - Set the maximum cell volume for refinement
7898 
7899   Input Parameters:
7900 + dm - The DM
7901 - refinementLimit - The maximum cell volume in the refined mesh
7902 
7903   Level: developer
7904 
7905 .seealso: DMRefine(), DMPlexGetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
7906 @*/
7907 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
7908 {
7909   DM_Plex *mesh = (DM_Plex*) dm->data;
7910 
7911   PetscFunctionBegin;
7912   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7913   mesh->refinementLimit = refinementLimit;
7914   PetscFunctionReturn(0);
7915 }
7916 
7917 /*@
7918   DMPlexGetRefinementLimit - Retrieve the maximum cell volume for refinement
7919 
7920   Input Parameter:
7921 . dm - The DM
7922 
7923   Output Parameter:
7924 . refinementLimit - The maximum cell volume in the refined mesh
7925 
7926   Level: developer
7927 
7928 .seealso: DMRefine(), DMPlexSetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
7929 @*/
7930 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
7931 {
7932   DM_Plex *mesh = (DM_Plex*) dm->data;
7933 
7934   PetscFunctionBegin;
7935   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7936   PetscValidPointer(refinementLimit,  2);
7937   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
7938   *refinementLimit = mesh->refinementLimit;
7939   PetscFunctionReturn(0);
7940 }
7941 
7942 /*@
7943   DMPlexSetRefinementFunction - Set the function giving the maximum cell volume for refinement
7944 
7945   Input Parameters:
7946 + dm - The DM
7947 - refinementFunc - Function giving the maximum cell volume in the refined mesh
7948 
7949   Note: The calling sequence is refinementFunc(coords, limit)
7950 $ coords - Coordinates of the current point, usually a cell centroid
7951 $ limit  - The maximum cell volume for a cell containing this point
7952 
7953   Level: developer
7954 
7955 .seealso: DMRefine(), DMPlexGetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
7956 @*/
7957 PetscErrorCode DMPlexSetRefinementFunction(DM dm, PetscErrorCode (*refinementFunc)(const PetscReal [], PetscReal *))
7958 {
7959   DM_Plex *mesh = (DM_Plex*) dm->data;
7960 
7961   PetscFunctionBegin;
7962   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7963   mesh->refinementFunc = refinementFunc;
7964   PetscFunctionReturn(0);
7965 }
7966 
7967 /*@
7968   DMPlexGetRefinementFunction - Get the function giving the maximum cell volume for refinement
7969 
7970   Input Parameter:
7971 . dm - The DM
7972 
7973   Output Parameter:
7974 . refinementFunc - Function giving the maximum cell volume in the refined mesh
7975 
7976   Note: The calling sequence is refinementFunc(coords, limit)
7977 $ coords - Coordinates of the current point, usually a cell centroid
7978 $ limit  - The maximum cell volume for a cell containing this point
7979 
7980   Level: developer
7981 
7982 .seealso: DMRefine(), DMPlexSetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
7983 @*/
7984 PetscErrorCode DMPlexGetRefinementFunction(DM dm, PetscErrorCode (**refinementFunc)(const PetscReal [], PetscReal *))
7985 {
7986   DM_Plex *mesh = (DM_Plex*) dm->data;
7987 
7988   PetscFunctionBegin;
7989   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7990   PetscValidPointer(refinementFunc,  2);
7991   *refinementFunc = mesh->refinementFunc;
7992   PetscFunctionReturn(0);
7993 }
7994 
7995 PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
7996 {
7997   PetscInt       dim, cStart, cEnd, coneSize, cMax, fMax;
7998   PetscErrorCode ierr;
7999 
8000   PetscFunctionBegin;
8001   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
8002   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8003   if (cEnd <= cStart) {*cellRefiner = REFINER_NOOP; PetscFunctionReturn(0);}
8004   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
8005   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, NULL, NULL);CHKERRQ(ierr);
8006   switch (dim) {
8007   case 1:
8008     switch (coneSize) {
8009     case 2:
8010       *cellRefiner = REFINER_SIMPLEX_1D;
8011       break;
8012     default:
8013       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
8014     }
8015     break;
8016   case 2:
8017     switch (coneSize) {
8018     case 3:
8019       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_2D;
8020       else *cellRefiner = REFINER_SIMPLEX_2D;
8021       break;
8022     case 4:
8023       if (cMax >= 0 && fMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_2D;
8024       else *cellRefiner = REFINER_HEX_2D;
8025       break;
8026     default:
8027       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
8028     }
8029     break;
8030   case 3:
8031     switch (coneSize) {
8032     case 4:
8033       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_3D;
8034       else *cellRefiner = REFINER_SIMPLEX_3D;
8035       break;
8036     case 6:
8037       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_3D;
8038       else *cellRefiner = REFINER_HEX_3D;
8039       break;
8040     default:
8041       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
8042     }
8043     break;
8044   default:
8045     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
8046   }
8047   PetscFunctionReturn(0);
8048 }
8049