xref: /petsc/src/dm/impls/plex/plexrefine.c (revision fbfcfee5110779e3d6a9465ca0a2e0f9a1a6e5e3)
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 > 0.0) {*inside = PETSC_FALSE; break;}
146     break;
147   case REFINER_HEX_2D:
148     for (d = 0; d < 2; ++d) if ((point[d] < -1.0) || (point[d] > 1.0)) {*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_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) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
189     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
190     break;
191   case REFINER_HYBRID_HEX_2D:
192     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
193     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
194     /* Quadrilateral */
195     depthSize[0] = vEnd - vStart + fMax - fStart + cMax - cStart;                 /* Add a vertex on every face and cell */
196     depthSize[1] = 2*(fMax - fStart) + 4*(cMax - cStart);                         /* Every face is split into 2 faces, and 4 faces are added for each cell */
197     depthSize[2] = 4*(cMax - cStart);                                             /* Every cell split into 4 cells */
198     /* Segment Prisms */
199     depthSize[0] += 0;                                                            /* No hybrid vertices */
200     depthSize[1] +=   (fEnd - fMax)  +   (cEnd - cMax);                           /* Every hybrid face remains and 1 faces is added for each hybrid cell */
201     depthSize[2] += 2*(cEnd - cMax);                                              /* Every hybrid cell split into 2 cells */
202     break;
203   case REFINER_SIMPLEX_3D:
204     depthSize[0] =    vEnd - vStart  +    eEnd - eStart;                    /* Add a vertex on every edge */
205     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 */
206     depthSize[2] = 4*(fEnd - fStart) + 8*(cEnd - cStart);                   /* Every face split into 4 faces and 8 faces are added for each cell */
207     depthSize[3] = 8*(cEnd - cStart);                                       /* Every cell split into 8 cells */
208     break;
209   case REFINER_HYBRID_SIMPLEX_3D:
210     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
211     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
212     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
213     /* Tetrahedra */
214     depthSize[0]  =    vEnd - vStart  +    eMax - eStart;                    /* Add a vertex on every interior edge */
215     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 */
216     depthSize[2]  = 4*(fMax - fStart) + 8*(cMax - cStart);                   /* Every interior face split into 4 faces, 8 faces added for each interior cell */
217     depthSize[3]  = 8*(cMax - cStart);                                       /* Every interior cell split into 8 cells */
218     /* Triangular Prisms */
219     depthSize[0] += 0;                                                       /* No hybrid vertices */
220     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax);                     /* Every hybrid edge remains, 1 edge for every hybrid face */
221     depthSize[2] += 2*(fEnd - fMax)   + 3*(cEnd - cMax);                     /* Every hybrid face split into 2 faces and 3 faces are added for each hybrid cell */
222     depthSize[3] += 4*(cEnd - cMax);                                         /* Every hybrid cell split into 4 cells */
223     break;
224   case REFINER_HEX_3D:
225     depthSize[0] = vEnd - vStart + eEnd - eStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every edge, face and cell */
226     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 */
227     depthSize[2] = 4*(fEnd - fStart) + 12*(cEnd - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
228     depthSize[3] = 8*(cEnd - cStart);                                             /* Every cell split into 8 cells */
229     break;
230   case REFINER_HYBRID_HEX_3D:
231     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
232     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
233     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
234     /* Hexahedra */
235     depthSize[0] = vEnd - vStart + eMax - eStart + fMax - fStart + cMax - cStart; /* Add a vertex on every edge, face and cell */
236     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 */
237     depthSize[2] = 4*(fMax - fStart) + 12*(cMax - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
238     depthSize[3] = 8*(cMax - cStart);                                             /* Every cell split into 8 cells */
239     /* Quadrilateral Prisms */
240     depthSize[0] += 0;                                                            /* No hybrid vertices */
241     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax)   +   (cEnd - cMax);      /* Every hybrid edge remains, 1 edge for every hybrid face and hybrid cell */
242     depthSize[2] += 2*(fEnd - fMax)   + 4*(cEnd - cMax);                          /* Every hybrid face split into 2 faces and 4 faces are added for each hybrid cell */
243     depthSize[3] += 4*(cEnd - cMax);                                              /* Every hybrid cell split into 4 cells */
244     break;
245   default:
246     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
247   }
248   PetscFunctionReturn(0);
249 }
250 
251 /* Return triangle edge for orientation o, if it is r for o == 0 */
252 PETSC_STATIC_INLINE PetscInt GetTriEdge_Static(PetscInt o, PetscInt r) {
253   return (o < 0 ? 2-(o+r) : o+r)%3;
254 }
255 PETSC_STATIC_INLINE PetscInt GetTriEdgeInverse_Static(PetscInt o, PetscInt s) {
256   return (o < 0 ? 2-(o+s) : 3+s-o)%3;
257 }
258 
259 /* Return triangle subface for orientation o, if it is r for o == 0 */
260 PETSC_STATIC_INLINE PetscInt GetTriSubface_Static(PetscInt o, PetscInt r) {
261   return (o < 0 ? 3-(o+r) : o+r)%3;
262 }
263 PETSC_STATIC_INLINE PetscInt GetTriSubfaceInverse_Static(PetscInt o, PetscInt s) {
264   return (o < 0 ? 3-(o+s) : 3+s-o)%3;
265 }
266 
267 /* I HAVE NO IDEA: Return ??? for orientation o, if it is r for o == 0 */
268 PETSC_STATIC_INLINE PetscInt GetTetSomething_Static(PetscInt o, PetscInt r) {
269   return (o < 0 ? 1-(o+r) : o+r)%3;
270 }
271 PETSC_STATIC_INLINE PetscInt GetTetSomethingInverse_Static(PetscInt o, PetscInt s) {
272   return (o < 0 ? 1-(o+s) : 3+s-o)%3;
273 }
274 
275 
276 /* Return quad edge for orientation o, if it is r for o == 0 */
277 PETSC_STATIC_INLINE PetscInt GetQuadEdge_Static(PetscInt o, PetscInt r) {
278   return (o < 0 ? 3-(o+r) : o+r)%4;
279 }
280 PETSC_STATIC_INLINE PetscInt GetQuadEdgeInverse_Static(PetscInt o, PetscInt s) {
281   return (o < 0 ? 3-(o+s) : 4+s-o)%4;
282 }
283 
284 /* Return quad subface for orientation o, if it is r for o == 0 */
285 PETSC_STATIC_INLINE PetscInt GetQuadSubface_Static(PetscInt o, PetscInt r) {
286   return (o < 0 ? 4-(o+r) : o+r)%4;
287 }
288 PETSC_STATIC_INLINE PetscInt GetQuadSubfaceInverse_Static(PetscInt o, PetscInt s) {
289   return (o < 0 ? 4-(o+s) : 4+s-o)%4;
290 }
291 
292 static PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
293 {
294   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, e, r;
295   PetscErrorCode ierr;
296 
297   PetscFunctionBegin;
298   if (!refiner) PetscFunctionReturn(0);
299   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
300   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
301   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
302   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
303   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
304   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
305   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
306   switch (refiner) {
307   case REFINER_SIMPLEX_1D:
308     /* All cells have 2 vertices */
309     for (c = cStart; c < cEnd; ++c) {
310       for (r = 0; r < 2; ++r) {
311         const PetscInt newp = cStartNew + (c - cStart)*2 + r;
312 
313         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
314       }
315     }
316     /* Old vertices have identical supports */
317     for (v = vStart; v < vEnd; ++v) {
318       const PetscInt newp = vStartNew + (v - vStart);
319       PetscInt       size;
320 
321       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
322       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
323     }
324     /* Cell vertices have support 2 */
325     for (c = cStart; c < cEnd; ++c) {
326       const PetscInt newp = vStartNew + (vEnd - vStart) + (c - cStart);
327 
328       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
329     }
330     break;
331   case REFINER_SIMPLEX_2D:
332     /* All cells have 3 faces */
333     for (c = cStart; c < cEnd; ++c) {
334       for (r = 0; r < 4; ++r) {
335         const PetscInt newp = (c - cStart)*4 + r;
336 
337         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
338       }
339     }
340     /* Split faces have 2 vertices and the same cells as the parent */
341     for (f = fStart; f < fEnd; ++f) {
342       for (r = 0; r < 2; ++r) {
343         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
344         PetscInt       size;
345 
346         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
347         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
348         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
349       }
350     }
351     /* Interior faces have 2 vertices and 2 cells */
352     for (c = cStart; c < cEnd; ++c) {
353       for (r = 0; r < 3; ++r) {
354         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
355 
356         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
357         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
358       }
359     }
360     /* Old vertices have identical supports */
361     for (v = vStart; v < vEnd; ++v) {
362       const PetscInt newp = vStartNew + (v - vStart);
363       PetscInt       size;
364 
365       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
366       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
367     }
368     /* Face vertices have 2 + cells*2 supports */
369     for (f = fStart; f < fEnd; ++f) {
370       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
371       PetscInt       size;
372 
373       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
374       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
375     }
376     break;
377   case REFINER_HEX_2D:
378     /* All cells have 4 faces */
379     for (c = cStart; c < cEnd; ++c) {
380       for (r = 0; r < 4; ++r) {
381         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
382 
383         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
384       }
385     }
386     /* Split faces have 2 vertices and the same cells as the parent */
387     for (f = fStart; f < fEnd; ++f) {
388       for (r = 0; r < 2; ++r) {
389         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
390         PetscInt       size;
391 
392         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
393         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
394         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
395       }
396     }
397     /* Interior faces have 2 vertices and 2 cells */
398     for (c = cStart; c < cEnd; ++c) {
399       for (r = 0; r < 4; ++r) {
400         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
401 
402         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
403         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
404       }
405     }
406     /* Old vertices have identical supports */
407     for (v = vStart; v < vEnd; ++v) {
408       const PetscInt newp = vStartNew + (v - vStart);
409       PetscInt       size;
410 
411       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
412       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
413     }
414     /* Face vertices have 2 + cells supports */
415     for (f = fStart; f < fEnd; ++f) {
416       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
417       PetscInt       size;
418 
419       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
420       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
421     }
422     /* Cell vertices have 4 supports */
423     for (c = cStart; c < cEnd; ++c) {
424       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
425 
426       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
427     }
428     break;
429   case REFINER_HYBRID_SIMPLEX_2D:
430     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
431     cMax = PetscMin(cEnd, cMax);
432     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
433     fMax = PetscMin(fEnd, fMax);
434     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
435     /* Interior cells have 3 faces */
436     for (c = cStart; c < cMax; ++c) {
437       for (r = 0; r < 4; ++r) {
438         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
439 
440         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
441       }
442     }
443     /* Hybrid cells have 4 faces */
444     for (c = cMax; c < cEnd; ++c) {
445       for (r = 0; r < 2; ++r) {
446         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
447 
448         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
449       }
450     }
451     /* Interior split faces have 2 vertices and the same cells as the parent */
452     for (f = fStart; f < fMax; ++f) {
453       for (r = 0; r < 2; ++r) {
454         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
455         PetscInt       size;
456 
457         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
458         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
459         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
460       }
461     }
462     /* Interior cell faces have 2 vertices and 2 cells */
463     for (c = cStart; c < cMax; ++c) {
464       for (r = 0; r < 3; ++r) {
465         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
466 
467         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
468         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
469       }
470     }
471     /* Hybrid faces have 2 vertices and the same cells */
472     for (f = fMax; f < fEnd; ++f) {
473       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
474       PetscInt       size;
475 
476       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
477       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
478       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
479     }
480     /* Hybrid cell faces have 2 vertices and 2 cells */
481     for (c = cMax; c < cEnd; ++c) {
482       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
483 
484       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
485       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
486     }
487     /* Old vertices have identical supports */
488     for (v = vStart; v < vEnd; ++v) {
489       const PetscInt newp = vStartNew + (v - vStart);
490       PetscInt       size;
491 
492       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
493       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
494     }
495     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
496     for (f = fStart; f < fMax; ++f) {
497       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
498       const PetscInt *support;
499       PetscInt       size, newSize = 2, s;
500 
501       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
502       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
503       for (s = 0; s < size; ++s) {
504         if (support[s] >= cMax) newSize += 1;
505         else newSize += 2;
506       }
507       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
508     }
509     break;
510   case REFINER_HYBRID_HEX_2D:
511     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
512     cMax = PetscMin(cEnd, cMax);
513     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
514     fMax = PetscMin(fEnd, fMax);
515     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
516     /* Interior cells have 4 faces */
517     for (c = cStart; c < cMax; ++c) {
518       for (r = 0; r < 4; ++r) {
519         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
520 
521         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
522       }
523     }
524     /* Hybrid cells have 4 faces */
525     for (c = cMax; c < cEnd; ++c) {
526       for (r = 0; r < 2; ++r) {
527         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
528 
529         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
530       }
531     }
532     /* Interior split faces have 2 vertices and the same cells as the parent */
533     for (f = fStart; f < fMax; ++f) {
534       for (r = 0; r < 2; ++r) {
535         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
536         PetscInt       size;
537 
538         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
539         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
540         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
541       }
542     }
543     /* Interior cell faces have 2 vertices and 2 cells */
544     for (c = cStart; c < cMax; ++c) {
545       for (r = 0; r < 4; ++r) {
546         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
547 
548         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
549         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
550       }
551     }
552     /* Hybrid faces have 2 vertices and the same cells */
553     for (f = fMax; f < fEnd; ++f) {
554       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
555       PetscInt       size;
556 
557       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
558       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
559       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
560     }
561     /* Hybrid cell faces have 2 vertices and 2 cells */
562     for (c = cMax; c < cEnd; ++c) {
563       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
564 
565       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
566       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
567     }
568     /* Old vertices have identical supports */
569     for (v = vStart; v < vEnd; ++v) {
570       const PetscInt newp = vStartNew + (v - vStart);
571       PetscInt       size;
572 
573       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
574       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
575     }
576     /* Face vertices have 2 + cells supports */
577     for (f = fStart; f < fMax; ++f) {
578       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
579       PetscInt       size;
580 
581       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
582       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
583     }
584     /* Cell vertices have 4 supports */
585     for (c = cStart; c < cMax; ++c) {
586       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
587 
588       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
589     }
590     break;
591   case REFINER_SIMPLEX_3D:
592     /* All cells have 4 faces */
593     for (c = cStart; c < cEnd; ++c) {
594       for (r = 0; r < 8; ++r) {
595         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
596 
597         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
598       }
599     }
600     /* Split faces have 3 edges and the same cells as the parent */
601     for (f = fStart; f < fEnd; ++f) {
602       for (r = 0; r < 4; ++r) {
603         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
604         PetscInt       size;
605 
606         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
607         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
608         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
609       }
610     }
611     /* Interior cell faces have 3 edges and 2 cells */
612     for (c = cStart; c < cEnd; ++c) {
613       for (r = 0; r < 8; ++r) {
614         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + r;
615 
616         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
617         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
618       }
619     }
620     /* Split edges have 2 vertices and the same faces */
621     for (e = eStart; e < eEnd; ++e) {
622       for (r = 0; r < 2; ++r) {
623         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
624         PetscInt       size;
625 
626         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
627         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
628         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
629       }
630     }
631     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
632     for (f = fStart; f < fEnd; ++f) {
633       for (r = 0; r < 3; ++r) {
634         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
635         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
636         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;
637 
638         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
639         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
640         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
641         for (s = 0; s < supportSize; ++s) {
642           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
643           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
644           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
645           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
646           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
647           er = GetTetSomethingInverse_Static(ornt[c], r);
648           if (er == eint[c]) {
649             intFaces += 1;
650           } else {
651             intFaces += 2;
652           }
653         }
654         ierr = DMPlexSetSupportSize(rdm, newp, 2+intFaces);CHKERRQ(ierr);
655       }
656     }
657     /* Interior cell edges have 2 vertices and 4 faces */
658     for (c = cStart; c < cEnd; ++c) {
659       const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
660 
661       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
662       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
663     }
664     /* Old vertices have identical supports */
665     for (v = vStart; v < vEnd; ++v) {
666       const PetscInt newp = vStartNew + (v - vStart);
667       PetscInt       size;
668 
669       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
670       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
671     }
672     /* Edge vertices have 2 + faces*2 + cells*0/1 supports */
673     for (e = eStart; e < eEnd; ++e) {
674       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
675       PetscInt       size, *star = NULL, starSize, s, cellSize = 0;
676 
677       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
678       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
679       for (s = 0; s < starSize*2; s += 2) {
680         const PetscInt *cone, *ornt;
681         PetscInt        e01, e23;
682 
683         if ((star[s] >= cStart) && (star[s] < cEnd)) {
684           /* Check edge 0-1 */
685           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
686           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
687           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
688           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
689           /* Check edge 2-3 */
690           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
691           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
692           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
693           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
694           if ((e01 == e) || (e23 == e)) ++cellSize;
695         }
696       }
697       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
698       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2 + cellSize);CHKERRQ(ierr);
699     }
700     break;
701   case REFINER_HYBRID_SIMPLEX_3D:
702     ierr = DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 8*(cMax - cStart),
703                                  eStartNew + 2*(eMax - eStart) + 3*(fMax - fStart) + (cMax - cStart), PETSC_DETERMINE);CHKERRQ(ierr);
704     /* Interior cells have 4 faces */
705     for (c = cStart; c < cMax; ++c) {
706       for (r = 0; r < 8; ++r) {
707         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
708 
709         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
710       }
711     }
712     /* Hybrid cells have 5 faces */
713     for (c = cMax; c < cEnd; ++c) {
714       for (r = 0; r < 4; ++r) {
715         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;
716 
717         ierr = DMPlexSetConeSize(rdm, newp, 5);CHKERRQ(ierr);
718       }
719     }
720     /* Interior split faces have 3 edges and the same cells as the parent */
721     for (f = fStart; f < fMax; ++f) {
722       for (r = 0; r < 4; ++r) {
723         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
724         PetscInt       size;
725 
726         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
727         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
728         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
729       }
730     }
731     /* Interior cell faces have 3 edges and 2 cells */
732     for (c = cStart; c < cMax; ++c) {
733       for (r = 0; r < 8; ++r) {
734         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + r;
735 
736         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
737         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
738       }
739     }
740     /* Hybrid split faces have 4 edges and the same cells as the parent */
741     for (f = fMax; f < fEnd; ++f) {
742       for (r = 0; r < 2; ++r) {
743         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
744         PetscInt       size;
745 
746         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
747         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
748         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
749       }
750     }
751     /* Hybrid cells faces have 4 edges and 2 cells */
752     for (c = cMax; c < cEnd; ++c) {
753       for (r = 0; r < 3; ++r) {
754         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + r;
755 
756         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
757         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
758       }
759     }
760     /* Interior split edges have 2 vertices and the same faces */
761     for (e = eStart; e < eMax; ++e) {
762       for (r = 0; r < 2; ++r) {
763         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
764         PetscInt       size;
765 
766         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
767         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
768         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
769       }
770     }
771     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
772     for (f = fStart; f < fMax; ++f) {
773       for (r = 0; r < 3; ++r) {
774         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
775         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
776         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;
777 
778         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
779         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
780         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
781         for (s = 0; s < supportSize; ++s) {
782           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
783           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
784           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
785           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
786           if (support[s] < cMax) {
787             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
788             er = GetTetSomethingInverse_Static(ornt[c], r);
789             if (er == eint[c]) {
790               intFaces += 1;
791             } else {
792               intFaces += 2;
793             }
794           } else {
795             intFaces += 1;
796           }
797         }
798         ierr = DMPlexSetSupportSize(rdm, newp, 2+intFaces);CHKERRQ(ierr);
799       }
800     }
801     /* Interior cell edges have 2 vertices and 4 faces */
802     for (c = cStart; c < cMax; ++c) {
803       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
804 
805       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
806       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
807     }
808     /* Hybrid edges have 2 vertices and the same faces */
809     for (e = eMax; e < eEnd; ++e) {
810       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
811       PetscInt       size;
812 
813       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
814       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
815       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
816     }
817     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
818     for (f = fMax; f < fEnd; ++f) {
819       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
820       PetscInt       size;
821 
822       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
823       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
824       ierr = DMPlexSetSupportSize(rdm, newp, 2+2*size);CHKERRQ(ierr);
825     }
826     /* Interior vertices have identical supports */
827     for (v = vStart; v < vEnd; ++v) {
828       const PetscInt newp = vStartNew + (v - vStart);
829       PetscInt       size;
830 
831       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
832       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
833     }
834     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
835     for (e = eStart; e < eMax; ++e) {
836       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
837       const PetscInt *support;
838       PetscInt        size, *star = NULL, starSize, s, faceSize = 0, cellSize = 0;
839 
840       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
841       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
842       for (s = 0; s < size; ++s) {
843         if (support[s] < fMax) faceSize += 2;
844         else                   faceSize += 1;
845       }
846       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
847       for (s = 0; s < starSize*2; s += 2) {
848         const PetscInt *cone, *ornt;
849         PetscInt        e01, e23;
850 
851         if ((star[s] >= cStart) && (star[s] < cMax)) {
852           /* Check edge 0-1 */
853           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
854           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
855           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
856           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
857           /* Check edge 2-3 */
858           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
859           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
860           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
861           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
862           if ((e01 == e) || (e23 == e)) ++cellSize;
863         }
864       }
865       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
866       ierr = DMPlexSetSupportSize(rdm, newp, 2 + faceSize + cellSize);CHKERRQ(ierr);
867     }
868     break;
869   case REFINER_HEX_3D:
870     /* All cells have 6 faces */
871     for (c = cStart; c < cEnd; ++c) {
872       for (r = 0; r < 8; ++r) {
873         const PetscInt newp = (c - cStart)*8 + r;
874 
875         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
876       }
877     }
878     /* Split faces have 4 edges and the same cells as the parent */
879     for (f = fStart; f < fEnd; ++f) {
880       for (r = 0; r < 4; ++r) {
881         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
882         PetscInt       size;
883 
884         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
885         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
886         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
887       }
888     }
889     /* Interior faces have 4 edges and 2 cells */
890     for (c = cStart; c < cEnd; ++c) {
891       for (r = 0; r < 12; ++r) {
892         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
893 
894         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
895         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
896       }
897     }
898     /* Split edges have 2 vertices and the same faces as the parent */
899     for (e = eStart; e < eEnd; ++e) {
900       for (r = 0; r < 2; ++r) {
901         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
902         PetscInt       size;
903 
904         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
905         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
906         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
907       }
908     }
909     /* Face edges have 2 vertices and 2+cells faces */
910     for (f = fStart; f < fEnd; ++f) {
911       for (r = 0; r < 4; ++r) {
912         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
913         PetscInt       size;
914 
915         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
916         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
917         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
918       }
919     }
920     /* Cell edges have 2 vertices and 4 faces */
921     for (c = cStart; c < cEnd; ++c) {
922       for (r = 0; r < 6; ++r) {
923         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
924 
925         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
926         ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
927       }
928     }
929     /* Old vertices have identical supports */
930     for (v = vStart; v < vEnd; ++v) {
931       const PetscInt newp = vStartNew + (v - vStart);
932       PetscInt       size;
933 
934       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
935       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
936     }
937     /* Edge vertices have 2 + faces supports */
938     for (e = eStart; e < eEnd; ++e) {
939       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
940       PetscInt       size;
941 
942       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
943       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
944     }
945     /* Face vertices have 4 + cells supports */
946     for (f = fStart; f < fEnd; ++f) {
947       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
948       PetscInt       size;
949 
950       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
951       ierr = DMPlexSetSupportSize(rdm, newp, 4 + size);CHKERRQ(ierr);
952     }
953     /* Cell vertices have 6 supports */
954     for (c = cStart; c < cEnd; ++c) {
955       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
956 
957       ierr = DMPlexSetSupportSize(rdm, newp, 6);CHKERRQ(ierr);
958     }
959     break;
960   case REFINER_HYBRID_HEX_3D:
961     ierr = DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 12*(cMax - cStart),
962                                  eStartNew + 2*(eMax - eStart) + 4*(fMax - fStart) + 6*(cMax - cStart), PETSC_DETERMINE);CHKERRQ(ierr);
963     /* Interior cells have 6 faces */
964     for (c = cStart; c < cMax; ++c) {
965       for (r = 0; r < 8; ++r) {
966         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
967 
968         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
969       }
970     }
971     /* Hybrid cells have 6 faces */
972     for (c = cMax; c < cEnd; ++c) {
973       for (r = 0; r < 4; ++r) {
974         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;
975 
976         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
977       }
978     }
979     /* Interior split faces have 4 edges and the same cells as the parent */
980     for (f = fStart; f < fMax; ++f) {
981       for (r = 0; r < 4; ++r) {
982         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
983         PetscInt       size;
984 
985         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
986         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
987         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
988       }
989     }
990     /* Interior cell faces have 4 edges and 2 cells */
991     for (c = cStart; c < cMax; ++c) {
992       for (r = 0; r < 12; ++r) {
993         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
994 
995         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
996         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
997       }
998     }
999     /* Hybrid split faces have 4 edges and the same cells as the parent */
1000     for (f = fMax; f < fEnd; ++f) {
1001       for (r = 0; r < 2; ++r) {
1002         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
1003         PetscInt       size;
1004 
1005         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1006         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1007         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1008       }
1009     }
1010     /* Hybrid cells faces have 4 edges and 2 cells */
1011     for (c = cMax; c < cEnd; ++c) {
1012       for (r = 0; r < 4; ++r) {
1013         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + r;
1014 
1015         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1016         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1017       }
1018     }
1019     /* Interior split edges have 2 vertices and the same faces as the parent */
1020     for (e = eStart; e < eMax; ++e) {
1021       for (r = 0; r < 2; ++r) {
1022         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1023         PetscInt       size;
1024 
1025         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1026         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1027         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1028       }
1029     }
1030     /* Interior face edges have 2 vertices and 2+cells faces */
1031     for (f = fStart; f < fMax; ++f) {
1032       for (r = 0; r < 4; ++r) {
1033         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
1034         PetscInt       size;
1035 
1036         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1037         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1038         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1039       }
1040     }
1041     /* Interior cell edges have 2 vertices and 4 faces */
1042     for (c = cStart; c < cMax; ++c) {
1043       for (r = 0; r < 6; ++r) {
1044         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
1045 
1046         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1047         ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1048       }
1049     }
1050     /* Hybrid edges have 2 vertices and the same faces */
1051     for (e = eMax; e < eEnd; ++e) {
1052       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
1053       PetscInt       size;
1054 
1055       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1056       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1057       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1058     }
1059     /* Hybrid face edges have 2 vertices and 2+cells faces */
1060     for (f = fMax; f < fEnd; ++f) {
1061       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
1062       PetscInt       size;
1063 
1064       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1065       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1066       ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1067     }
1068     /* Hybrid cell edges have 2 vertices and 4 faces */
1069     for (c = cMax; c < cEnd; ++c) {
1070       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
1071 
1072       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1073       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1074     }
1075     /* Interior vertices have identical supports */
1076     for (v = vStart; v < vEnd; ++v) {
1077       const PetscInt newp = vStartNew + (v - vStart);
1078       PetscInt       size;
1079 
1080       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1081       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1082     }
1083     /* Interior edge vertices have 2 + faces supports */
1084     for (e = eStart; e < eMax; ++e) {
1085       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1086       PetscInt       size;
1087 
1088       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1089       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1090     }
1091     /* Interior face vertices have 4 + cells supports */
1092     for (f = fStart; f < fMax; ++f) {
1093       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
1094       PetscInt       size;
1095 
1096       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1097       ierr = DMPlexSetSupportSize(rdm, newp, 4 + size);CHKERRQ(ierr);
1098     }
1099     /* Interior cell vertices have 6 supports */
1100     for (c = cStart; c < cMax; ++c) {
1101       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
1102 
1103       ierr = DMPlexSetSupportSize(rdm, newp, 6);CHKERRQ(ierr);
1104     }
1105     break;
1106   default:
1107     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
1108   }
1109   PetscFunctionReturn(0);
1110 }
1111 
1112 static PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
1113 {
1114   const PetscInt *faces, cellInd[4] = {0, 1, 2, 3};
1115   PetscInt        cStart,    cEnd,    cMax,    vStart,    vEnd, vMax, fStart,    fEnd,    fMax,    eStart,    eEnd,    eMax;
1116   PetscInt        cStartNew, cEndNew, cMaxNew, vStartNew, vEndNew,    fStartNew, fEndNew, fMaxNew, eStartNew, eEndNew, eMaxNew;
1117   PetscInt        depth, maxSupportSize, *supportRef, c, f, e, v, r, p;
1118   PetscErrorCode  ierr;
1119 
1120   PetscFunctionBegin;
1121   if (!refiner) PetscFunctionReturn(0);
1122   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1123   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
1124   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
1125   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1126   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
1127   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
1128   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
1129   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
1130   switch (refiner) {
1131   case REFINER_SIMPLEX_1D:
1132     /* Max support size of refined mesh is 2 */
1133     ierr = PetscMalloc1(2, &supportRef);CHKERRQ(ierr);
1134     /* All cells have 2 vertices */
1135     for (c = cStart; c < cEnd; ++c) {
1136       const PetscInt  newv = vStartNew + (vEnd - vStart) + (c - cStart);
1137 
1138       for (r = 0; r < 2; ++r) {
1139         const PetscInt newp = cStartNew + (c - cStart)*2 + r;
1140         const PetscInt *cone;
1141         PetscInt        coneNew[2];
1142 
1143         ierr             = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1144         coneNew[0]       = vStartNew + (cone[0] - vStart);
1145         coneNew[1]       = vStartNew + (cone[1] - vStart);
1146         coneNew[(r+1)%2] = newv;
1147         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1148 #if 1
1149         if ((newp < cStartNew) || (newp >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp, cStartNew, cEndNew);
1150         for (p = 0; p < 2; ++p) {
1151           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);
1152         }
1153 #endif
1154       }
1155     }
1156     /* Old vertices have identical supports */
1157     for (v = vStart; v < vEnd; ++v) {
1158       const PetscInt  newp = vStartNew + (v - vStart);
1159       const PetscInt *support, *cone;
1160       PetscInt        size, s;
1161 
1162       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1163       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1164       for (s = 0; s < size; ++s) {
1165         PetscInt r = 0;
1166 
1167         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1168         if (cone[1] == v) r = 1;
1169         supportRef[s] = cStartNew + (support[s] - cStart)*2 + r;
1170       }
1171       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1172 #if 1
1173       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1174       for (p = 0; p < size; ++p) {
1175         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);
1176       }
1177 #endif
1178     }
1179     /* Cell vertices have support of 2 cells */
1180     for (c = cStart; c < cEnd; ++c) {
1181       const PetscInt  newp = vStartNew + (vEnd - vStart) + (c - cStart);
1182 
1183       supportRef[0] = cStartNew + (c - cStart)*2 + 0;
1184       supportRef[1] = cStartNew + (c - cStart)*2 + 1;
1185       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1186 #if 1
1187       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1188       for (p = 0; p < 2; ++p) {
1189         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);
1190       }
1191 #endif
1192     }
1193     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1194     break;
1195   case REFINER_SIMPLEX_2D:
1196     /*
1197      2
1198      |\
1199      | \
1200      |  \
1201      |   \
1202      | C  \
1203      |     \
1204      |      \
1205      2---1---1
1206      |\  D  / \
1207      | 2   0   \
1208      |A \ /  B  \
1209      0---0-------1
1210      */
1211     /* All cells have 3 faces */
1212     for (c = cStart; c < cEnd; ++c) {
1213       const PetscInt  newp = cStartNew + (c - cStart)*4;
1214       const PetscInt *cone, *ornt;
1215       PetscInt        coneNew[3], orntNew[3];
1216 
1217       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1218       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1219       /* A triangle */
1220       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1221       orntNew[0] = ornt[0];
1222       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1223       orntNew[1] = -2;
1224       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1225       orntNew[2] = ornt[2];
1226       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1227       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1228 #if 1
1229       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);
1230       for (p = 0; p < 3; ++p) {
1231         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);
1232       }
1233 #endif
1234       /* B triangle */
1235       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1236       orntNew[0] = ornt[0];
1237       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1238       orntNew[1] = ornt[1];
1239       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1240       orntNew[2] = -2;
1241       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1242       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1243 #if 1
1244       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);
1245       for (p = 0; p < 3; ++p) {
1246         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);
1247       }
1248 #endif
1249       /* C triangle */
1250       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1251       orntNew[0] = -2;
1252       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1253       orntNew[1] = ornt[1];
1254       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1255       orntNew[2] = ornt[2];
1256       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1257       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1258 #if 1
1259       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);
1260       for (p = 0; p < 3; ++p) {
1261         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);
1262       }
1263 #endif
1264       /* D triangle */
1265       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1266       orntNew[0] = 0;
1267       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1268       orntNew[1] = 0;
1269       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1270       orntNew[2] = 0;
1271       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1272       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1273 #if 1
1274       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);
1275       for (p = 0; p < 3; ++p) {
1276         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);
1277       }
1278 #endif
1279     }
1280     /* Split faces have 2 vertices and the same cells as the parent */
1281     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1282     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
1283     for (f = fStart; f < fEnd; ++f) {
1284       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1285 
1286       for (r = 0; r < 2; ++r) {
1287         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1288         const PetscInt *cone, *ornt, *support;
1289         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1290 
1291         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1292         coneNew[0]       = vStartNew + (cone[0] - vStart);
1293         coneNew[1]       = vStartNew + (cone[1] - vStart);
1294         coneNew[(r+1)%2] = newv;
1295         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1296 #if 1
1297         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1298         for (p = 0; p < 2; ++p) {
1299           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);
1300         }
1301 #endif
1302         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1303         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1304         for (s = 0; s < supportSize; ++s) {
1305           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1306           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1307           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1308           for (c = 0; c < coneSize; ++c) {
1309             if (cone[c] == f) break;
1310           }
1311           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1312         }
1313         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1314 #if 1
1315         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1316         for (p = 0; p < supportSize; ++p) {
1317           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);
1318         }
1319 #endif
1320       }
1321     }
1322     /* Interior faces have 2 vertices and 2 cells */
1323     for (c = cStart; c < cEnd; ++c) {
1324       const PetscInt *cone;
1325 
1326       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1327       for (r = 0; r < 3; ++r) {
1328         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
1329         PetscInt       coneNew[2];
1330         PetscInt       supportNew[2];
1331 
1332         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
1333         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
1334         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1335 #if 1
1336         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1337         for (p = 0; p < 2; ++p) {
1338           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);
1339         }
1340 #endif
1341         supportNew[0] = (c - cStart)*4 + (r+1)%3;
1342         supportNew[1] = (c - cStart)*4 + 3;
1343         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1344 #if 1
1345         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1346         for (p = 0; p < 2; ++p) {
1347           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);
1348         }
1349 #endif
1350       }
1351     }
1352     /* Old vertices have identical supports */
1353     for (v = vStart; v < vEnd; ++v) {
1354       const PetscInt  newp = vStartNew + (v - vStart);
1355       const PetscInt *support, *cone;
1356       PetscInt        size, s;
1357 
1358       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1359       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1360       for (s = 0; s < size; ++s) {
1361         PetscInt r = 0;
1362 
1363         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1364         if (cone[1] == v) r = 1;
1365         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1366       }
1367       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1368 #if 1
1369       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1370       for (p = 0; p < size; ++p) {
1371         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);
1372       }
1373 #endif
1374     }
1375     /* Face vertices have 2 + cells*2 supports */
1376     for (f = fStart; f < fEnd; ++f) {
1377       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1378       const PetscInt *cone, *support;
1379       PetscInt        size, s;
1380 
1381       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1382       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1383       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1384       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1385       for (s = 0; s < size; ++s) {
1386         PetscInt r = 0;
1387 
1388         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1389         if      (cone[1] == f) r = 1;
1390         else if (cone[2] == f) r = 2;
1391         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
1392         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
1393       }
1394       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1395 #if 1
1396       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1397       for (p = 0; p < 2+size*2; ++p) {
1398         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);
1399       }
1400 #endif
1401     }
1402     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1403     break;
1404   case REFINER_HEX_2D:
1405     /*
1406      3---------2---------2
1407      |         |         |
1408      |    D    2    C    |
1409      |         |         |
1410      3----3----0----1----1
1411      |         |         |
1412      |    A    0    B    |
1413      |         |         |
1414      0---------0---------1
1415      */
1416     /* All cells have 4 faces */
1417     for (c = cStart; c < cEnd; ++c) {
1418       const PetscInt  newp = (c - cStart)*4;
1419       const PetscInt *cone, *ornt;
1420       PetscInt        coneNew[4], orntNew[4];
1421 
1422       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1423       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1424       /* A quad */
1425       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1426       orntNew[0] = ornt[0];
1427       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
1428       orntNew[1] = 0;
1429       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
1430       orntNew[2] = -2;
1431       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
1432       orntNew[3] = ornt[3];
1433       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1434       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1435 #if 1
1436       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);
1437       for (p = 0; p < 4; ++p) {
1438         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);
1439       }
1440 #endif
1441       /* B quad */
1442       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1443       orntNew[0] = ornt[0];
1444       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1445       orntNew[1] = ornt[1];
1446       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
1447       orntNew[2] = 0;
1448       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
1449       orntNew[3] = -2;
1450       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1451       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1452 #if 1
1453       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);
1454       for (p = 0; p < 4; ++p) {
1455         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);
1456       }
1457 #endif
1458       /* C quad */
1459       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
1460       orntNew[0] = -2;
1461       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1462       orntNew[1] = ornt[1];
1463       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1464       orntNew[2] = ornt[2];
1465       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
1466       orntNew[3] = 0;
1467       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1468       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1469 #if 1
1470       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);
1471       for (p = 0; p < 4; ++p) {
1472         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1473       }
1474 #endif
1475       /* D quad */
1476       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
1477       orntNew[0] = 0;
1478       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
1479       orntNew[1] = -2;
1480       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1481       orntNew[2] = ornt[2];
1482       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
1483       orntNew[3] = ornt[3];
1484       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1485       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1486 #if 1
1487       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);
1488       for (p = 0; p < 4; ++p) {
1489         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);
1490       }
1491 #endif
1492     }
1493     /* Split faces have 2 vertices and the same cells as the parent */
1494     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1495     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
1496     for (f = fStart; f < fEnd; ++f) {
1497       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1498 
1499       for (r = 0; r < 2; ++r) {
1500         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1501         const PetscInt *cone, *ornt, *support;
1502         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1503 
1504         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1505         coneNew[0]       = vStartNew + (cone[0] - vStart);
1506         coneNew[1]       = vStartNew + (cone[1] - vStart);
1507         coneNew[(r+1)%2] = newv;
1508         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1509 #if 1
1510         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1511         for (p = 0; p < 2; ++p) {
1512           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);
1513         }
1514 #endif
1515         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1516         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1517         for (s = 0; s < supportSize; ++s) {
1518           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1519           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1520           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1521           for (c = 0; c < coneSize; ++c) {
1522             if (cone[c] == f) break;
1523           }
1524           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
1525         }
1526         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1527 #if 1
1528         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1529         for (p = 0; p < supportSize; ++p) {
1530           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);
1531         }
1532 #endif
1533       }
1534     }
1535     /* Interior faces have 2 vertices and 2 cells */
1536     for (c = cStart; c < cEnd; ++c) {
1537       const PetscInt *cone;
1538       PetscInt        coneNew[2], supportNew[2];
1539 
1540       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1541       for (r = 0; r < 4; ++r) {
1542         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
1543 
1544         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
1545         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
1546         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1547 #if 1
1548         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1549         for (p = 0; p < 2; ++p) {
1550           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);
1551         }
1552 #endif
1553         supportNew[0] = (c - cStart)*4 + r;
1554         supportNew[1] = (c - cStart)*4 + (r+1)%4;
1555         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1556 #if 1
1557         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1558         for (p = 0; p < 2; ++p) {
1559           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);
1560         }
1561 #endif
1562       }
1563     }
1564     /* Old vertices have identical supports */
1565     for (v = vStart; v < vEnd; ++v) {
1566       const PetscInt  newp = vStartNew + (v - vStart);
1567       const PetscInt *support, *cone;
1568       PetscInt        size, s;
1569 
1570       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1571       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1572       for (s = 0; s < size; ++s) {
1573         PetscInt r = 0;
1574 
1575         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1576         if (cone[1] == v) r = 1;
1577         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1578       }
1579       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1580 #if 1
1581       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1582       for (p = 0; p < size; ++p) {
1583         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);
1584       }
1585 #endif
1586     }
1587     /* Face vertices have 2 + cells supports */
1588     for (f = fStart; f < fEnd; ++f) {
1589       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1590       const PetscInt *cone, *support;
1591       PetscInt        size, s;
1592 
1593       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1594       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1595       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1596       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1597       for (s = 0; s < size; ++s) {
1598         PetscInt r = 0;
1599 
1600         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1601         if      (cone[1] == f) r = 1;
1602         else if (cone[2] == f) r = 2;
1603         else if (cone[3] == f) r = 3;
1604         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
1605       }
1606       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1607 #if 1
1608       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1609       for (p = 0; p < 2+size; ++p) {
1610         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);
1611       }
1612 #endif
1613     }
1614     /* Cell vertices have 4 supports */
1615     for (c = cStart; c < cEnd; ++c) {
1616       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
1617       PetscInt       supportNew[4];
1618 
1619       for (r = 0; r < 4; ++r) {
1620         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
1621       }
1622       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1623     }
1624     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1625     break;
1626   case REFINER_HYBRID_SIMPLEX_2D:
1627     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
1628     cMax = PetscMin(cEnd, cMax);
1629     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
1630     fMax = PetscMin(fEnd, fMax);
1631     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);CHKERRQ(ierr);
1632     /* Interior cells have 3 faces */
1633     for (c = cStart; c < cMax; ++c) {
1634       const PetscInt  newp = cStartNew + (c - cStart)*4;
1635       const PetscInt *cone, *ornt;
1636       PetscInt        coneNew[3], orntNew[3];
1637 
1638       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1639       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1640       /* A triangle */
1641       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1642       orntNew[0] = ornt[0];
1643       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
1644       orntNew[1] = -2;
1645       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1646       orntNew[2] = ornt[2];
1647       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1648       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1649 #if 1
1650       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);
1651       for (p = 0; p < 3; ++p) {
1652         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);
1653       }
1654 #endif
1655       /* B triangle */
1656       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1657       orntNew[0] = ornt[0];
1658       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1659       orntNew[1] = ornt[1];
1660       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
1661       orntNew[2] = -2;
1662       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1663       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1664 #if 1
1665       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);
1666       for (p = 0; p < 3; ++p) {
1667         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);
1668       }
1669 #endif
1670       /* C triangle */
1671       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
1672       orntNew[0] = -2;
1673       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1674       orntNew[1] = ornt[1];
1675       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1676       orntNew[2] = ornt[2];
1677       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1678       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1679 #if 1
1680       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);
1681       for (p = 0; p < 3; ++p) {
1682         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);
1683       }
1684 #endif
1685       /* D triangle */
1686       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
1687       orntNew[0] = 0;
1688       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
1689       orntNew[1] = 0;
1690       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
1691       orntNew[2] = 0;
1692       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1693       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1694 #if 1
1695       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);
1696       for (p = 0; p < 3; ++p) {
1697         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);
1698       }
1699 #endif
1700     }
1701     /*
1702      2----3----3
1703      |         |
1704      |    B    |
1705      |         |
1706      0----4--- 1
1707      |         |
1708      |    A    |
1709      |         |
1710      0----2----1
1711      */
1712     /* Hybrid cells have 4 faces */
1713     for (c = cMax; c < cEnd; ++c) {
1714       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
1715       const PetscInt *cone, *ornt;
1716       PetscInt        coneNew[4], orntNew[4], r;
1717 
1718       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1719       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1720       r    = (ornt[0] < 0 ? 1 : 0);
1721       /* A quad */
1722       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + r;
1723       orntNew[0]   = ornt[0];
1724       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + r;
1725       orntNew[1]   = ornt[1];
1726       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2+r] - fMax);
1727       orntNew[2+r] = 0;
1728       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
1729       orntNew[3-r] = 0;
1730       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1731       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1732 #if 1
1733       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);
1734       for (p = 0; p < 4; ++p) {
1735         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);
1736       }
1737 #endif
1738       /* B quad */
1739       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + 1-r;
1740       orntNew[0]   = ornt[0];
1741       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + 1-r;
1742       orntNew[1]   = ornt[1];
1743       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
1744       orntNew[2+r] = 0;
1745       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3-r] - fMax);
1746       orntNew[3-r] = 0;
1747       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1748       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1749 #if 1
1750       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);
1751       for (p = 0; p < 4; ++p) {
1752         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);
1753       }
1754 #endif
1755     }
1756     /* Interior split faces have 2 vertices and the same cells as the parent */
1757     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1758     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
1759     for (f = fStart; f < fMax; ++f) {
1760       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1761 
1762       for (r = 0; r < 2; ++r) {
1763         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1764         const PetscInt *cone, *ornt, *support;
1765         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1766 
1767         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1768         coneNew[0]       = vStartNew + (cone[0] - vStart);
1769         coneNew[1]       = vStartNew + (cone[1] - vStart);
1770         coneNew[(r+1)%2] = newv;
1771         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1772 #if 1
1773         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1774         for (p = 0; p < 2; ++p) {
1775           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);
1776         }
1777 #endif
1778         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1779         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1780         for (s = 0; s < supportSize; ++s) {
1781           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1782           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1783           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1784           for (c = 0; c < coneSize; ++c) if (cone[c] == f) break;
1785           if (support[s] >= cMax) {
1786             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[c] < 0 ? 1-r : r);
1787           } else {
1788             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1789           }
1790         }
1791         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1792 #if 1
1793         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1794         for (p = 0; p < supportSize; ++p) {
1795           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);
1796         }
1797 #endif
1798       }
1799     }
1800     /* Interior cell faces have 2 vertices and 2 cells */
1801     for (c = cStart; c < cMax; ++c) {
1802       const PetscInt *cone;
1803 
1804       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1805       for (r = 0; r < 3; ++r) {
1806         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
1807         PetscInt       coneNew[2];
1808         PetscInt       supportNew[2];
1809 
1810         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
1811         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
1812         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1813 #if 1
1814         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1815         for (p = 0; p < 2; ++p) {
1816           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);
1817         }
1818 #endif
1819         supportNew[0] = (c - cStart)*4 + (r+1)%3;
1820         supportNew[1] = (c - cStart)*4 + 3;
1821         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1822 #if 1
1823         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1824         for (p = 0; p < 2; ++p) {
1825           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);
1826         }
1827 #endif
1828       }
1829     }
1830     /* Interior hybrid faces have 2 vertices and the same cells */
1831     for (f = fMax; f < fEnd; ++f) {
1832       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
1833       const PetscInt *cone, *ornt;
1834       const PetscInt *support;
1835       PetscInt        coneNew[2];
1836       PetscInt        supportNew[2];
1837       PetscInt        size, s, r;
1838 
1839       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1840       coneNew[0] = vStartNew + (cone[0] - vStart);
1841       coneNew[1] = vStartNew + (cone[1] - vStart);
1842       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1843 #if 1
1844       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1845       for (p = 0; p < 2; ++p) {
1846         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);
1847       }
1848 #endif
1849       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1850       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1851       for (s = 0; s < size; ++s) {
1852         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1853         ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1854         for (r = 0; r < 2; ++r) {
1855           if (cone[r+2] == f) break;
1856         }
1857         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[0] < 0 ? 1-r : r);
1858       }
1859       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1860 #if 1
1861       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1862       for (p = 0; p < size; ++p) {
1863         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);
1864       }
1865 #endif
1866     }
1867     /* Cell hybrid faces have 2 vertices and 2 cells */
1868     for (c = cMax; c < cEnd; ++c) {
1869       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
1870       const PetscInt *cone;
1871       PetscInt        coneNew[2];
1872       PetscInt        supportNew[2];
1873 
1874       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1875       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
1876       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
1877       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1878 #if 1
1879       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1880       for (p = 0; p < 2; ++p) {
1881         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);
1882       }
1883 #endif
1884       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
1885       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
1886       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1887 #if 1
1888       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1889       for (p = 0; p < 2; ++p) {
1890         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);
1891       }
1892 #endif
1893     }
1894     /* Old vertices have identical supports */
1895     for (v = vStart; v < vEnd; ++v) {
1896       const PetscInt  newp = vStartNew + (v - vStart);
1897       const PetscInt *support, *cone;
1898       PetscInt        size, s;
1899 
1900       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1901       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1902       for (s = 0; s < size; ++s) {
1903         if (support[s] >= fMax) {
1904           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
1905         } else {
1906           PetscInt r = 0;
1907 
1908           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1909           if (cone[1] == v) r = 1;
1910           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1911         }
1912       }
1913       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1914 #if 1
1915       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1916       for (p = 0; p < size; ++p) {
1917         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);
1918       }
1919 #endif
1920     }
1921     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
1922     for (f = fStart; f < fMax; ++f) {
1923       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1924       const PetscInt *cone, *support;
1925       PetscInt        size, newSize = 2, s;
1926 
1927       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1928       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1929       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1930       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1931       for (s = 0; s < size; ++s) {
1932         PetscInt r = 0;
1933 
1934         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1935         if (support[s] >= cMax) {
1936           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
1937 
1938           newSize += 1;
1939         } else {
1940           if      (cone[1] == f) r = 1;
1941           else if (cone[2] == f) r = 2;
1942           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
1943           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
1944 
1945           newSize += 2;
1946         }
1947       }
1948       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1949 #if 1
1950       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1951       for (p = 0; p < newSize; ++p) {
1952         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);
1953       }
1954 #endif
1955     }
1956     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1957     break;
1958   case REFINER_HYBRID_HEX_2D:
1959     /* Hybrid Hex 2D */
1960     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
1961     cMax = PetscMin(cEnd, cMax);
1962     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
1963     fMax = PetscMin(fEnd, fMax);
1964     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);CHKERRQ(ierr);
1965     /* Interior cells have 4 faces */
1966     for (c = cStart; c < cMax; ++c) {
1967       const PetscInt  newp = cStartNew + (c - cStart)*4;
1968       const PetscInt *cone, *ornt;
1969       PetscInt        coneNew[4], orntNew[4];
1970 
1971       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1972       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1973       /* A quad */
1974       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1975       orntNew[0] = ornt[0];
1976       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
1977       orntNew[1] = 0;
1978       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
1979       orntNew[2] = -2;
1980       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
1981       orntNew[3] = ornt[3];
1982       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1983       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1984 #if 1
1985       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);
1986       for (p = 0; p < 4; ++p) {
1987         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);
1988       }
1989 #endif
1990       /* B quad */
1991       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1992       orntNew[0] = ornt[0];
1993       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1994       orntNew[1] = ornt[1];
1995       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
1996       orntNew[2] = 0;
1997       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
1998       orntNew[3] = -2;
1999       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2000       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2001 #if 1
2002       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);
2003       for (p = 0; p < 4; ++p) {
2004         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);
2005       }
2006 #endif
2007       /* C quad */
2008       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
2009       orntNew[0] = -2;
2010       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2011       orntNew[1] = ornt[1];
2012       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2013       orntNew[2] = ornt[2];
2014       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
2015       orntNew[3] = 0;
2016       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2017       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2018 #if 1
2019       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);
2020       for (p = 0; p < 4; ++p) {
2021         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);
2022       }
2023 #endif
2024       /* D quad */
2025       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
2026       orntNew[0] = 0;
2027       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
2028       orntNew[1] = -2;
2029       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2030       orntNew[2] = ornt[2];
2031       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
2032       orntNew[3] = ornt[3];
2033       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2034       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2035 #if 1
2036       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);
2037       for (p = 0; p < 4; ++p) {
2038         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);
2039       }
2040 #endif
2041     }
2042     /*
2043      2----3----3
2044      |         |
2045      |    B    |
2046      |         |
2047      0----4--- 1
2048      |         |
2049      |    A    |
2050      |         |
2051      0----2----1
2052      */
2053     /* Hybrid cells have 4 faces */
2054     for (c = cMax; c < cEnd; ++c) {
2055       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
2056       const PetscInt *cone, *ornt;
2057       PetscInt        coneNew[4], orntNew[4];
2058 
2059       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2060       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2061       /* A quad */
2062       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2063       orntNew[0] = ornt[0];
2064       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2065       orntNew[1] = ornt[1];
2066       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[2] - fMax);
2067       orntNew[2] = 0;
2068       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
2069       orntNew[3] = 0;
2070       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2071       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2072 #if 1
2073       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);
2074       for (p = 0; p < 4; ++p) {
2075         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);
2076       }
2077 #endif
2078       /* B quad */
2079       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2080       orntNew[0] = ornt[0];
2081       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2082       orntNew[1] = ornt[1];
2083       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
2084       orntNew[2] = 0;
2085       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[3] - fMax);
2086       orntNew[3] = 0;
2087       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2088       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2089 #if 1
2090       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);
2091       for (p = 0; p < 4; ++p) {
2092         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);
2093       }
2094 #endif
2095     }
2096     /* Interior split faces have 2 vertices and the same cells as the parent */
2097     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2098     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2099     for (f = fStart; f < fMax; ++f) {
2100       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
2101 
2102       for (r = 0; r < 2; ++r) {
2103         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2104         const PetscInt *cone, *ornt, *support;
2105         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2106 
2107         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2108         coneNew[0]       = vStartNew + (cone[0] - vStart);
2109         coneNew[1]       = vStartNew + (cone[1] - vStart);
2110         coneNew[(r+1)%2] = newv;
2111         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2112 #if 1
2113         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2114         for (p = 0; p < 2; ++p) {
2115           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);
2116         }
2117 #endif
2118         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2119         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2120         for (s = 0; s < supportSize; ++s) {
2121           if (support[s] >= cMax) {
2122             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
2123           } else {
2124             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2125             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2126             ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2127             for (c = 0; c < coneSize; ++c) {
2128               if (cone[c] == f) break;
2129             }
2130             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
2131           }
2132         }
2133         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2134 #if 1
2135         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2136         for (p = 0; p < supportSize; ++p) {
2137           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);
2138         }
2139 #endif
2140       }
2141     }
2142     /* Interior cell faces have 2 vertices and 2 cells */
2143     for (c = cStart; c < cMax; ++c) {
2144       const PetscInt *cone;
2145 
2146       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2147       for (r = 0; r < 4; ++r) {
2148         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
2149         PetscInt       coneNew[2], supportNew[2];
2150 
2151         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2152         coneNew[1] = vStartNew + (vEnd - vStart) + (fMax    - fStart) + (c - cStart);
2153         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2154 #if 1
2155         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2156         for (p = 0; p < 2; ++p) {
2157           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);
2158         }
2159 #endif
2160         supportNew[0] = (c - cStart)*4 + r;
2161         supportNew[1] = (c - cStart)*4 + (r+1)%4;
2162         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2163 #if 1
2164         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2165         for (p = 0; p < 2; ++p) {
2166           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);
2167         }
2168 #endif
2169       }
2170     }
2171     /* Hybrid faces have 2 vertices and the same cells */
2172     for (f = fMax; f < fEnd; ++f) {
2173       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
2174       const PetscInt *cone, *support;
2175       PetscInt        coneNew[2], supportNew[2];
2176       PetscInt        size, s, r;
2177 
2178       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2179       coneNew[0] = vStartNew + (cone[0] - vStart);
2180       coneNew[1] = vStartNew + (cone[1] - vStart);
2181       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2182 #if 1
2183       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2184       for (p = 0; p < 2; ++p) {
2185         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);
2186       }
2187 #endif
2188       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2189       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2190       for (s = 0; s < size; ++s) {
2191         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2192         for (r = 0; r < 2; ++r) {
2193           if (cone[r+2] == f) break;
2194         }
2195         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
2196       }
2197       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2198 #if 1
2199       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2200       for (p = 0; p < size; ++p) {
2201         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);
2202       }
2203 #endif
2204     }
2205     /* Cell hybrid faces have 2 vertices and 2 cells */
2206     for (c = cMax; c < cEnd; ++c) {
2207       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
2208       const PetscInt *cone;
2209       PetscInt        coneNew[2], supportNew[2];
2210 
2211       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2212       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
2213       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
2214       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2215 #if 1
2216       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2217       for (p = 0; p < 2; ++p) {
2218         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);
2219       }
2220 #endif
2221       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
2222       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
2223       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2224 #if 1
2225       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2226       for (p = 0; p < 2; ++p) {
2227         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);
2228       }
2229 #endif
2230     }
2231     /* Old vertices have identical supports */
2232     for (v = vStart; v < vEnd; ++v) {
2233       const PetscInt  newp = vStartNew + (v - vStart);
2234       const PetscInt *support, *cone;
2235       PetscInt        size, s;
2236 
2237       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2238       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2239       for (s = 0; s < size; ++s) {
2240         if (support[s] >= fMax) {
2241           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (support[s] - fMax);
2242         } else {
2243           PetscInt r = 0;
2244 
2245           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2246           if (cone[1] == v) r = 1;
2247           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2248         }
2249       }
2250       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2251 #if 1
2252       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2253       for (p = 0; p < size; ++p) {
2254         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);
2255       }
2256 #endif
2257     }
2258     /* Face vertices have 2 + cells supports */
2259     for (f = fStart; f < fMax; ++f) {
2260       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2261       const PetscInt *cone, *support;
2262       PetscInt        size, s;
2263 
2264       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2265       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2266       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2267       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2268       for (s = 0; s < size; ++s) {
2269         PetscInt r = 0;
2270 
2271         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2272         if (support[s] >= cMax) {
2273           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (support[s] - cMax);
2274         } else {
2275           if      (cone[1] == f) r = 1;
2276           else if (cone[2] == f) r = 2;
2277           else if (cone[3] == f) r = 3;
2278           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*4 + r;
2279         }
2280       }
2281       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2282 #if 1
2283       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2284       for (p = 0; p < 2+size; ++p) {
2285         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);
2286       }
2287 #endif
2288     }
2289     /* Cell vertices have 4 supports */
2290     for (c = cStart; c < cMax; ++c) {
2291       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
2292       PetscInt       supportNew[4];
2293 
2294       for (r = 0; r < 4; ++r) {
2295         supportNew[r] = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
2296       }
2297       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2298     }
2299     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2300     break;
2301   case REFINER_SIMPLEX_3D:
2302     /* All cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
2303     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
2304     for (c = cStart; c < cEnd; ++c) {
2305       const PetscInt  newp = cStartNew + (c - cStart)*8;
2306       const PetscInt *cone, *ornt;
2307       PetscInt        coneNew[4], orntNew[4];
2308 
2309       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2310       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2311       /* A tetrahedron: {0, a, c, d} */
2312       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
2313       orntNew[0] = ornt[0];
2314       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
2315       orntNew[1] = ornt[1];
2316       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
2317       orntNew[2] = ornt[2];
2318       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
2319       orntNew[3] = 0;
2320       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2321       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2322 #if 1
2323       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);
2324       for (p = 0; p < 4; ++p) {
2325         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);
2326       }
2327 #endif
2328       /* B tetrahedron: {a, 1, b, e} */
2329       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
2330       orntNew[0] = ornt[0];
2331       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
2332       orntNew[1] = ornt[1];
2333       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
2334       orntNew[2] = 0;
2335       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
2336       orntNew[3] = ornt[3];
2337       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2338       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2339 #if 1
2340       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);
2341       for (p = 0; p < 4; ++p) {
2342         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);
2343       }
2344 #endif
2345       /* C tetrahedron: {c, b, 2, f} */
2346       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
2347       orntNew[0] = ornt[0];
2348       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
2349       orntNew[1] = 0;
2350       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
2351       orntNew[2] = ornt[2];
2352       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
2353       orntNew[3] = ornt[3];
2354       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2355       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2356 #if 1
2357       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);
2358       for (p = 0; p < 4; ++p) {
2359         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);
2360       }
2361 #endif
2362       /* D tetrahedron: {d, e, f, 3} */
2363       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
2364       orntNew[0] = 0;
2365       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
2366       orntNew[1] = ornt[1];
2367       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
2368       orntNew[2] = ornt[2];
2369       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
2370       orntNew[3] = ornt[3];
2371       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2372       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2373 #if 1
2374       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);
2375       for (p = 0; p < 4; ++p) {
2376         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);
2377       }
2378 #endif
2379       /* A' tetrahedron: {c, d, a, f} */
2380       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
2381       orntNew[0] = -3;
2382       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
2383       orntNew[1] = ornt[2] < 0 ? -(GetTetSomething_Static(ornt[2], 0)+1) : GetTetSomething_Static(ornt[2], 0);
2384       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
2385       orntNew[2] = 0;
2386       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
2387       orntNew[3] = 2;
2388       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
2389       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
2390 #if 1
2391       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);
2392       for (p = 0; p < 4; ++p) {
2393         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);
2394       }
2395 #endif
2396       /* B' tetrahedron: {e, b, a, f} */
2397       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
2398       orntNew[0] = -2;
2399       coneNew[1] = fStartNew + (cone[3] - fStart)*4 + 3;
2400       orntNew[1] = ornt[3] < 0 ? -(GetTetSomething_Static(ornt[3], 1)+1) : GetTetSomething_Static(ornt[3], 1);
2401       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
2402       orntNew[2] = 0;
2403       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
2404       orntNew[3] = 0;
2405       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
2406       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
2407 #if 1
2408       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);
2409       for (p = 0; p < 4; ++p) {
2410         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);
2411       }
2412 #endif
2413       /* C' tetrahedron: {f, a, c, b} */
2414       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
2415       orntNew[0] = -2;
2416       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
2417       orntNew[1] = -2;
2418       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
2419       orntNew[2] = -1;
2420       coneNew[3] = fStartNew + (cone[0] - fStart)*4 + 3;
2421       orntNew[3] = ornt[0] < 0 ? -(GetTetSomething_Static(ornt[0], 2)+1) : GetTetSomething_Static(ornt[0], 2);
2422       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
2423       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
2424 #if 1
2425       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);
2426       for (p = 0; p < 4; ++p) {
2427         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);
2428       }
2429 #endif
2430       /* D' tetrahedron: {f, a, e, d} */
2431       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
2432       orntNew[0] = -2;
2433       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
2434       orntNew[1] = -1;
2435       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
2436       orntNew[2] = -2;
2437       coneNew[3] = fStartNew + (cone[1] - fStart)*4 + 3;
2438       orntNew[3] = ornt[1] < 0 ? -(GetTetSomething_Static(ornt[1], 1)+1) : GetTetSomething_Static(ornt[1], 1);
2439       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
2440       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
2441 #if 1
2442       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);
2443       for (p = 0; p < 4; ++p) {
2444         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);
2445       }
2446 #endif
2447     }
2448     /* Split faces have 3 edges and the same cells as the parent */
2449     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2450     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2451     for (f = fStart; f < fEnd; ++f) {
2452       const PetscInt  newp = fStartNew + (f - fStart)*4;
2453       const PetscInt *cone, *ornt, *support;
2454       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
2455 
2456       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2457       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
2458       /* A triangle */
2459       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
2460       orntNew[0] = ornt[0];
2461       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
2462       orntNew[1] = -2;
2463       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
2464       orntNew[2] = ornt[2];
2465       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2466       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2467 #if 1
2468       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);
2469       for (p = 0; p < 3; ++p) {
2470         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);
2471       }
2472 #endif
2473       /* B triangle */
2474       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
2475       orntNew[0] = ornt[0];
2476       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
2477       orntNew[1] = ornt[1];
2478       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
2479       orntNew[2] = -2;
2480       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2481       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2482 #if 1
2483       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);
2484       for (p = 0; p < 3; ++p) {
2485         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);
2486       }
2487 #endif
2488       /* C triangle */
2489       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
2490       orntNew[0] = -2;
2491       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
2492       orntNew[1] = ornt[1];
2493       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
2494       orntNew[2] = ornt[2];
2495       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2496       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2497 #if 1
2498       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);
2499       for (p = 0; p < 3; ++p) {
2500         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);
2501       }
2502 #endif
2503       /* D triangle */
2504       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
2505       orntNew[0] = 0;
2506       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
2507       orntNew[1] = 0;
2508       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
2509       orntNew[2] = 0;
2510       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2511       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2512 #if 1
2513       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);
2514       for (p = 0; p < 3; ++p) {
2515         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);
2516       }
2517 #endif
2518       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2519       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2520       for (r = 0; r < 4; ++r) {
2521         for (s = 0; s < supportSize; ++s) {
2522           PetscInt subf;
2523           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2524           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2525           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2526           for (c = 0; c < coneSize; ++c) {
2527             if (cone[c] == f) break;
2528           }
2529           subf = GetTriSubfaceInverse_Static(ornt[c], r);
2530           supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
2531         }
2532         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
2533 #if 1
2534         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);
2535         for (p = 0; p < supportSize; ++p) {
2536           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);
2537         }
2538 #endif
2539       }
2540     }
2541     /* Interior faces have 3 edges and 2 cells */
2542     for (c = cStart; c < cEnd; ++c) {
2543       PetscInt        newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8;
2544       const PetscInt *cone, *ornt;
2545       PetscInt        coneNew[3], orntNew[3];
2546       PetscInt        supportNew[2];
2547 
2548       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2549       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2550       /* Face A: {c, a, d} */
2551       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
2552       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2553       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
2554       orntNew[1] = ornt[1] < 0 ? -2 : 0;
2555       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 2);
2556       orntNew[2] = ornt[2] < 0 ? -2 : 0;
2557       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2558       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2559 #if 1
2560       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2561       for (p = 0; p < 3; ++p) {
2562         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);
2563       }
2564 #endif
2565       supportNew[0] = (c - cStart)*8 + 0;
2566       supportNew[1] = (c - cStart)*8 + 0+4;
2567       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2568 #if 1
2569       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2570       for (p = 0; p < 2; ++p) {
2571         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);
2572       }
2573 #endif
2574       ++newp;
2575       /* Face B: {a, b, e} */
2576       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
2577       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2578       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 0);
2579       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2580       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
2581       orntNew[2] = ornt[1] < 0 ? -2 : 0;
2582       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2583       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2584 #if 1
2585       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2586       for (p = 0; p < 3; ++p) {
2587         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);
2588       }
2589 #endif
2590       supportNew[0] = (c - cStart)*8 + 1;
2591       supportNew[1] = (c - cStart)*8 + 1+4;
2592       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2593 #if 1
2594       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2595       for (p = 0; p < 2; ++p) {
2596         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);
2597       }
2598 #endif
2599       ++newp;
2600       /* Face C: {c, f, b} */
2601       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
2602       orntNew[0] = ornt[2] < 0 ? -2 : 0;
2603       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
2604       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2605       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 1);
2606       orntNew[2] = ornt[0] < 0 ? -2 : 0;
2607       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2608       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2609 #if 1
2610       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2611       for (p = 0; p < 3; ++p) {
2612         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);
2613       }
2614 #endif
2615       supportNew[0] = (c - cStart)*8 + 2;
2616       supportNew[1] = (c - cStart)*8 + 2+4;
2617       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2618 #if 1
2619       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2620       for (p = 0; p < 2; ++p) {
2621         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
2622       }
2623 #endif
2624       ++newp;
2625       /* Face D: {d, e, f} */
2626       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 0);
2627       orntNew[0] = ornt[1] < 0 ? -2 : 0;
2628       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
2629       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2630       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
2631       orntNew[2] = ornt[2] < 0 ? -2 : 0;
2632       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2633       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2634 #if 1
2635       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2636       for (p = 0; p < 3; ++p) {
2637         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);
2638       }
2639 #endif
2640       supportNew[0] = (c - cStart)*8 + 3;
2641       supportNew[1] = (c - cStart)*8 + 3+4;
2642       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2643 #if 1
2644       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2645       for (p = 0; p < 2; ++p) {
2646         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);
2647       }
2648 #endif
2649       ++newp;
2650       /* Face E: {d, f, a} */
2651       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
2652       orntNew[0] = ornt[2] < 0 ? 0 : -2;
2653       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2654       orntNew[1] = -2;
2655       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
2656       orntNew[2] = ornt[1] < 0 ? -2 : 0;
2657       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2658       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2659 #if 1
2660       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2661       for (p = 0; p < 3; ++p) {
2662         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);
2663       }
2664 #endif
2665       supportNew[0] = (c - cStart)*8 + 0+4;
2666       supportNew[1] = (c - cStart)*8 + 3+4;
2667       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2668 #if 1
2669       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2670       for (p = 0; p < 2; ++p) {
2671         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);
2672       }
2673 #endif
2674       ++newp;
2675       /* Face F: {c, a, f} */
2676       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
2677       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2678       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2679       orntNew[1] = 0;
2680       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
2681       orntNew[2] = ornt[2] < 0 ? 0 : -2;
2682       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2683       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2684 #if 1
2685       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2686       for (p = 0; p < 3; ++p) {
2687         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);
2688       }
2689 #endif
2690       supportNew[0] = (c - cStart)*8 + 0+4;
2691       supportNew[1] = (c - cStart)*8 + 2+4;
2692       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2693 #if 1
2694       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2695       for (p = 0; p < 2; ++p) {
2696         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);
2697       }
2698 #endif
2699       ++newp;
2700       /* Face G: {e, a, f} */
2701       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
2702       orntNew[0] = ornt[1] < 0 ? -2 : 0;
2703       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2704       orntNew[1] = 0;
2705       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
2706       orntNew[2] = ornt[3] < 0 ? 0 : -2;
2707       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2708       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2709 #if 1
2710       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2711       for (p = 0; p < 3; ++p) {
2712         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);
2713       }
2714 #endif
2715       supportNew[0] = (c - cStart)*8 + 1+4;
2716       supportNew[1] = (c - cStart)*8 + 3+4;
2717       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2718 #if 1
2719       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2720       for (p = 0; p < 2; ++p) {
2721         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);
2722       }
2723 #endif
2724       ++newp;
2725       /* Face H: {a, b, f} */
2726       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
2727       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2728       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
2729       orntNew[1] = ornt[3] < 0 ? 0 : -2;
2730       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2731       orntNew[2] = -2;
2732       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2733       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2734 #if 1
2735       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2736       for (p = 0; p < 3; ++p) {
2737         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);
2738       }
2739 #endif
2740       supportNew[0] = (c - cStart)*8 + 1+4;
2741       supportNew[1] = (c - cStart)*8 + 2+4;
2742       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2743 #if 1
2744       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2745       for (p = 0; p < 2; ++p) {
2746         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);
2747       }
2748 #endif
2749       ++newp;
2750     }
2751     /* Split Edges have 2 vertices and the same faces as the parent */
2752     for (e = eStart; e < eEnd; ++e) {
2753       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
2754 
2755       for (r = 0; r < 2; ++r) {
2756         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
2757         const PetscInt *cone, *ornt, *support;
2758         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2759 
2760         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
2761         coneNew[0]       = vStartNew + (cone[0] - vStart);
2762         coneNew[1]       = vStartNew + (cone[1] - vStart);
2763         coneNew[(r+1)%2] = newv;
2764         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2765 #if 1
2766         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2767         for (p = 0; p < 2; ++p) {
2768           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);
2769         }
2770 #endif
2771         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
2772         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
2773         for (s = 0; s < supportSize; ++s) {
2774           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2775           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2776           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2777           for (c = 0; c < coneSize; ++c) {
2778             if (cone[c] == e) break;
2779           }
2780           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
2781         }
2782         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2783 #if 1
2784         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2785         for (p = 0; p < supportSize; ++p) {
2786           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);
2787         }
2788 #endif
2789       }
2790     }
2791     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
2792     for (f = fStart; f < fEnd; ++f) {
2793       const PetscInt *cone, *ornt, *support;
2794       PetscInt        coneSize, supportSize, s;
2795 
2796       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2797       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2798       for (r = 0; r < 3; ++r) {
2799         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
2800         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
2801         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
2802                                     -1, -1,  1,  6,  0,  4,
2803                                      2,  5,  3,  4, -1, -1,
2804                                     -1, -1,  3,  6,  2,  7};
2805 
2806         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2807         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
2808         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
2809         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2810 #if 1
2811         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2812         for (p = 0; p < 2; ++p) {
2813           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);
2814         }
2815 #endif
2816         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
2817         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
2818         for (s = 0; s < supportSize; ++s) {
2819           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2820           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2821           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2822           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
2823           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
2824           er = GetTetSomethingInverse_Static(ornt[c], r);
2825           if (er == eint[c]) {
2826             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
2827           } else {
2828             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
2829             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
2830           }
2831         }
2832         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2833 #if 1
2834         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2835         for (p = 0; p < intFaces; ++p) {
2836           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);
2837         }
2838 #endif
2839       }
2840     }
2841     /* Interior edges have 2 vertices and 4 faces */
2842     for (c = cStart; c < cEnd; ++c) {
2843       const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2844       const PetscInt *cone, *ornt, *fcone;
2845       PetscInt        coneNew[2], supportNew[4], find;
2846 
2847       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2848       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2849       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
2850       find = GetTriEdge_Static(ornt[0], 0);
2851       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
2852       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
2853       find = GetTriEdge_Static(ornt[2], 1);
2854       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
2855       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2856 #if 1
2857       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2858       for (p = 0; p < 2; ++p) {
2859         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);
2860       }
2861 #endif
2862       supportNew[0] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 4;
2863       supportNew[1] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 5;
2864       supportNew[2] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 6;
2865       supportNew[3] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 7;
2866       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2867 #if 1
2868       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2869       for (p = 0; p < 4; ++p) {
2870         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);
2871       }
2872 #endif
2873     }
2874     /* Old vertices have identical supports */
2875     for (v = vStart; v < vEnd; ++v) {
2876       const PetscInt  newp = vStartNew + (v - vStart);
2877       const PetscInt *support, *cone;
2878       PetscInt        size, s;
2879 
2880       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2881       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2882       for (s = 0; s < size; ++s) {
2883         PetscInt r = 0;
2884 
2885         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2886         if (cone[1] == v) r = 1;
2887         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
2888       }
2889       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2890 #if 1
2891       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2892       for (p = 0; p < size; ++p) {
2893         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);
2894       }
2895 #endif
2896     }
2897     /* Edge vertices have 2 + face*2 + 0/1 supports */
2898     for (e = eStart; e < eEnd; ++e) {
2899       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
2900       const PetscInt *cone, *support;
2901       PetscInt       *star = NULL, starSize, cellSize = 0, coneSize, size, s;
2902 
2903       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
2904       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
2905       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
2906       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
2907       for (s = 0; s < size; ++s) {
2908         PetscInt r = 0;
2909 
2910         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2911         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2912         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
2913         supportRef[2+s*2+0] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
2914         supportRef[2+s*2+1] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
2915       }
2916       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
2917       for (s = 0; s < starSize*2; s += 2) {
2918         const PetscInt *cone, *ornt;
2919         PetscInt        e01, e23;
2920 
2921         if ((star[s] >= cStart) && (star[s] < cEnd)) {
2922           /* Check edge 0-1 */
2923           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
2924           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
2925           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
2926           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
2927           /* Check edge 2-3 */
2928           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
2929           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
2930           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
2931           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
2932           if ((e01 == e) || (e23 == e)) {supportRef[2+size*2+cellSize++] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (star[s] - cStart);}
2933         }
2934       }
2935       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
2936       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2937 #if 1
2938       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2939       for (p = 0; p < 2+size*2+cellSize; ++p) {
2940         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);
2941       }
2942 #endif
2943     }
2944     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2945     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
2946     break;
2947   case REFINER_HYBRID_SIMPLEX_3D:
2948     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
2949     /* Interior cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
2950     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
2951     for (c = cStart; c < cMax; ++c) {
2952       const PetscInt  newp = cStartNew + (c - cStart)*8;
2953       const PetscInt *cone, *ornt;
2954       PetscInt        coneNew[4], orntNew[4];
2955 
2956       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2957       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2958       /* A tetrahedron: {0, a, c, d} */
2959       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
2960       orntNew[0] = ornt[0];
2961       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
2962       orntNew[1] = ornt[1];
2963       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
2964       orntNew[2] = ornt[2];
2965       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
2966       orntNew[3] = 0;
2967       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2968       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2969 #if 1
2970       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);
2971       for (p = 0; p < 4; ++p) {
2972         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);
2973       }
2974 #endif
2975       /* B tetrahedron: {a, 1, b, e} */
2976       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
2977       orntNew[0] = ornt[0];
2978       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
2979       orntNew[1] = ornt[1];
2980       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
2981       orntNew[2] = 0;
2982       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
2983       orntNew[3] = ornt[3];
2984       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2985       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2986 #if 1
2987       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);
2988       for (p = 0; p < 4; ++p) {
2989         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);
2990       }
2991 #endif
2992       /* C tetrahedron: {c, b, 2, f} */
2993       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
2994       orntNew[0] = ornt[0];
2995       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
2996       orntNew[1] = 0;
2997       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
2998       orntNew[2] = ornt[2];
2999       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
3000       orntNew[3] = ornt[3];
3001       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3002       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3003 #if 1
3004       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);
3005       for (p = 0; p < 4; ++p) {
3006         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);
3007       }
3008 #endif
3009       /* D tetrahedron: {d, e, f, 3} */
3010       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
3011       orntNew[0] = 0;
3012       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
3013       orntNew[1] = ornt[1];
3014       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
3015       orntNew[2] = ornt[2];
3016       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
3017       orntNew[3] = ornt[3];
3018       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3019       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3020 #if 1
3021       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);
3022       for (p = 0; p < 4; ++p) {
3023         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);
3024       }
3025 #endif
3026       /* A' tetrahedron: {d, a, c, f} */
3027       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
3028       orntNew[0] = -3;
3029       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
3030       orntNew[1] = ornt[2] < 0 ? -(GetTetSomething_Static(ornt[2], 0)+1) : GetTetSomething_Static(ornt[2], 0);
3031       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
3032       orntNew[2] = 0;
3033       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
3034       orntNew[3] = 2;
3035       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
3036       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
3037 #if 1
3038       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);
3039       for (p = 0; p < 4; ++p) {
3040         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);
3041       }
3042 #endif
3043       /* B' tetrahedron: {e, b, a, f} */
3044       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
3045       orntNew[0] = -3;
3046       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
3047       orntNew[1] = 1;
3048       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
3049       orntNew[2] = 0;
3050       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + 3;
3051       orntNew[3] = ornt[3] < 0 ? -(GetTetSomething_Static(ornt[3], 0)+1) : GetTetSomething_Static(ornt[3], 0);
3052       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
3053       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
3054 #if 1
3055       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);
3056       for (p = 0; p < 4; ++p) {
3057         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);
3058       }
3059 #endif
3060       /* C' tetrahedron: {b, f, c, a} */
3061       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
3062       orntNew[0] = -3;
3063       coneNew[1] = fStartNew + (cone[0] - fStart)*4 + 3;
3064       orntNew[1] = ornt[0] < 0 ? -(GetTetSomething_Static(ornt[0], 2)+1) : GetTetSomething_Static(ornt[0], 2);
3065       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
3066       orntNew[2] = -3;
3067       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
3068       orntNew[3] = -2;
3069       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
3070       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
3071 #if 1
3072       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);
3073       for (p = 0; p < 4; ++p) {
3074         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);
3075       }
3076 #endif
3077       /* D' tetrahedron: {f, e, d, a} */
3078       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
3079       orntNew[0] = -3;
3080       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
3081       orntNew[1] = -3;
3082       coneNew[2] = fStartNew + (cone[1] - fStart)*4 + 3;
3083       orntNew[2] = ornt[1] < 0 ? -(GetTetSomething_Static(ornt[1], 0)+1) : GetTetSomething_Static(ornt[1], 0);
3084       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
3085       orntNew[3] = -3;
3086       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
3087       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
3088 #if 1
3089       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);
3090       for (p = 0; p < 4; ++p) {
3091         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);
3092       }
3093 #endif
3094     }
3095     /* Hybrid cells have 5 faces */
3096     for (c = cMax; c < cEnd; ++c) {
3097       const PetscInt  newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4;
3098       const PetscInt *cone, *ornt, *fornt;
3099       PetscInt        coneNew[5], orntNew[5], o, of, i;
3100 
3101       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3102       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3103       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
3104       o = ornt[0] < 0 ? -1 : 1;
3105       for (r = 0; r < 3; ++r) {
3106         coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], r);
3107         orntNew[0] = ornt[0];
3108         coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], r);
3109         orntNew[1] = ornt[1];
3110         of = fornt[GetTriEdge_Static(ornt[0], r)]       < 0 ? -1 : 1;
3111         i  = GetTriEdgeInverse_Static(ornt[0], r)       + 2;
3112         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], r)]       - fMax)*2 + (o*of < 0 ? 1 : 0);
3113         orntNew[i] = 0;
3114         i  = GetTriEdgeInverse_Static(ornt[0], (r+1)%3) + 2;
3115         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + GetTriSubface_Static(ornt[0], r);
3116         orntNew[i] = 0;
3117         of = fornt[GetTriEdge_Static(ornt[0], (r+2)%3)] < 0 ? -1 : 1;
3118         i  = GetTriEdgeInverse_Static(ornt[0], (r+2)%3) + 2;
3119         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);
3120         orntNew[i] = 0;
3121         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
3122         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
3123 #if 1
3124         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);
3125         for (p = 0; p < 2; ++p) {
3126           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);
3127         }
3128         for (p = 2; p < 5; ++p) {
3129           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);
3130         }
3131 #endif
3132       }
3133       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + 3;
3134       orntNew[0] = 0;
3135       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + 3;
3136       orntNew[1] = 0;
3137       coneNew[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
3138       orntNew[2] = 0;
3139       coneNew[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
3140       orntNew[3] = 0;
3141       coneNew[4] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
3142       orntNew[4] = 0;
3143       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3144       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3145 #if 1
3146       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);
3147       for (p = 0; p < 2; ++p) {
3148         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);
3149       }
3150       for (p = 2; p < 5; ++p) {
3151         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);
3152       }
3153 #endif
3154     }
3155     /* Split faces have 3 edges and the same cells as the parent */
3156     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3157     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
3158     for (f = fStart; f < fMax; ++f) {
3159       const PetscInt  newp = fStartNew + (f - fStart)*4;
3160       const PetscInt *cone, *ornt, *support;
3161       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
3162 
3163       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3164       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3165       /* A triangle */
3166       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
3167       orntNew[0] = ornt[0];
3168       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
3169       orntNew[1] = -2;
3170       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
3171       orntNew[2] = ornt[2];
3172       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3173       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3174 #if 1
3175       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);
3176       for (p = 0; p < 3; ++p) {
3177         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);
3178       }
3179 #endif
3180       /* B triangle */
3181       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
3182       orntNew[0] = ornt[0];
3183       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
3184       orntNew[1] = ornt[1];
3185       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
3186       orntNew[2] = -2;
3187       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3188       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3189 #if 1
3190       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);
3191       for (p = 0; p < 3; ++p) {
3192         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);
3193       }
3194 #endif
3195       /* C triangle */
3196       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
3197       orntNew[0] = -2;
3198       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
3199       orntNew[1] = ornt[1];
3200       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
3201       orntNew[2] = ornt[2];
3202       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3203       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3204 #if 1
3205       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);
3206       for (p = 0; p < 3; ++p) {
3207         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);
3208       }
3209 #endif
3210       /* D triangle */
3211       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
3212       orntNew[0] = 0;
3213       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
3214       orntNew[1] = 0;
3215       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
3216       orntNew[2] = 0;
3217       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3218       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3219 #if 1
3220       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);
3221       for (p = 0; p < 3; ++p) {
3222         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);
3223       }
3224 #endif
3225       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3226       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3227       for (r = 0; r < 4; ++r) {
3228         for (s = 0; s < supportSize; ++s) {
3229           PetscInt subf;
3230           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3231           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3232           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3233           for (c = 0; c < coneSize; ++c) {
3234             if (cone[c] == f) break;
3235           }
3236           subf = GetTriSubfaceInverse_Static(ornt[c], r);
3237           if (support[s] < cMax) {
3238             supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
3239           } else {
3240             supportRef[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (r==3 ? r : subf);
3241           }
3242         }
3243         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
3244 #if 1
3245         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);
3246         for (p = 0; p < supportSize; ++p) {
3247           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);
3248         }
3249 #endif
3250       }
3251     }
3252     /* Interior cell faces have 3 edges and 2 cells */
3253     for (c = cStart; c < cMax; ++c) {
3254       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8;
3255       const PetscInt *cone, *ornt;
3256       PetscInt        coneNew[3], orntNew[3];
3257       PetscInt        supportNew[2];
3258 
3259       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3260       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3261       /* Face A: {c, a, d} */
3262       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
3263       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3264       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
3265       orntNew[1] = ornt[1] < 0 ? -2 : 0;
3266       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 2);
3267       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3268       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3269       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3270 #if 1
3271       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3272       for (p = 0; p < 3; ++p) {
3273         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);
3274       }
3275 #endif
3276       supportNew[0] = (c - cStart)*8 + 0;
3277       supportNew[1] = (c - cStart)*8 + 0+4;
3278       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3279 #if 1
3280       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3281       for (p = 0; p < 2; ++p) {
3282         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);
3283       }
3284 #endif
3285       ++newp;
3286       /* Face B: {a, b, e} */
3287       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
3288       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3289       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 0);
3290       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3291       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
3292       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3293       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3294       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3295 #if 1
3296       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);
3297       for (p = 0; p < 3; ++p) {
3298         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);
3299       }
3300 #endif
3301       supportNew[0] = (c - cStart)*8 + 1;
3302       supportNew[1] = (c - cStart)*8 + 1+4;
3303       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3304 #if 1
3305       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3306       for (p = 0; p < 2; ++p) {
3307         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);
3308       }
3309 #endif
3310       ++newp;
3311       /* Face C: {c, f, b} */
3312       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
3313       orntNew[0] = ornt[2] < 0 ? -2 : 0;
3314       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
3315       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3316       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 1);
3317       orntNew[2] = ornt[0] < 0 ? -2 : 0;
3318       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3319       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3320 #if 1
3321       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3322       for (p = 0; p < 3; ++p) {
3323         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);
3324       }
3325 #endif
3326       supportNew[0] = (c - cStart)*8 + 2;
3327       supportNew[1] = (c - cStart)*8 + 2+4;
3328       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3329 #if 1
3330       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3331       for (p = 0; p < 2; ++p) {
3332         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);
3333       }
3334 #endif
3335       ++newp;
3336       /* Face D: {d, e, f} */
3337       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 0);
3338       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3339       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
3340       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3341       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
3342       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3343       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3344       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3345 #if 1
3346       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3347       for (p = 0; p < 3; ++p) {
3348         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);
3349       }
3350 #endif
3351       supportNew[0] = (c - cStart)*8 + 3;
3352       supportNew[1] = (c - cStart)*8 + 3+4;
3353       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3354 #if 1
3355       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3356       for (p = 0; p < 2; ++p) {
3357         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);
3358       }
3359 #endif
3360       ++newp;
3361       /* Face E: {d, f, a} */
3362       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
3363       orntNew[0] = ornt[2] < 0 ? 0 : -2;
3364       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3365       orntNew[1] = -2;
3366       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
3367       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3368       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3369       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3370 #if 1
3371       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3372       for (p = 0; p < 3; ++p) {
3373         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);
3374       }
3375 #endif
3376       supportNew[0] = (c - cStart)*8 + 0+4;
3377       supportNew[1] = (c - cStart)*8 + 3+4;
3378       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3379 #if 1
3380       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3381       for (p = 0; p < 2; ++p) {
3382         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);
3383       }
3384 #endif
3385       ++newp;
3386       /* Face F: {c, a, f} */
3387       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
3388       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3389       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3390       orntNew[1] = 0;
3391       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
3392       orntNew[2] = ornt[2] < 0 ? 0 : -2;
3393       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3394       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3395 #if 1
3396       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3397       for (p = 0; p < 3; ++p) {
3398         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);
3399       }
3400 #endif
3401       supportNew[0] = (c - cStart)*8 + 0+4;
3402       supportNew[1] = (c - cStart)*8 + 2+4;
3403       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3404 #if 1
3405       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3406       for (p = 0; p < 2; ++p) {
3407         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);
3408       }
3409 #endif
3410       ++newp;
3411       /* Face G: {e, a, f} */
3412       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
3413       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3414       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3415       orntNew[1] = 0;
3416       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
3417       orntNew[2] = ornt[3] < 0 ? 0 : -2;
3418       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3419       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3420 #if 1
3421       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3422       for (p = 0; p < 3; ++p) {
3423         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);
3424       }
3425 #endif
3426       supportNew[0] = (c - cStart)*8 + 1+4;
3427       supportNew[1] = (c - cStart)*8 + 3+4;
3428       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3429 #if 1
3430       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3431       for (p = 0; p < 2; ++p) {
3432         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);
3433       }
3434 #endif
3435       ++newp;
3436       /* Face H: {a, b, f} */
3437       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
3438       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3439       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
3440       orntNew[1] = ornt[3] < 0 ? 0 : -2;
3441       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3442       orntNew[2] = -2;
3443       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3444       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3445 #if 1
3446       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3447       for (p = 0; p < 3; ++p) {
3448         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);
3449       }
3450 #endif
3451       supportNew[0] = (c - cStart)*8 + 1+4;
3452       supportNew[1] = (c - cStart)*8 + 2+4;
3453       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3454 #if 1
3455       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3456       for (p = 0; p < 2; ++p) {
3457         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);
3458       }
3459 #endif
3460       ++newp;
3461     }
3462     /* Hybrid split faces have 4 edges and same cells */
3463     for (f = fMax; f < fEnd; ++f) {
3464       const PetscInt *cone, *ornt, *support;
3465       PetscInt        coneNew[4], orntNew[4];
3466       PetscInt        supportNew[2], size, s, c;
3467 
3468       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3469       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3470       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3471       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3472       for (r = 0; r < 2; ++r) {
3473         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
3474 
3475         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
3476         orntNew[0]   = ornt[0];
3477         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
3478         orntNew[1]   = ornt[1];
3479         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (cone[2+r] - eMax);
3480         orntNew[2+r] = 0;
3481         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd      - eMax) + (f - fMax);
3482         orntNew[3-r] = 0;
3483         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3484         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3485 #if 1
3486         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
3487         for (p = 0; p < 2; ++p) {
3488           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);
3489         }
3490         for (p = 2; p < 4; ++p) {
3491           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);
3492         }
3493 #endif
3494         for (s = 0; s < size; ++s) {
3495           const PetscInt *coneCell, *orntCell, *fornt;
3496           PetscInt        o, of;
3497 
3498           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
3499           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
3500           o = orntCell[0] < 0 ? -1 : 1;
3501           for (c = 2; c < 5; ++c) if (coneCell[c] == f) break;
3502           if (c >= 5) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
3503           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
3504           of = fornt[c-2] < 0 ? -1 : 1;
3505           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetTriEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%3;
3506         }
3507         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3508 #if 1
3509         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
3510         for (p = 0; p < size; ++p) {
3511           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);
3512         }
3513 #endif
3514       }
3515     }
3516     /* Hybrid cell faces have 4 edges and 2 cells */
3517     for (c = cMax; c < cEnd; ++c) {
3518       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3;
3519       const PetscInt *cone, *ornt;
3520       PetscInt        coneNew[4], orntNew[4];
3521       PetscInt        supportNew[2];
3522 
3523       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3524       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3525       for (r = 0; r < 3; ++r) {
3526         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + (r+2)%3;
3527         orntNew[0] = 0;
3528         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + (r+2)%3;
3529         orntNew[1] = 0;
3530         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+(r+2)%3] - fMax);
3531         orntNew[2] = 0;
3532         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+r]       - fMax);
3533         orntNew[3] = 0;
3534         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
3535         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
3536 #if 1
3537         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);
3538         for (p = 0; p < 2; ++p) {
3539           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);
3540         }
3541         for (p = 2; p < 4; ++p) {
3542           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);
3543         }
3544 #endif
3545         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetTriSubface_Static(ornt[0], r);
3546         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + 3;
3547         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
3548 #if 1
3549         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);
3550         for (p = 0; p < 2; ++p) {
3551           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);
3552         }
3553 #endif
3554       }
3555     }
3556     /* Interior split edges have 2 vertices and the same faces as the parent */
3557     for (e = eStart; e < eMax; ++e) {
3558       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
3559 
3560       for (r = 0; r < 2; ++r) {
3561         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
3562         const PetscInt *cone, *ornt, *support;
3563         PetscInt        coneNew[2], coneSize, c, supportSize, s;
3564 
3565         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3566         coneNew[0]       = vStartNew + (cone[0] - vStart);
3567         coneNew[1]       = vStartNew + (cone[1] - vStart);
3568         coneNew[(r+1)%2] = newv;
3569         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3570 #if 1
3571         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3572         for (p = 0; p < 2; ++p) {
3573           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);
3574         }
3575 #endif
3576         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
3577         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3578         for (s = 0; s < supportSize; ++s) {
3579           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3580           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3581           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3582           for (c = 0; c < coneSize; ++c) if (cone[c] == e) break;
3583           if (support[s] < fMax) {
3584             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
3585           } else {
3586             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
3587           }
3588         }
3589         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3590 #if 1
3591         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3592         for (p = 0; p < supportSize; ++p) {
3593           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);
3594         }
3595 #endif
3596       }
3597     }
3598     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
3599     for (f = fStart; f < fMax; ++f) {
3600       const PetscInt *cone, *ornt, *support;
3601       PetscInt        coneSize, supportSize, s;
3602 
3603       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3604       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3605       for (r = 0; r < 3; ++r) {
3606         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
3607         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
3608         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
3609                                     -1, -1,  1,  6,  0,  4,
3610                                      2,  5,  3,  4, -1, -1,
3611                                     -1, -1,  3,  6,  2,  7};
3612 
3613         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3614         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
3615         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
3616         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3617 #if 1
3618         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3619         for (p = 0; p < 2; ++p) {
3620           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);
3621         }
3622 #endif
3623         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
3624         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
3625         for (s = 0; s < supportSize; ++s) {
3626           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3627           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3628           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3629           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
3630           if (support[s] < cMax) {
3631             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
3632             er = GetTetSomethingInverse_Static(ornt[c], r);
3633             if (er == eint[c]) {
3634               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
3635             } else {
3636               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
3637               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
3638             }
3639           } else {
3640             supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (r + 1)%3;
3641           }
3642         }
3643         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3644 #if 1
3645         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3646         for (p = 0; p < intFaces; ++p) {
3647           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);
3648         }
3649 #endif
3650       }
3651     }
3652     /* Interior cell edges have 2 vertices and 4 faces */
3653     for (c = cStart; c < cMax; ++c) {
3654       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3655       const PetscInt *cone, *ornt, *fcone;
3656       PetscInt        coneNew[2], supportNew[4], find;
3657 
3658       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3659       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3660       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
3661       find = GetTriEdge_Static(ornt[0], 0);
3662       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3663       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
3664       find = GetTriEdge_Static(ornt[2], 1);
3665       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3666       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3667 #if 1
3668       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3669       for (p = 0; p < 2; ++p) {
3670         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);
3671       }
3672 #endif
3673       supportNew[0] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 4;
3674       supportNew[1] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 5;
3675       supportNew[2] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 6;
3676       supportNew[3] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 7;
3677       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3678 #if 1
3679       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3680       for (p = 0; p < 4; ++p) {
3681         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);
3682       }
3683 #endif
3684     }
3685     /* Hybrid edges have two vertices and the same faces */
3686     for (e = eMax; e < eEnd; ++e) {
3687       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
3688       const PetscInt *cone, *support, *fcone;
3689       PetscInt        coneNew[2], size, fsize, s;
3690 
3691       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3692       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
3693       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3694       coneNew[0] = vStartNew + (cone[0] - vStart);
3695       coneNew[1] = vStartNew + (cone[1] - vStart);
3696       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3697 #if 1
3698       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3699       for (p = 0; p < 2; ++p) {
3700         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);
3701       }
3702 #endif
3703       for (s = 0; s < size; ++s) {
3704         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
3705         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
3706         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
3707         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
3708         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + c-2;
3709       }
3710       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3711 #if 1
3712       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3713       for (p = 0; p < size; ++p) {
3714         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);
3715       }
3716 #endif
3717     }
3718     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
3719     for (f = fMax; f < fEnd; ++f) {
3720       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
3721       const PetscInt *cone, *support, *ccone, *cornt;
3722       PetscInt        coneNew[2], size, csize, s;
3723 
3724       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3725       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3726       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3727       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
3728       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
3729       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3730 #if 1
3731       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3732       for (p = 0; p < 2; ++p) {
3733         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);
3734       }
3735 #endif
3736       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 0;
3737       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 1;
3738       for (s = 0; s < size; ++s) {
3739         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
3740         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
3741         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
3742         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
3743         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]);
3744         supportRef[2+s*2+0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + c-2;
3745         supportRef[2+s*2+1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (c-1)%3;
3746       }
3747       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3748 #if 1
3749       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3750       for (p = 0; p < 2+size*2; ++p) {
3751         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);
3752       }
3753 #endif
3754     }
3755     /* Interior vertices have identical supports */
3756     for (v = vStart; v < vEnd; ++v) {
3757       const PetscInt  newp = vStartNew + (v - vStart);
3758       const PetscInt *support, *cone;
3759       PetscInt        size, s;
3760 
3761       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
3762       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
3763       for (s = 0; s < size; ++s) {
3764         PetscInt r = 0;
3765 
3766         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3767         if (cone[1] == v) r = 1;
3768         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
3769         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (support[s] - eMax);
3770       }
3771       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3772 #if 1
3773       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3774       for (p = 0; p < size; ++p) {
3775         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);
3776       }
3777 #endif
3778     }
3779     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
3780     for (e = eStart; e < eMax; ++e) {
3781       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
3782       const PetscInt *cone, *support;
3783       PetscInt       *star = NULL, starSize, faceSize = 0, cellSize = 0, coneSize, size, s;
3784 
3785       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
3786       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3787       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
3788       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
3789       for (s = 0; s < size; ++s) {
3790         PetscInt r = 0;
3791 
3792         if (support[s] < fMax) {
3793           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3794           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3795           for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
3796           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
3797           supportRef[2+faceSize+1] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
3798           faceSize += 2;
3799         } else {
3800           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (support[s] - fMax);
3801           ++faceSize;
3802         }
3803       }
3804       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
3805       for (s = 0; s < starSize*2; s += 2) {
3806         const PetscInt *cone, *ornt;
3807         PetscInt        e01, e23;
3808 
3809         if ((star[s] >= cStart) && (star[s] < cMax)) {
3810           /* Check edge 0-1 */
3811           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
3812           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
3813           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
3814           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
3815           /* Check edge 2-3 */
3816           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
3817           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
3818           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
3819           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
3820           if ((e01 == e) || (e23 == e)) {supportRef[2+faceSize+cellSize++] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (star[s] - cStart);}
3821         }
3822       }
3823       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
3824       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3825 #if 1
3826       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3827       for (p = 0; p < 2+faceSize+cellSize; ++p) {
3828         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);
3829       }
3830 #endif
3831     }
3832     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3833     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
3834     break;
3835   case REFINER_HEX_3D:
3836     /*
3837      Bottom (viewed from top)    Top
3838      1---------2---------2       7---------2---------6
3839      |         |         |       |         |         |
3840      |    B    2    C    |       |    H    2    G    |
3841      |         |         |       |         |         |
3842      3----3----0----1----1       3----3----0----1----1
3843      |         |         |       |         |         |
3844      |    A    0    D    |       |    E    0    F    |
3845      |         |         |       |         |         |
3846      0---------0---------3       4---------0---------5
3847      */
3848     /* All cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
3849     for (c = cStart; c < cEnd; ++c) {
3850       const PetscInt  newp = (c - cStart)*8;
3851       const PetscInt *cone, *ornt;
3852       PetscInt        coneNew[6], orntNew[6];
3853 
3854       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3855       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3856       /* A hex */
3857       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
3858       orntNew[0] = ornt[0];
3859       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
3860       orntNew[1] = 0;
3861       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
3862       orntNew[2] = ornt[2];
3863       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
3864       orntNew[3] = 0;
3865       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
3866       orntNew[4] = 0;
3867       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
3868       orntNew[5] = ornt[5];
3869       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3870       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3871 #if 1
3872       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);
3873       for (p = 0; p < 6; ++p) {
3874         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);
3875       }
3876 #endif
3877       /* B hex */
3878       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
3879       orntNew[0] = ornt[0];
3880       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
3881       orntNew[1] = 0;
3882       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
3883       orntNew[2] = -1;
3884       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
3885       orntNew[3] = ornt[3];
3886       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
3887       orntNew[4] = 0;
3888       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
3889       orntNew[5] = ornt[5];
3890       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3891       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3892 #if 1
3893       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);
3894       for (p = 0; p < 6; ++p) {
3895         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);
3896       }
3897 #endif
3898       /* C hex */
3899       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
3900       orntNew[0] = ornt[0];
3901       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
3902       orntNew[1] = 0;
3903       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
3904       orntNew[2] = -1;
3905       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
3906       orntNew[3] = ornt[3];
3907       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
3908       orntNew[4] = ornt[4];
3909       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
3910       orntNew[5] = -4;
3911       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3912       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3913 #if 1
3914       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);
3915       for (p = 0; p < 6; ++p) {
3916         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);
3917       }
3918 #endif
3919       /* D hex */
3920       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
3921       orntNew[0] = ornt[0];
3922       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
3923       orntNew[1] = 0;
3924       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
3925       orntNew[2] = ornt[2];
3926       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
3927       orntNew[3] = 0;
3928       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
3929       orntNew[4] = ornt[4];
3930       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
3931       orntNew[5] = -4;
3932       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3933       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3934 #if 1
3935       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);
3936       for (p = 0; p < 6; ++p) {
3937         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);
3938       }
3939 #endif
3940       /* E hex */
3941       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
3942       orntNew[0] = -4;
3943       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
3944       orntNew[1] = ornt[1];
3945       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
3946       orntNew[2] = ornt[2];
3947       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
3948       orntNew[3] = 0;
3949       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
3950       orntNew[4] = -1;
3951       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
3952       orntNew[5] = ornt[5];
3953       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
3954       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
3955 #if 1
3956       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);
3957       for (p = 0; p < 6; ++p) {
3958         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);
3959       }
3960 #endif
3961       /* F hex */
3962       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
3963       orntNew[0] = -4;
3964       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
3965       orntNew[1] = ornt[1];
3966       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
3967       orntNew[2] = ornt[2];
3968       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
3969       orntNew[3] = -1;
3970       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
3971       orntNew[4] = ornt[4];
3972       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
3973       orntNew[5] = 1;
3974       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
3975       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
3976 #if 1
3977       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);
3978       for (p = 0; p < 6; ++p) {
3979         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);
3980       }
3981 #endif
3982       /* G hex */
3983       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
3984       orntNew[0] = -4;
3985       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
3986       orntNew[1] = ornt[1];
3987       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
3988       orntNew[2] = 0;
3989       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
3990       orntNew[3] = ornt[3];
3991       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
3992       orntNew[4] = ornt[4];
3993       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
3994       orntNew[5] = -3;
3995       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
3996       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
3997 #if 1
3998       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);
3999       for (p = 0; p < 6; ++p) {
4000         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);
4001       }
4002 #endif
4003       /* H hex */
4004       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
4005       orntNew[0] = -4;
4006       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
4007       orntNew[1] = ornt[1];
4008       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
4009       orntNew[2] = -1;
4010       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
4011       orntNew[3] = ornt[3];
4012       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
4013       orntNew[4] = 3;
4014       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
4015       orntNew[5] = ornt[5];
4016       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
4017       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
4018 #if 1
4019       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);
4020       for (p = 0; p < 6; ++p) {
4021         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);
4022       }
4023 #endif
4024     }
4025     /* Split faces have 4 edges and the same cells as the parent */
4026     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4027     ierr = PetscMalloc1(4 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
4028     for (f = fStart; f < fEnd; ++f) {
4029       for (r = 0; r < 4; ++r) {
4030         /* TODO: This can come from GetFaces_Internal() */
4031         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};
4032         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
4033         const PetscInt *cone, *ornt, *support;
4034         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
4035 
4036         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4037         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4038         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
4039         orntNew[(r+3)%4] = ornt[(r+3)%4];
4040         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
4041         orntNew[(r+0)%4] = ornt[r];
4042         coneNew[(r+1)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
4043         orntNew[(r+1)%4] = 0;
4044         coneNew[(r+2)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + (r+3)%4;
4045         orntNew[(r+2)%4] = -2;
4046         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4047         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4048 #if 1
4049         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4050         for (p = 0; p < 4; ++p) {
4051           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);
4052         }
4053 #endif
4054         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4055         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4056         for (s = 0; s < supportSize; ++s) {
4057           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4058           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4059           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4060           for (c = 0; c < coneSize; ++c) {
4061             if (cone[c] == f) break;
4062           }
4063           supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+GetQuadSubfaceInverse_Static(ornt[c], r)];
4064         }
4065         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4066 #if 1
4067         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4068         for (p = 0; p < supportSize; ++p) {
4069           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);
4070         }
4071 #endif
4072       }
4073     }
4074     /* Interior faces have 4 edges and 2 cells */
4075     for (c = cStart; c < cEnd; ++c) {
4076       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};
4077       const PetscInt *cone, *ornt;
4078       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
4079 
4080       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4081       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4082       /* A-D face */
4083       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 0;
4084       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
4085       orntNew[0] = 0;
4086       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
4087       orntNew[1] = 0;
4088       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
4089       orntNew[2] = -2;
4090       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
4091       orntNew[3] = -2;
4092       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4093       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4094 #if 1
4095       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4096       for (p = 0; p < 4; ++p) {
4097         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);
4098       }
4099 #endif
4100       /* C-D face */
4101       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 1;
4102       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
4103       orntNew[0] = 0;
4104       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
4105       orntNew[1] = 0;
4106       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
4107       orntNew[2] = -2;
4108       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
4109       orntNew[3] = -2;
4110       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4111       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4112 #if 1
4113       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4114       for (p = 0; p < 4; ++p) {
4115         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);
4116       }
4117 #endif
4118       /* B-C face */
4119       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 2;
4120       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
4121       orntNew[0] = -2;
4122       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
4123       orntNew[1] = 0;
4124       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
4125       orntNew[2] = 0;
4126       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
4127       orntNew[3] = -2;
4128       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4129       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4130 #if 1
4131       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4132       for (p = 0; p < 4; ++p) {
4133         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);
4134       }
4135 #endif
4136       /* A-B face */
4137       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 3;
4138       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
4139       orntNew[0] = -2;
4140       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
4141       orntNew[1] = 0;
4142       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
4143       orntNew[2] = 0;
4144       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
4145       orntNew[3] = -2;
4146       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4147       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4148 #if 1
4149       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4150       for (p = 0; p < 4; ++p) {
4151         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);
4152       }
4153 #endif
4154       /* E-F face */
4155       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 4;
4156       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
4157       orntNew[0] = -2;
4158       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
4159       orntNew[1] = -2;
4160       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
4161       orntNew[2] = 0;
4162       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
4163       orntNew[3] = 0;
4164       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4165       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4166 #if 1
4167       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4168       for (p = 0; p < 4; ++p) {
4169         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);
4170       }
4171 #endif
4172       /* F-G face */
4173       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 5;
4174       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
4175       orntNew[0] = -2;
4176       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
4177       orntNew[1] = -2;
4178       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
4179       orntNew[2] = 0;
4180       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
4181       orntNew[3] = 0;
4182       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4183       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4184 #if 1
4185       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4186       for (p = 0; p < 4; ++p) {
4187         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);
4188       }
4189 #endif
4190       /* G-H face */
4191       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 6;
4192       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
4193       orntNew[0] = -2;
4194       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
4195       orntNew[1] = 0;
4196       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
4197       orntNew[2] = 0;
4198       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
4199       orntNew[3] = -2;
4200       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4201       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4202 #if 1
4203       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4204       for (p = 0; p < 4; ++p) {
4205         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);
4206       }
4207 #endif
4208       /* E-H face */
4209       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 7;
4210       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
4211       orntNew[0] = -2;
4212       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
4213       orntNew[1] = -2;
4214       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
4215       orntNew[2] = 0;
4216       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
4217       orntNew[3] = 0;
4218       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4219       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4220 #if 1
4221       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4222       for (p = 0; p < 4; ++p) {
4223         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);
4224       }
4225 #endif
4226       /* A-E face */
4227       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 8;
4228       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
4229       orntNew[0] = 0;
4230       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
4231       orntNew[1] = 0;
4232       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
4233       orntNew[2] = -2;
4234       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
4235       orntNew[3] = -2;
4236       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4237       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4238 #if 1
4239       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4240       for (p = 0; p < 4; ++p) {
4241         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);
4242       }
4243 #endif
4244       /* D-F face */
4245       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 9;
4246       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
4247       orntNew[0] = -2;
4248       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
4249       orntNew[1] = 0;
4250       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
4251       orntNew[2] = 0;
4252       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
4253       orntNew[3] = -2;
4254       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4255       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4256 #if 1
4257       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4258       for (p = 0; p < 4; ++p) {
4259         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);
4260       }
4261 #endif
4262       /* C-G face */
4263       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 10;
4264       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
4265       orntNew[0] = -2;
4266       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
4267       orntNew[1] = -2;
4268       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
4269       orntNew[2] = 0;
4270       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
4271       orntNew[3] = 0;
4272       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4273       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4274 #if 1
4275       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4276       for (p = 0; p < 4; ++p) {
4277         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);
4278       }
4279 #endif
4280       /* B-H face */
4281       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 11;
4282       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
4283       orntNew[0] = 0;
4284       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
4285       orntNew[1] = -2;
4286       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
4287       orntNew[2] = -2;
4288       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
4289       orntNew[3] = 0;
4290       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4291       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4292 #if 1
4293       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4294       for (p = 0; p < 4; ++p) {
4295         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);
4296       }
4297 #endif
4298       for (r = 0; r < 12; ++r) {
4299         newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
4300         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
4301         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
4302         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4303 #if 1
4304         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4305         for (p = 0; p < 2; ++p) {
4306           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);
4307         }
4308 #endif
4309       }
4310     }
4311     /* Split edges have 2 vertices and the same faces as the parent */
4312     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4313     for (e = eStart; e < eEnd; ++e) {
4314       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
4315 
4316       for (r = 0; r < 2; ++r) {
4317         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
4318         const PetscInt *cone, *ornt, *support;
4319         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4320 
4321         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4322         coneNew[0]       = vStartNew + (cone[0] - vStart);
4323         coneNew[1]       = vStartNew + (cone[1] - vStart);
4324         coneNew[(r+1)%2] = newv;
4325         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4326 #if 1
4327         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4328         for (p = 0; p < 2; ++p) {
4329           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);
4330         }
4331 #endif
4332         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
4333         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4334         for (s = 0; s < supportSize; ++s) {
4335           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4336           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4337           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4338           for (c = 0; c < coneSize; ++c) {
4339             if (cone[c] == e) break;
4340           }
4341           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
4342         }
4343         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4344 #if 1
4345         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4346         for (p = 0; p < supportSize; ++p) {
4347           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);
4348         }
4349 #endif
4350       }
4351     }
4352     /* Face edges have 2 vertices and 2+cells faces */
4353     for (f = fStart; f < fEnd; ++f) {
4354       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};
4355       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
4356       const PetscInt *cone, *coneCell, *orntCell, *support;
4357       PetscInt        coneNew[2], coneSize, c, supportSize, s;
4358 
4359       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4360       for (r = 0; r < 4; ++r) {
4361         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
4362 
4363         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
4364         coneNew[1] = newv;
4365         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4366 #if 1
4367         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4368         for (p = 0; p < 2; ++p) {
4369           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);
4370         }
4371 #endif
4372         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4373         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4374         supportRef[0] = fStartNew + (f - fStart)*4 + r;
4375         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
4376         for (s = 0; s < supportSize; ++s) {
4377           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4378           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
4379           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
4380           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
4381           supportRef[2+s] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
4382         }
4383         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4384 #if 1
4385         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4386         for (p = 0; p < 2+supportSize; ++p) {
4387           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);
4388         }
4389 #endif
4390       }
4391     }
4392     /* Cell edges have 2 vertices and 4 faces */
4393     for (c = cStart; c < cEnd; ++c) {
4394       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};
4395       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
4396       const PetscInt *cone;
4397       PetscInt        coneNew[2], supportNew[4];
4398 
4399       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4400       for (r = 0; r < 6; ++r) {
4401         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
4402 
4403         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
4404         coneNew[1] = newv;
4405         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4406 #if 1
4407         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4408         for (p = 0; p < 2; ++p) {
4409           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);
4410         }
4411 #endif
4412         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
4413         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4414 #if 1
4415         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4416         for (p = 0; p < 4; ++p) {
4417           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);
4418         }
4419 #endif
4420       }
4421     }
4422     /* Old vertices have identical supports */
4423     for (v = vStart; v < vEnd; ++v) {
4424       const PetscInt  newp = vStartNew + (v - vStart);
4425       const PetscInt *support, *cone;
4426       PetscInt        size, s;
4427 
4428       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4429       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4430       for (s = 0; s < size; ++s) {
4431         PetscInt r = 0;
4432 
4433         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4434         if (cone[1] == v) r = 1;
4435         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4436       }
4437       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4438 #if 1
4439       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4440       for (p = 0; p < size; ++p) {
4441         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);
4442       }
4443 #endif
4444     }
4445     /* Edge vertices have 2 + faces supports */
4446     for (e = eStart; e < eEnd; ++e) {
4447       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4448       const PetscInt *cone, *support;
4449       PetscInt        size, s;
4450 
4451       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4452       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4453       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4454       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4455       for (s = 0; s < size; ++s) {
4456         PetscInt r;
4457 
4458         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4459         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
4460         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*4 + r;
4461       }
4462       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4463 #if 1
4464       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4465       for (p = 0; p < 2+size; ++p) {
4466         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);
4467       }
4468 #endif
4469     }
4470     /* Face vertices have 4 + cells supports */
4471     for (f = fStart; f < fEnd; ++f) {
4472       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
4473       const PetscInt *cone, *support;
4474       PetscInt        size, s;
4475 
4476       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4477       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4478       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eEnd - eStart)*2 +  (f - fStart)*4 + r;
4479       for (s = 0; s < size; ++s) {
4480         PetscInt r;
4481 
4482         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4483         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
4484         supportRef[4+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (support[s] - cStart)*6 + r;
4485       }
4486       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4487 #if 1
4488       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4489       for (p = 0; p < 4+size; ++p) {
4490         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);
4491       }
4492 #endif
4493     }
4494     /* Cell vertices have 6 supports */
4495     for (c = cStart; c < cEnd; ++c) {
4496       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
4497       PetscInt       supportNew[6];
4498 
4499       for (r = 0; r < 6; ++r) {
4500         supportNew[r] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
4501       }
4502       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4503     }
4504     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4505     break;
4506   case REFINER_HYBRID_HEX_3D:
4507     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
4508     /*
4509      Bottom (viewed from top)    Top
4510      1---------2---------2       7---------2---------6
4511      |         |         |       |         |         |
4512      |    B    2    C    |       |    H    2    G    |
4513      |         |         |       |         |         |
4514      3----3----0----1----1       3----3----0----1----1
4515      |         |         |       |         |         |
4516      |    A    0    D    |       |    E    0    F    |
4517      |         |         |       |         |         |
4518      0---------0---------3       4---------0---------5
4519      */
4520     /* Interior cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
4521     for (c = cStart; c < cMax; ++c) {
4522       const PetscInt  newp = (c - cStart)*8;
4523       const PetscInt *cone, *ornt;
4524       PetscInt        coneNew[6], orntNew[6];
4525 
4526       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4527       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4528       /* A hex */
4529       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
4530       orntNew[0] = ornt[0];
4531       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
4532       orntNew[1] = 0;
4533       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
4534       orntNew[2] = ornt[2];
4535       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
4536       orntNew[3] = 0;
4537       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
4538       orntNew[4] = 0;
4539       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
4540       orntNew[5] = ornt[5];
4541       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4542       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4543 #if 1
4544       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);
4545       for (p = 0; p < 6; ++p) {
4546         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);
4547       }
4548 #endif
4549       /* B hex */
4550       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
4551       orntNew[0] = ornt[0];
4552       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
4553       orntNew[1] = 0;
4554       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
4555       orntNew[2] = -1;
4556       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
4557       orntNew[3] = ornt[3];
4558       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
4559       orntNew[4] = 0;
4560       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
4561       orntNew[5] = ornt[5];
4562       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4563       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4564 #if 1
4565       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);
4566       for (p = 0; p < 6; ++p) {
4567         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);
4568       }
4569 #endif
4570       /* C hex */
4571       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
4572       orntNew[0] = ornt[0];
4573       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
4574       orntNew[1] = 0;
4575       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
4576       orntNew[2] = -1;
4577       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
4578       orntNew[3] = ornt[3];
4579       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
4580       orntNew[4] = ornt[4];
4581       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
4582       orntNew[5] = -4;
4583       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4584       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4585 #if 1
4586       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);
4587       for (p = 0; p < 6; ++p) {
4588         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);
4589       }
4590 #endif
4591       /* D hex */
4592       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
4593       orntNew[0] = ornt[0];
4594       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
4595       orntNew[1] = 0;
4596       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
4597       orntNew[2] = ornt[2];
4598       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
4599       orntNew[3] = 0;
4600       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
4601       orntNew[4] = ornt[4];
4602       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
4603       orntNew[5] = -4;
4604       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4605       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4606 #if 1
4607       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);
4608       for (p = 0; p < 6; ++p) {
4609         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);
4610       }
4611 #endif
4612       /* E hex */
4613       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
4614       orntNew[0] = -4;
4615       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
4616       orntNew[1] = ornt[1];
4617       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
4618       orntNew[2] = ornt[2];
4619       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
4620       orntNew[3] = 0;
4621       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
4622       orntNew[4] = -1;
4623       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
4624       orntNew[5] = ornt[5];
4625       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
4626       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
4627 #if 1
4628       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);
4629       for (p = 0; p < 6; ++p) {
4630         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);
4631       }
4632 #endif
4633       /* F hex */
4634       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
4635       orntNew[0] = -4;
4636       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
4637       orntNew[1] = ornt[1];
4638       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
4639       orntNew[2] = ornt[2];
4640       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4641       orntNew[3] = -1;
4642       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
4643       orntNew[4] = ornt[4];
4644       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
4645       orntNew[5] = 1;
4646       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
4647       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
4648 #if 1
4649       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);
4650       for (p = 0; p < 6; ++p) {
4651         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);
4652       }
4653 #endif
4654       /* G hex */
4655       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
4656       orntNew[0] = -4;
4657       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
4658       orntNew[1] = ornt[1];
4659       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4660       orntNew[2] = 0;
4661       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
4662       orntNew[3] = ornt[3];
4663       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
4664       orntNew[4] = ornt[4];
4665       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
4666       orntNew[5] = -3;
4667       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
4668       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
4669 #if 1
4670       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);
4671       for (p = 0; p < 6; ++p) {
4672         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);
4673       }
4674 #endif
4675       /* H hex */
4676       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
4677       orntNew[0] = -4;
4678       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
4679       orntNew[1] = ornt[1];
4680       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
4681       orntNew[2] = -1;
4682       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
4683       orntNew[3] = ornt[3];
4684       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
4685       orntNew[4] = 3;
4686       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
4687       orntNew[5] = ornt[5];
4688       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
4689       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
4690 #if 1
4691       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);
4692       for (p = 0; p < 6; ++p) {
4693         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);
4694       }
4695 #endif
4696     }
4697     /* Hybrid cells have 6 faces: Front, Back, Sides */
4698     /*
4699      3---------2---------2
4700      |         |         |
4701      |    D    2    C    |
4702      |         |         |
4703      3----3----0----1----1
4704      |         |         |
4705      |    A    0    B    |
4706      |         |         |
4707      0---------0---------1
4708      */
4709     for (c = cMax; c < cEnd; ++c) {
4710       const PetscInt  newp = (cMax - cStart)*8 + (c - cMax)*4;
4711       const PetscInt *cone, *ornt, *fornt;
4712       PetscInt        coneNew[6], orntNew[6], o, of, i;
4713 
4714       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4715       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4716       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
4717       o = ornt[0] < 0 ? -1 : 1;
4718       for (r = 0; r < 4; ++r) {
4719         PetscInt subfA = GetQuadSubface_Static(ornt[0], r);
4720         PetscInt edgeA = GetQuadEdge_Static(ornt[0], r);
4721         PetscInt edgeB = GetQuadEdge_Static(ornt[0], (r+3)%4);
4722         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]);
4723         coneNew[0]         = fStartNew + (cone[0] - fStart)*4 + subfA;
4724         orntNew[0]         = ornt[0];
4725         coneNew[1]         = fStartNew + (cone[1] - fStart)*4 + subfA;
4726         orntNew[1]         = ornt[0];
4727         of = fornt[edgeA] < 0 ? -1 : 1;
4728         i  = GetQuadEdgeInverse_Static(ornt[0], r) + 2;
4729         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeA] - fMax)*2 + (o*of < 0 ? 1 : 0);
4730         orntNew[i] = ornt[edgeA];
4731         i  = GetQuadEdgeInverse_Static(ornt[0], (r+1)%4) + 2;
4732         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeA;
4733         orntNew[i] = 0;
4734         i  = GetQuadEdgeInverse_Static(ornt[0], (r+2)%4) + 2;
4735         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeB;
4736         orntNew[i] = -2;
4737         of = fornt[edgeB] < 0 ? -1 : 1;
4738         i  = GetQuadEdgeInverse_Static(ornt[0], (r+3)%4) + 2;
4739         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeB] - fMax)*2 + (o*of < 0 ? 0 : 1);
4740         orntNew[i] = ornt[edgeB];
4741         ierr       = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
4742         ierr       = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
4743 #if 1
4744         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);
4745         for (p = 0; p < 2; ++p) {
4746           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);
4747         }
4748         for (p = 2; p < 6; ++p) {
4749           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);
4750         }
4751 #endif
4752       }
4753     }
4754     /* Interior split faces have 4 edges and the same cells as the parent */
4755     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4756     ierr = PetscMalloc1(4 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
4757     for (f = fStart; f < fMax; ++f) {
4758       for (r = 0; r < 4; ++r) {
4759         /* TODO: This can come from GetFaces_Internal() */
4760         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};
4761         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
4762         const PetscInt *cone, *ornt, *support;
4763         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
4764 
4765         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4766         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4767         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
4768         orntNew[(r+3)%4] = ornt[(r+3)%4];
4769         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
4770         orntNew[(r+0)%4] = ornt[r];
4771         coneNew[(r+1)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
4772         orntNew[(r+1)%4] = 0;
4773         coneNew[(r+2)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + (r+3)%4;
4774         orntNew[(r+2)%4] = -2;
4775         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4776         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4777 #if 1
4778         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4779         for (p = 0; p < 4; ++p) {
4780           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);
4781         }
4782 #endif
4783         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4784         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4785         for (s = 0; s < supportSize; ++s) {
4786           PetscInt subf;
4787           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4788           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4789           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4790           for (c = 0; c < coneSize; ++c) {
4791             if (cone[c] == f) break;
4792           }
4793           subf = GetQuadSubfaceInverse_Static(ornt[c], r);
4794           if (support[s] < cMax) {
4795             supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+subf];
4796           } else {
4797             supportRef[s] = cStartNew + (cMax       - cStart)*8 + (support[s] - cMax)*4 + subf;
4798           }
4799         }
4800         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4801 #if 1
4802         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4803         for (p = 0; p < supportSize; ++p) {
4804           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);
4805         }
4806 #endif
4807       }
4808     }
4809     /* Interior cell faces have 4 edges and 2 cells */
4810     for (c = cStart; c < cMax; ++c) {
4811       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};
4812       const PetscInt *cone, *ornt;
4813       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
4814 
4815       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4816       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4817       /* A-D face */
4818       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 0;
4819       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
4820       orntNew[0] = 0;
4821       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4822       orntNew[1] = 0;
4823       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4824       orntNew[2] = -2;
4825       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
4826       orntNew[3] = -2;
4827       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4828       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4829 #if 1
4830       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4831       for (p = 0; p < 4; ++p) {
4832         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);
4833       }
4834 #endif
4835       /* C-D face */
4836       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 1;
4837       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
4838       orntNew[0] = 0;
4839       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4840       orntNew[1] = 0;
4841       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4842       orntNew[2] = -2;
4843       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
4844       orntNew[3] = -2;
4845       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4846       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4847 #if 1
4848       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4849       for (p = 0; p < 4; ++p) {
4850         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);
4851       }
4852 #endif
4853       /* B-C face */
4854       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 2;
4855       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
4856       orntNew[0] = -2;
4857       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
4858       orntNew[1] = 0;
4859       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4860       orntNew[2] = 0;
4861       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4862       orntNew[3] = -2;
4863       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4864       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4865 #if 1
4866       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4867       for (p = 0; p < 4; ++p) {
4868         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);
4869       }
4870 #endif
4871       /* A-B face */
4872       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 3;
4873       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
4874       orntNew[0] = -2;
4875       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
4876       orntNew[1] = 0;
4877       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4878       orntNew[2] = 0;
4879       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4880       orntNew[3] = -2;
4881       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4882       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4883 #if 1
4884       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4885       for (p = 0; p < 4; ++p) {
4886         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);
4887       }
4888 #endif
4889       /* E-F face */
4890       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 4;
4891       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4892       orntNew[0] = -2;
4893       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
4894       orntNew[1] = -2;
4895       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
4896       orntNew[2] = 0;
4897       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4898       orntNew[3] = 0;
4899       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4900       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4901 #if 1
4902       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4903       for (p = 0; p < 4; ++p) {
4904         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);
4905       }
4906 #endif
4907       /* F-G face */
4908       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 5;
4909       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4910       orntNew[0] = -2;
4911       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
4912       orntNew[1] = -2;
4913       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
4914       orntNew[2] = 0;
4915       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4916       orntNew[3] = 0;
4917       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4918       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4919 #if 1
4920       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4921       for (p = 0; p < 4; ++p) {
4922         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);
4923       }
4924 #endif
4925       /* G-H face */
4926       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 6;
4927       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
4928       orntNew[0] = -2;
4929       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
4930       orntNew[1] = 0;
4931       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4932       orntNew[2] = 0;
4933       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4934       orntNew[3] = -2;
4935       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4936       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4937 #if 1
4938       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4939       for (p = 0; p < 4; ++p) {
4940         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);
4941       }
4942 #endif
4943       /* E-H face */
4944       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 7;
4945       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4946       orntNew[0] = -2;
4947       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
4948       orntNew[1] = -2;
4949       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
4950       orntNew[2] = 0;
4951       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4952       orntNew[3] = 0;
4953       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4954       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4955 #if 1
4956       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4957       for (p = 0; p < 4; ++p) {
4958         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);
4959       }
4960 #endif
4961       /* A-E face */
4962       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 8;
4963       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
4964       orntNew[0] = 0;
4965       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4966       orntNew[1] = 0;
4967       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4968       orntNew[2] = -2;
4969       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
4970       orntNew[3] = -2;
4971       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4972       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4973 #if 1
4974       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4975       for (p = 0; p < 4; ++p) {
4976         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);
4977       }
4978 #endif
4979       /* D-F face */
4980       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 9;
4981       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
4982       orntNew[0] = -2;
4983       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
4984       orntNew[1] = 0;
4985       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4986       orntNew[2] = 0;
4987       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4988       orntNew[3] = -2;
4989       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4990       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4991 #if 1
4992       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4993       for (p = 0; p < 4; ++p) {
4994         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);
4995       }
4996 #endif
4997       /* C-G face */
4998       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 10;
4999       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
5000       orntNew[0] = -2;
5001       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
5002       orntNew[1] = -2;
5003       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
5004       orntNew[2] = 0;
5005       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
5006       orntNew[3] = 0;
5007       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5008       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5009 #if 1
5010       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5011       for (p = 0; p < 4; ++p) {
5012         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);
5013       }
5014 #endif
5015       /* B-H face */
5016       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 11;
5017       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
5018       orntNew[0] = 0;
5019       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
5020       orntNew[1] = -2;
5021       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
5022       orntNew[2] = -2;
5023       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
5024       orntNew[3] = 0;
5025       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5026       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5027 #if 1
5028       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5029       for (p = 0; p < 4; ++p) {
5030         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);
5031       }
5032 #endif
5033       for (r = 0; r < 12; ++r) {
5034         newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
5035         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
5036         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
5037         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5038 #if 1
5039         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5040         for (p = 0; p < 2; ++p) {
5041           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);
5042         }
5043 #endif
5044       }
5045     }
5046     /* Hybrid split faces have 4 edges and same cells */
5047     for (f = fMax; f < fEnd; ++f) {
5048       const PetscInt *cone, *ornt, *support;
5049       PetscInt        coneNew[4], orntNew[4];
5050       PetscInt        supportNew[2], size, s, c;
5051 
5052       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5053       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
5054       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5055       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5056       for (r = 0; r < 2; ++r) {
5057         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
5058 
5059         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
5060         orntNew[0]   = ornt[0];
5061         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
5062         orntNew[1]   = ornt[1];
5063         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (cone[2+r] - eMax);
5064         orntNew[2+r] = 0;
5065         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd      - eMax) + (f - fMax);
5066         orntNew[3-r] = 0;
5067         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5068         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5069 #if 1
5070         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
5071         for (p = 0; p < 2; ++p) {
5072           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);
5073         }
5074         for (p = 2; p < 4; ++p) {
5075           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);
5076         }
5077 #endif
5078         for (s = 0; s < size; ++s) {
5079           const PetscInt *coneCell, *orntCell, *fornt;
5080           PetscInt        o, of;
5081 
5082           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
5083           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
5084           o = orntCell[0] < 0 ? -1 : 1;
5085           for (c = 2; c < 6; ++c) if (coneCell[c] == f) break;
5086           if (c >= 6) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
5087           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
5088           of = fornt[c-2] < 0 ? -1 : 1;
5089           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetQuadEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%4;
5090         }
5091         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5092 #if 1
5093         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
5094         for (p = 0; p < size; ++p) {
5095           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);
5096         }
5097 #endif
5098       }
5099     }
5100     /* Hybrid cell faces have 4 edges and 2 cells */
5101     for (c = cMax; c < cEnd; ++c) {
5102       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4;
5103       const PetscInt *cone, *ornt;
5104       PetscInt        coneNew[4], orntNew[4];
5105       PetscInt        supportNew[2];
5106 
5107       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5108       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5109       for (r = 0; r < 4; ++r) {
5110 #if 0
5111         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], r);
5112         orntNew[0] = 0;
5113         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], r);
5114         orntNew[1] = 0;
5115         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+GetQuadEdge_Static(ornt[0], r)] - fMax);
5116         orntNew[2] = 0;
5117         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd                                   - fMax) + (c - cMax);
5118         orntNew[3] = 0;
5119 #else
5120         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + r;
5121         orntNew[0] = 0;
5122         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + r;
5123         orntNew[1] = 0;
5124         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+r] - fMax);
5125         orntNew[2] = 0;
5126         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd      - fMax) + (c - cMax);
5127         orntNew[3] = 0;
5128 #endif
5129         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
5130         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
5131 #if 1
5132         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);
5133         for (p = 0; p < 2; ++p) {
5134           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);
5135         }
5136         for (p = 2; p < 4; ++p) {
5137           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);
5138         }
5139 #endif
5140         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], r);
5141         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], (r+1)%4);
5142         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
5143 #if 1
5144         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);
5145         for (p = 0; p < 2; ++p) {
5146           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);
5147         }
5148 #endif
5149       }
5150     }
5151     /* Interior split edges have 2 vertices and the same faces as the parent */
5152     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5153     for (e = eStart; e < eMax; ++e) {
5154       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
5155 
5156       for (r = 0; r < 2; ++r) {
5157         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
5158         const PetscInt *cone, *ornt, *support;
5159         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5160 
5161         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
5162         coneNew[0]       = vStartNew + (cone[0] - vStart);
5163         coneNew[1]       = vStartNew + (cone[1] - vStart);
5164         coneNew[(r+1)%2] = newv;
5165         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5166 #if 1
5167         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5168         for (p = 0; p < 2; ++p) {
5169           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);
5170         }
5171 #endif
5172         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
5173         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5174         for (s = 0; s < supportSize; ++s) {
5175           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5176           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5177           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5178           for (c = 0; c < coneSize; ++c) {
5179             if (cone[c] == e) break;
5180           }
5181           if (support[s] < fMax) {
5182             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%4;
5183           } else {
5184             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
5185           }
5186         }
5187         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5188 #if 1
5189         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5190         for (p = 0; p < supportSize; ++p) {
5191           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);
5192         }
5193 #endif
5194       }
5195     }
5196     /* Interior face edges have 2 vertices and 2+cells faces */
5197     for (f = fStart; f < fMax; ++f) {
5198       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};
5199       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
5200       const PetscInt *cone, *coneCell, *orntCell, *support;
5201       PetscInt        coneNew[2], coneSize, c, supportSize, s;
5202 
5203       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5204       for (r = 0; r < 4; ++r) {
5205         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
5206 
5207         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
5208         coneNew[1] = newv;
5209         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5210 #if 1
5211         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5212         for (p = 0; p < 2; ++p) {
5213           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);
5214         }
5215 #endif
5216         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5217         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5218         supportRef[0] = fStartNew + (f - fStart)*4 + r;
5219         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
5220         for (s = 0; s < supportSize; ++s) {
5221           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5222           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
5223           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
5224           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
5225           if (support[s] < cMax) {
5226             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
5227           } else {
5228             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + r;
5229           }
5230         }
5231         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5232 #if 1
5233         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5234         for (p = 0; p < 2+supportSize; ++p) {
5235           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);
5236         }
5237 #endif
5238       }
5239     }
5240     /* Interior cell edges have 2 vertices and 4 faces */
5241     for (c = cStart; c < cMax; ++c) {
5242       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};
5243       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
5244       const PetscInt *cone;
5245       PetscInt        coneNew[2], supportNew[4];
5246 
5247       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5248       for (r = 0; r < 6; ++r) {
5249         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
5250 
5251         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
5252         coneNew[1] = newv;
5253         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5254 #if 1
5255         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5256         for (p = 0; p < 2; ++p) {
5257           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);
5258         }
5259 #endif
5260         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
5261         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5262 #if 1
5263         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5264         for (p = 0; p < 4; ++p) {
5265           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);
5266         }
5267 #endif
5268       }
5269     }
5270     /* Hybrid edges have two vertices and the same faces */
5271     for (e = eMax; e < eEnd; ++e) {
5272       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
5273       const PetscInt *cone, *support, *fcone;
5274       PetscInt        coneNew[2], size, fsize, s;
5275 
5276       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
5277       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
5278       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5279       coneNew[0] = vStartNew + (cone[0] - vStart);
5280       coneNew[1] = vStartNew + (cone[1] - vStart);
5281       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5282 #if 1
5283       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5284       for (p = 0; p < 2; ++p) {
5285         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);
5286       }
5287 #endif
5288       for (s = 0; s < size; ++s) {
5289         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
5290         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
5291         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
5292         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
5293         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + c-2;
5294       }
5295       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5296 #if 1
5297       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5298       for (p = 0; p < size; ++p) {
5299         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);
5300       }
5301 #endif
5302     }
5303     /* Hybrid face edges have 2 vertices and 2+cells faces */
5304     for (f = fMax; f < fEnd; ++f) {
5305       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
5306       const PetscInt *cone, *support, *ccone, *cornt;
5307       PetscInt        coneNew[2], size, csize, s;
5308 
5309       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5310       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5311       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5312       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
5313       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
5314       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5315 #if 1
5316       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5317       for (p = 0; p < 2; ++p) {
5318         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);
5319       }
5320 #endif
5321       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 0;
5322       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 1;
5323       for (s = 0; s < size; ++s) {
5324         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
5325         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
5326         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
5327         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
5328         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]);
5329         supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + c-2;
5330       }
5331       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5332 #if 1
5333       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5334       for (p = 0; p < 2+size; ++p) {
5335         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);
5336       }
5337 #endif
5338     }
5339     /* Hybrid cell edges have 2 vertices and 4 faces */
5340     for (c = cMax; c < cEnd; ++c) {
5341       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
5342       const PetscInt *cone, *support;
5343       PetscInt        coneNew[2], size;
5344 
5345       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5346       ierr = DMPlexGetSupportSize(dm, c, &size);CHKERRQ(ierr);
5347       ierr = DMPlexGetSupport(dm, c, &support);CHKERRQ(ierr);
5348       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
5349       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
5350       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5351 #if 1
5352       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5353       for (p = 0; p < 2; ++p) {
5354         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);
5355       }
5356 #endif
5357       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 0;
5358       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 1;
5359       supportRef[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 2;
5360       supportRef[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 3;
5361       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5362 #if 1
5363       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5364       for (p = 0; p < 4; ++p) {
5365         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);
5366       }
5367 #endif
5368     }
5369     /* Interior vertices have identical supports */
5370     for (v = vStart; v < vEnd; ++v) {
5371       const PetscInt  newp = vStartNew + (v - vStart);
5372       const PetscInt *support, *cone;
5373       PetscInt        size, s;
5374 
5375       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5376       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5377       for (s = 0; s < size; ++s) {
5378         PetscInt r = 0;
5379 
5380         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5381         if (cone[1] == v) r = 1;
5382         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
5383         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (support[s] - eMax);
5384       }
5385       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5386 #if 1
5387       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5388       for (p = 0; p < size; ++p) {
5389         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);
5390       }
5391 #endif
5392     }
5393     /* Interior edge vertices have 2 + faces supports */
5394     for (e = eStart; e < eMax; ++e) {
5395       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
5396       const PetscInt *cone, *support;
5397       PetscInt        size, s;
5398 
5399       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
5400       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5401       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
5402       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
5403       for (s = 0; s < size; ++s) {
5404         PetscInt r;
5405 
5406         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5407         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
5408         if (support[s] < fMax) {
5409           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*4 + r;
5410         } else {
5411           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (support[s] - fMax);
5412         }
5413       }
5414       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5415 #if 1
5416       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5417       for (p = 0; p < 2+size; ++p) {
5418         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);
5419       }
5420 #endif
5421     }
5422     /* Interior face vertices have 4 + cells supports */
5423     for (f = fStart; f < fMax; ++f) {
5424       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
5425       const PetscInt *cone, *support;
5426       PetscInt        size, s;
5427 
5428       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5429       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5430       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eMax - eStart)*2 +  (f - fStart)*4 + r;
5431       for (s = 0; s < size; ++s) {
5432         PetscInt r;
5433 
5434         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5435         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
5436         if (support[s] < cMax) {
5437           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (support[s] - cStart)*6 + r;
5438         } else {
5439           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax       - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (support[s] - cMax);
5440         }
5441       }
5442       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5443 #if 1
5444       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5445       for (p = 0; p < 4+size; ++p) {
5446         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);
5447       }
5448 #endif
5449     }
5450     /* Cell vertices have 6 supports */
5451     for (c = cStart; c < cMax; ++c) {
5452       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
5453       PetscInt       supportNew[6];
5454 
5455       for (r = 0; r < 6; ++r) {
5456         supportNew[r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
5457       }
5458       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5459     }
5460     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5461     break;
5462   default:
5463     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5464   }
5465   PetscFunctionReturn(0);
5466 }
5467 
5468 static PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5469 {
5470   PetscSection   coordSection, coordSectionNew;
5471   Vec            coordinates, coordinatesNew;
5472   PetscScalar   *coords, *coordsNew;
5473   const PetscInt numVertices = depthSize ? depthSize[0] : 0;
5474   PetscInt       dim, spaceDim, depth, bs, coordSizeNew, cStart, cEnd, cMax, c, vStart, vStartNew, vEnd, v, eStart, eEnd, eMax, e, fStart, fEnd, fMax, f;
5475   VecType        vtype;
5476   PetscErrorCode ierr;
5477 
5478   PetscFunctionBegin;
5479   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
5480   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5481   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5482   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5483   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5484   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5485   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, NULL);CHKERRQ(ierr);
5486   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);}
5487   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
5488   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5489   ierr = PetscSectionGetFieldComponents(coordSection, 0, &spaceDim);CHKERRQ(ierr);
5490   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
5491   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
5492   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, spaceDim);CHKERRQ(ierr);
5493   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+numVertices);CHKERRQ(ierr);
5494   if (cMax < 0) cMax = cEnd;
5495   if (fMax < 0) fMax = fEnd;
5496   if (eMax < 0) eMax = eEnd;
5497   /* All vertices have the spaceDim coordinates */
5498   for (v = vStartNew; v < vStartNew+numVertices; ++v) {
5499     ierr = PetscSectionSetDof(coordSectionNew, v, spaceDim);CHKERRQ(ierr);
5500     ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, spaceDim);CHKERRQ(ierr);
5501   }
5502   ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
5503   ierr = DMSetCoordinateSection(rdm, PETSC_DETERMINE, coordSectionNew);CHKERRQ(ierr);
5504   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5505   ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
5506   ierr = VecCreate(PETSC_COMM_SELF, &coordinatesNew);CHKERRQ(ierr);
5507   ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
5508   ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
5509   ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr);
5510   ierr = VecSetBlockSize(coordinatesNew, bs);CHKERRQ(ierr);
5511   ierr = VecGetType(coordinates, &vtype);CHKERRQ(ierr);
5512   ierr = VecSetType(coordinatesNew, vtype);CHKERRQ(ierr);
5513   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
5514   ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5515   switch (refiner) {
5516   case REFINER_NOOP: break;
5517   case REFINER_HEX_3D:
5518   case REFINER_HYBRID_HEX_3D:
5519     /* Face vertices have the average of corner coordinates */
5520     for (f = fStart; f < fMax; ++f) {
5521       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
5522       PetscInt      *cone = NULL;
5523       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
5524 
5525       ierr = DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5526       for (p = 0; p < closureSize*2; p += 2) {
5527         const PetscInt point = cone[p];
5528         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
5529       }
5530       for (v = 0; v < coneSize; ++v) {
5531         ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
5532       }
5533       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5534       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
5535       for (v = 0; v < coneSize; ++v) {ierr = DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);CHKERRQ(ierr);}
5536       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
5537       ierr = DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5538     }
5539   case REFINER_HEX_2D:
5540   case REFINER_HYBRID_HEX_2D:
5541   case REFINER_SIMPLEX_1D:
5542     /* Cell vertices have the average of corner coordinates */
5543     for (c = cStart; c < cMax; ++c) {
5544       const PetscInt newv = vStartNew + (vEnd - vStart) + (dim > 1 ? (eMax - eStart) : 0) + (c - cStart) + (dim > 2 ? (fMax - fStart) : 0);
5545       PetscInt      *cone = NULL;
5546       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
5547 
5548       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5549       for (p = 0; p < closureSize*2; p += 2) {
5550         const PetscInt point = cone[p];
5551         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
5552       }
5553       for (v = 0; v < coneSize; ++v) {
5554         ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
5555       }
5556       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5557       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
5558       for (v = 0; v < coneSize; ++v) {ierr = DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);CHKERRQ(ierr);}
5559       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
5560       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5561     }
5562   case REFINER_SIMPLEX_2D:
5563   case REFINER_HYBRID_SIMPLEX_2D:
5564   case REFINER_SIMPLEX_3D:
5565   case REFINER_HYBRID_SIMPLEX_3D:
5566     /* Edge vertices have the average of endpoint coordinates */
5567     for (e = eStart; e < eMax; ++e) {
5568       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
5569       const PetscInt *cone;
5570       PetscInt        coneSize, offA, offB, offnew, d;
5571 
5572       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
5573       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
5574       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
5575       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
5576       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
5577       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5578       ierr = DMLocalizeCoordinate_Internal(dm, spaceDim, &coords[offA], &coords[offB], &coordsNew[offnew]);CHKERRQ(ierr);
5579       for (d = 0; d < spaceDim; ++d) {
5580         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coordsNew[offnew+d]);
5581       }
5582     }
5583     /* Old vertices have the same coordinates */
5584     for (v = vStart; v < vEnd; ++v) {
5585       const PetscInt newv = vStartNew + (v - vStart);
5586       PetscInt       off, offnew, d;
5587 
5588       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5589       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5590       for (d = 0; d < spaceDim; ++d) {
5591         coordsNew[offnew+d] = coords[off+d];
5592       }
5593     }
5594     break;
5595   default:
5596     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5597   }
5598   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
5599   ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5600   ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
5601   ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
5602   ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
5603   if (dm->maxCell) {
5604     const PetscReal *maxCell, *L;
5605     const DMBoundaryType *bd;
5606     ierr = DMGetPeriodicity(dm,  &maxCell, &L, &bd);CHKERRQ(ierr);
5607     ierr = DMSetPeriodicity(rdm,  maxCell,  L,  bd);CHKERRQ(ierr);
5608   }
5609   PetscFunctionReturn(0);
5610 }
5611 
5612 /*@
5613   DMPlexCreateProcessSF - Create an SF which just has process connectivity
5614 
5615   Collective on DM
5616 
5617   Input Parameters:
5618 + dm      - The DM
5619 - sfPoint - The PetscSF which encodes point connectivity
5620 
5621   Output Parameters:
5622 + processRanks - A list of process neighbors, or NULL
5623 - sfProcess    - An SF encoding the process connectivity, or NULL
5624 
5625   Level: developer
5626 
5627 .seealso: PetscSFCreate(), DMPlexCreateTwoSidedProcessSF()
5628 @*/
5629 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
5630 {
5631   PetscInt           numRoots, numLeaves, l;
5632   const PetscInt    *localPoints;
5633   const PetscSFNode *remotePoints;
5634   PetscInt          *localPointsNew;
5635   PetscSFNode       *remotePointsNew;
5636   PetscInt          *ranks, *ranksNew;
5637   PetscMPIInt        numProcs;
5638   PetscErrorCode     ierr;
5639 
5640   PetscFunctionBegin;
5641   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5642   PetscValidHeaderSpecific(sfPoint, PETSCSF_CLASSID, 2);
5643   if (processRanks) {PetscValidPointer(processRanks, 3);}
5644   if (sfProcess)    {PetscValidPointer(sfProcess, 4);}
5645   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) dm), &numProcs);CHKERRQ(ierr);
5646   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5647   ierr = PetscMalloc1(numLeaves, &ranks);CHKERRQ(ierr);
5648   for (l = 0; l < numLeaves; ++l) {
5649     ranks[l] = remotePoints[l].rank;
5650   }
5651   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
5652   ierr = PetscMalloc1(numLeaves, &ranksNew);CHKERRQ(ierr);
5653   ierr = PetscMalloc1(numLeaves, &localPointsNew);CHKERRQ(ierr);
5654   ierr = PetscMalloc1(numLeaves, &remotePointsNew);CHKERRQ(ierr);
5655   for (l = 0; l < numLeaves; ++l) {
5656     ranksNew[l]              = ranks[l];
5657     localPointsNew[l]        = l;
5658     remotePointsNew[l].index = 0;
5659     remotePointsNew[l].rank  = ranksNew[l];
5660   }
5661   ierr = PetscFree(ranks);CHKERRQ(ierr);
5662   if (processRanks) {ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);}
5663   else              {ierr = PetscFree(ranksNew);CHKERRQ(ierr);}
5664   if (sfProcess) {
5665     ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
5666     ierr = PetscObjectSetName((PetscObject) *sfProcess, "Process SF");CHKERRQ(ierr);
5667     ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
5668     ierr = PetscSFSetGraph(*sfProcess, numProcs, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
5669   }
5670   PetscFunctionReturn(0);
5671 }
5672 
5673 static PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5674 {
5675   PetscSF            sf, sfNew, sfProcess;
5676   IS                 processRanks;
5677   MPI_Datatype       depthType;
5678   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
5679   const PetscInt    *localPoints, *neighbors;
5680   const PetscSFNode *remotePoints;
5681   PetscInt          *localPointsNew;
5682   PetscSFNode       *remotePointsNew;
5683   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
5684   PetscInt           ldepth, depth, numNeighbors, pStartNew, pEndNew, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r, n;
5685   PetscInt           cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
5686   PetscErrorCode     ierr;
5687 
5688   PetscFunctionBegin;
5689   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
5690   ierr = DMPlexGetDepth(dm, &ldepth);CHKERRQ(ierr);
5691   ierr = MPIU_Allreduce(&ldepth, &depth, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
5692   if ((ldepth >= 0) && (depth != ldepth)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent Plex depth %d != %d", ldepth, depth);
5693   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5694   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5695   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5696   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5697   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5698   cMax = cMax < 0 ? cEnd : cMax;
5699   fMax = fMax < 0 ? fEnd : fMax;
5700   eMax = eMax < 0 ? eEnd : eMax;
5701   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
5702   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
5703   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
5704   /* Calculate size of new SF */
5705   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5706   if (numRoots < 0) PetscFunctionReturn(0);
5707   for (l = 0; l < numLeaves; ++l) {
5708     const PetscInt p = localPoints[l];
5709 
5710     switch (refiner) {
5711     case REFINER_SIMPLEX_1D:
5712       if ((p >= vStart) && (p < vEnd)) {
5713         /* Interior vertices stay the same */
5714         ++numLeavesNew;
5715       } else if ((p >= cStart && p < cMax)) {
5716         /* Interior cells add new cells and interior vertices */
5717         numLeavesNew += 2 + 1;
5718       }
5719       break;
5720     case REFINER_SIMPLEX_2D:
5721     case REFINER_HYBRID_SIMPLEX_2D:
5722       if ((p >= vStart) && (p < vEnd)) {
5723         /* Interior vertices stay the same */
5724         ++numLeavesNew;
5725       } else if ((p >= fStart) && (p < fMax)) {
5726         /* Interior faces add new faces and vertex */
5727         numLeavesNew += 2 + 1;
5728       } else if ((p >= fMax) && (p < fEnd)) {
5729         /* Hybrid faces stay the same */
5730         ++numLeavesNew;
5731       } else if ((p >= cStart) && (p < cMax)) {
5732         /* Interior cells add new cells and interior faces */
5733         numLeavesNew += 4 + 3;
5734       } else if ((p >= cMax) && (p < cEnd)) {
5735         /* Hybrid cells add new cells and hybrid face */
5736         numLeavesNew += 2 + 1;
5737       }
5738       break;
5739     case REFINER_HEX_2D:
5740     case REFINER_HYBRID_HEX_2D:
5741       if ((p >= vStart) && (p < vEnd)) {
5742         /* Interior vertices stay the same */
5743         ++numLeavesNew;
5744       } else if ((p >= fStart) && (p < fMax)) {
5745         /* Interior faces add new faces and vertex */
5746         numLeavesNew += 2 + 1;
5747       } else if ((p >= fMax) && (p < fEnd)) {
5748         /* Hybrid faces stay the same */
5749         ++numLeavesNew;
5750       } else if ((p >= cStart) && (p < cMax)) {
5751         /* Interior cells add new cells, interior faces, and vertex */
5752         numLeavesNew += 4 + 4 + 1;
5753       } else if ((p >= cMax) && (p < cEnd)) {
5754         /* Hybrid cells add new cells and hybrid face */
5755         numLeavesNew += 2 + 1;
5756       }
5757       break;
5758     case REFINER_SIMPLEX_3D:
5759     case REFINER_HYBRID_SIMPLEX_3D:
5760       if ((p >= vStart) && (p < vEnd)) {
5761         /* Interior vertices stay the same */
5762         ++numLeavesNew;
5763       } else if ((p >= eStart) && (p < eMax)) {
5764         /* Interior edges add new edges and vertex */
5765         numLeavesNew += 2 + 1;
5766       } else if ((p >= eMax) && (p < eEnd)) {
5767         /* Hybrid edges stay the same */
5768         ++numLeavesNew;
5769       } else if ((p >= fStart) && (p < fMax)) {
5770         /* Interior faces add new faces and edges */
5771         numLeavesNew += 4 + 3;
5772       } else if ((p >= fMax) && (p < fEnd)) {
5773         /* Hybrid faces add new faces and edges */
5774         numLeavesNew += 2 + 1;
5775       } else if ((p >= cStart) && (p < cMax)) {
5776         /* Interior cells add new cells, faces, and edges */
5777         numLeavesNew += 8 + 8 + 1;
5778       } else if ((p >= cMax) && (p < cEnd)) {
5779         /* Hybrid cells add new cells and faces */
5780         numLeavesNew += 4 + 3;
5781       }
5782       break;
5783     case REFINER_HEX_3D:
5784     case REFINER_HYBRID_HEX_3D:
5785       if ((p >= vStart) && (p < vEnd)) {
5786         /* Old vertices stay the same */
5787         ++numLeavesNew;
5788       } else if ((p >= eStart) && (p < eMax)) {
5789         /* Interior edges add new edges, and vertex */
5790         numLeavesNew += 2 + 1;
5791       } else if ((p >= eMax) && (p < eEnd)) {
5792         /* Hybrid edges stay the same */
5793         ++numLeavesNew;
5794       } else if ((p >= fStart) && (p < fMax)) {
5795         /* Interior faces add new faces, edges, and vertex */
5796         numLeavesNew += 4 + 4 + 1;
5797       } else if ((p >= fMax) && (p < fEnd)) {
5798         /* Hybrid faces add new faces and edges */
5799         numLeavesNew += 2 + 1;
5800       } else if ((p >= cStart) && (p < cMax)) {
5801         /* Interior cells add new cells, faces, edges, and vertex */
5802         numLeavesNew += 8 + 12 + 6 + 1;
5803       } else if ((p >= cStart) && (p < cEnd)) {
5804         /* Hybrid cells add new cells, faces, and edges */
5805         numLeavesNew += 4 + 4 + 1;
5806       }
5807       break;
5808     default:
5809       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5810     }
5811   }
5812   /* Communicate depthSizes for each remote rank */
5813   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
5814   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
5815   ierr = PetscMalloc5((depth+1)*numNeighbors,&rdepthSize,numNeighbors,&rvStartNew,numNeighbors,&reStartNew,numNeighbors,&rfStartNew,numNeighbors,&rcStartNew);CHKERRQ(ierr);
5816   ierr = PetscMalloc7(depth+1,&depthSizeOld,(depth+1)*numNeighbors,&rdepthSizeOld,(depth+1)*numNeighbors,&rdepthMaxOld,numNeighbors,&rvStart,numNeighbors,&reStart,numNeighbors,&rfStart,numNeighbors,&rcStart);CHKERRQ(ierr);
5817   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
5818   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
5819   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5820   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5821   for (n = 0; n < numNeighbors; ++n) {
5822     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
5823   }
5824   depthSizeOld[depth]   = cMax;
5825   depthSizeOld[0]       = vMax;
5826   depthSizeOld[depth-1] = fMax;
5827   depthSizeOld[1]       = eMax;
5828 
5829   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5830   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5831 
5832   depthSizeOld[depth]   = cEnd - cStart;
5833   depthSizeOld[0]       = vEnd - vStart;
5834   depthSizeOld[depth-1] = fEnd - fStart;
5835   depthSizeOld[1]       = eEnd - eStart;
5836 
5837   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5838   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5839   for (n = 0; n < numNeighbors; ++n) {
5840     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
5841     rdepthMaxOld[n*(depth+1)+depth]   = rdepthMaxOld[n*(depth+1)+depth]   < 0 ? rdepthSizeOld[n*(depth+1)+depth]  +rcStart[n]: rdepthMaxOld[n*(depth+1)+depth];
5842     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];
5843     rdepthMaxOld[n*(depth+1)+1]       = rdepthMaxOld[n*(depth+1)+1]       < 0 ? rdepthSizeOld[n*(depth+1)+1]      +reStart[n]: rdepthMaxOld[n*(depth+1)+1];
5844   }
5845   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
5846   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
5847   /* Calculate new point SF */
5848   ierr = PetscMalloc1(numLeavesNew, &localPointsNew);CHKERRQ(ierr);
5849   ierr = PetscMalloc1(numLeavesNew, &remotePointsNew);CHKERRQ(ierr);
5850   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
5851   for (l = 0, m = 0; l < numLeaves; ++l) {
5852     PetscInt    p     = localPoints[l];
5853     PetscInt    rp    = remotePoints[l].index, n;
5854     PetscMPIInt rrank = remotePoints[l].rank;
5855 
5856     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
5857     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
5858     switch (refiner) {
5859     case REFINER_SIMPLEX_1D:
5860       if ((p >= vStart) && (p < vEnd)) {
5861         /* Old vertices stay the same */
5862         localPointsNew[m]        = vStartNew     + (p  - vStart);
5863         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5864         remotePointsNew[m].rank  = rrank;
5865         ++m;
5866       } else if ((p >= cStart) && (p < cMax)) {
5867         /* Old interior cells add new cells and vertex */
5868         for (r = 0; r < 2; ++r, ++m) {
5869           localPointsNew[m]        = cStartNew     + (p  - cStart)*2     + r;
5870           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*2 + r;
5871           remotePointsNew[m].rank  = rrank;
5872         }
5873         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - cStart);
5874         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rcStart[n]);
5875         remotePointsNew[m].rank  = rrank;
5876         ++m;
5877       }
5878       break;
5879     case REFINER_SIMPLEX_2D:
5880     case REFINER_HYBRID_SIMPLEX_2D:
5881       if ((p >= vStart) && (p < vEnd)) {
5882         /* Old vertices stay the same */
5883         localPointsNew[m]        = vStartNew     + (p  - vStart);
5884         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5885         remotePointsNew[m].rank  = rrank;
5886         ++m;
5887       } else if ((p >= fStart) && (p < fMax)) {
5888         /* Old interior faces add new faces and vertex */
5889         for (r = 0; r < 2; ++r, ++m) {
5890           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5891           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5892           remotePointsNew[m].rank  = rrank;
5893         }
5894         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5895         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5896         remotePointsNew[m].rank  = rrank;
5897         ++m;
5898       } else if ((p >= fMax) && (p < fEnd)) {
5899         /* Old hybrid faces stay the same */
5900         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
5901         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
5902         remotePointsNew[m].rank  = rrank;
5903         ++m;
5904       } else if ((p >= cStart) && (p < cMax)) {
5905         /* Old interior cells add new cells and interior faces */
5906         for (r = 0; r < 4; ++r, ++m) {
5907           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5908           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5909           remotePointsNew[m].rank  = rrank;
5910         }
5911         for (r = 0; r < 3; ++r, ++m) {
5912           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
5913           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
5914           remotePointsNew[m].rank  = rrank;
5915         }
5916       } else if ((p >= cMax) && (p < cEnd)) {
5917         /* Old hybrid cells add new cells and hybrid face */
5918         for (r = 0; r < 2; ++r, ++m) {
5919           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5920           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5921           remotePointsNew[m].rank  = rrank;
5922         }
5923         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
5924         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]);
5925         remotePointsNew[m].rank  = rrank;
5926         ++m;
5927       }
5928       break;
5929     case REFINER_HEX_2D:
5930     case REFINER_HYBRID_HEX_2D:
5931       if ((p >= vStart) && (p < vEnd)) {
5932         /* Old vertices stay the same */
5933         localPointsNew[m]        = vStartNew     + (p  - vStart);
5934         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5935         remotePointsNew[m].rank  = rrank;
5936         ++m;
5937       } else if ((p >= fStart) && (p < fMax)) {
5938         /* Old interior faces add new faces and vertex */
5939         for (r = 0; r < 2; ++r, ++m) {
5940           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5941           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5942           remotePointsNew[m].rank  = rrank;
5943         }
5944         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5945         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5946         remotePointsNew[m].rank  = rrank;
5947         ++m;
5948       } else if ((p >= fMax) && (p < fEnd)) {
5949         /* Old hybrid faces stay the same */
5950         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
5951         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
5952         remotePointsNew[m].rank  = rrank;
5953         ++m;
5954       } else if ((p >= cStart) && (p < cMax)) {
5955         /* Old interior cells add new cells, interior faces, and vertex */
5956         for (r = 0; r < 4; ++r, ++m) {
5957           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5958           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5959           remotePointsNew[m].rank  = rrank;
5960         }
5961         for (r = 0; r < 4; ++r, ++m) {
5962           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*4     + r;
5963           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*4 + r;
5964           remotePointsNew[m].rank  = rrank;
5965         }
5966         localPointsNew[m]        = vStartNew     + (vEnd - vStart)               + (fMax                              - fStart)     + (p  - cStart);
5967         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0]  + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]);
5968         remotePointsNew[m].rank  = rrank;
5969         ++m;
5970       } else if ((p >= cStart) && (p < cMax)) {
5971         /* Old hybrid cells add new cells and hybrid face */
5972         for (r = 0; r < 2; ++r, ++m) {
5973           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5974           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5975           remotePointsNew[m].rank  = rrank;
5976         }
5977         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*4     + (p  - cMax);
5978         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]);
5979         remotePointsNew[m].rank  = rrank;
5980         ++m;
5981       }
5982       break;
5983     case REFINER_SIMPLEX_3D:
5984     case REFINER_HYBRID_SIMPLEX_3D:
5985       if ((p >= vStart) && (p < vEnd)) {
5986         /* Interior vertices stay the same */
5987         localPointsNew[m]        = vStartNew     + (p  - vStart);
5988         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5989         remotePointsNew[m].rank  = rrank;
5990         ++m;
5991       } else if ((p >= eStart) && (p < eMax)) {
5992         /* Interior edges add new edges and vertex */
5993         for (r = 0; r < 2; ++r, ++m) {
5994           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
5995           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
5996           remotePointsNew[m].rank  = rrank;
5997         }
5998         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
5999         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
6000         remotePointsNew[m].rank  = rrank;
6001         ++m;
6002       } else if ((p >= eMax) && (p < eEnd)) {
6003         /* Hybrid edges stay the same */
6004         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - eMax);
6005         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]);
6006         remotePointsNew[m].rank  = rrank;
6007         ++m;
6008       } else if ((p >= fStart) && (p < fMax)) {
6009         /* Interior faces add new faces and edges */
6010         for (r = 0; r < 4; ++r, ++m) {
6011           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
6012           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
6013           remotePointsNew[m].rank  = rrank;
6014         }
6015         for (r = 0; r < 3; ++r, ++m) {
6016           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*3     + r;
6017           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
6018           remotePointsNew[m].rank  = rrank;
6019         }
6020       } else if ((p >= fMax) && (p < fEnd)) {
6021         /* Hybrid faces add new faces and edges */
6022         for (r = 0; r < 2; ++r, ++m) {
6023           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fMax)*2                              + r;
6024           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;
6025           remotePointsNew[m].rank  = rrank;
6026         }
6027         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (eEnd                                    - eMax)                        + (p  - fMax);
6028         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]);
6029         remotePointsNew[m].rank  = rrank;
6030         ++m;
6031       } else if ((p >= cStart) && (p < cMax)) {
6032         /* Interior cells add new cells, faces, and edges */
6033         for (r = 0; r < 8; ++r, ++m) {
6034           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
6035           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
6036           remotePointsNew[m].rank  = rrank;
6037         }
6038         for (r = 0; r < 8; ++r, ++m) {
6039           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*8     + r;
6040           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*8 + r;
6041           remotePointsNew[m].rank  = rrank;
6042         }
6043         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (p  - cStart)*1     + 0;
6044         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;
6045         remotePointsNew[m].rank  = rrank;
6046         ++m;
6047       } else if ((p >= cMax) && (p < cEnd)) {
6048         /* Hybrid cells add new cells and faces */
6049         for (r = 0; r < 4; ++r, ++m) {
6050           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
6051           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
6052           remotePointsNew[m].rank  = rrank;
6053         }
6054         for (r = 0; r < 3; ++r, ++m) {
6055           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*2                              + (p  - cMax)*3                            + r;
6056           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;
6057           remotePointsNew[m].rank  = rrank;
6058         }
6059       }
6060       break;
6061     case REFINER_HEX_3D:
6062     case REFINER_HYBRID_HEX_3D:
6063       if ((p >= vStart) && (p < vEnd)) {
6064         /* Interior vertices stay the same */
6065         localPointsNew[m]        = vStartNew     + (p  - vStart);
6066         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6067         remotePointsNew[m].rank  = rrank;
6068         ++m;
6069       } else if ((p >= eStart) && (p < eMax)) {
6070         /* Interior edges add new edges and vertex */
6071         for (r = 0; r < 2; ++r, ++m) {
6072           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
6073           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
6074           remotePointsNew[m].rank  = rrank;
6075         }
6076         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
6077         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
6078         remotePointsNew[m].rank  = rrank;
6079         ++m;
6080       } else if ((p >= eMax) && (p < eEnd)) {
6081         /* Hybrid edges stay the same */
6082         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (p  - eMax);
6083         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]);
6084         remotePointsNew[m].rank  = rrank;
6085         ++m;
6086       } else if ((p >= fStart) && (p < fMax)) {
6087         /* Interior faces add new faces, edges, and vertex */
6088         for (r = 0; r < 4; ++r, ++m) {
6089           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
6090           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
6091           remotePointsNew[m].rank  = rrank;
6092         }
6093         for (r = 0; r < 4; ++r, ++m) {
6094           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*4     + r;
6095           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*4 + r;
6096           remotePointsNew[m].rank  = rrank;
6097         }
6098         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax                        - eStart)     + (p  - fStart);
6099         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
6100         remotePointsNew[m].rank  = rrank;
6101         ++m;
6102       } else if ((p >= fMax) && (p < fEnd)) {
6103         /* Hybrid faces add new faces and edges */
6104         for (r = 0; r < 2; ++r, ++m) {
6105           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (p  - fMax)*2                              + r;
6106           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;
6107           remotePointsNew[m].rank  = rrank;
6108         }
6109         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (p  - fMax);
6110         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]);
6111         remotePointsNew[m].rank  = rrank;
6112         ++m;
6113       } else if ((p >= cStart) && (p < cMax)) {
6114         /* Interior cells add new cells, faces, edges, and vertex */
6115         for (r = 0; r < 8; ++r, ++m) {
6116           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
6117           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
6118           remotePointsNew[m].rank  = rrank;
6119         }
6120         for (r = 0; r < 12; ++r, ++m) {
6121           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*12     + r;
6122           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*12 + r;
6123           remotePointsNew[m].rank  = rrank;
6124         }
6125         for (r = 0; r < 6; ++r, ++m) {
6126           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (p  - cStart)*6     + r;
6127           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;
6128           remotePointsNew[m].rank  = rrank;
6129         }
6130         for (r = 0; r < 1; ++r, ++m) {
6131           localPointsNew[m]        = vStartNew     + (eMax                        - eStart)     + (fMax                              - fStart)     + (p  - cStart)     + r;
6132           remotePointsNew[m].index = rvStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]) + r;
6133           remotePointsNew[m].rank  = rrank;
6134         }
6135       } else if ((p >= cMax) && (p < cEnd)) {
6136         /* Hybrid cells add new cells, faces, and edges */
6137         for (r = 0; r < 4; ++r, ++m) {
6138           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
6139           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
6140           remotePointsNew[m].rank  = rrank;
6141         }
6142         for (r = 0; r < 4; ++r, ++m) {
6143           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (fEnd                                          - fMax)*2                              + (p  - cMax)*4                            + r;
6144           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;
6145           remotePointsNew[m].rank  = rrank;
6146         }
6147         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (fEnd                                          - fMax)                              + (p  - cMax);
6148         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]);
6149         remotePointsNew[m].rank  = rrank;
6150         ++m;
6151       }
6152       break;
6153     default:
6154       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6155     }
6156   }
6157   if (m != numLeavesNew) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of leaf point %d should be %d", m, numLeavesNew);
6158   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
6159   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
6160   {
6161     PetscSFNode *rp, *rtmp;
6162     PetscInt    *lp, *idx, *ltmp, i;
6163 
6164     /* SF needs sorted leaves to correct calculate Gather */
6165     ierr = PetscMalloc1(numLeavesNew,&idx);CHKERRQ(ierr);
6166     ierr = PetscMalloc1(numLeavesNew, &lp);CHKERRQ(ierr);
6167     ierr = PetscMalloc1(numLeavesNew, &rp);CHKERRQ(ierr);
6168     for (i = 0; i < numLeavesNew; ++i) {
6169       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);
6170       idx[i] = i;
6171     }
6172     ierr = PetscSortIntWithPermutation(numLeavesNew, localPointsNew, idx);CHKERRQ(ierr);
6173     for (i = 0; i < numLeavesNew; ++i) {
6174       lp[i] = localPointsNew[idx[i]];
6175       rp[i] = remotePointsNew[idx[i]];
6176     }
6177     ltmp            = localPointsNew;
6178     localPointsNew  = lp;
6179     rtmp            = remotePointsNew;
6180     remotePointsNew = rp;
6181     ierr = PetscFree(idx);CHKERRQ(ierr);
6182     ierr = PetscFree(ltmp);CHKERRQ(ierr);
6183     ierr = PetscFree(rtmp);CHKERRQ(ierr);
6184   }
6185   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6186   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
6187   ierr = PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
6188   PetscFunctionReturn(0);
6189 }
6190 
6191 static PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6192 {
6193   PetscInt       numLabels, l;
6194   PetscInt       depth, newp, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r;
6195   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
6196   PetscErrorCode ierr;
6197 
6198   PetscFunctionBegin;
6199   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6200   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6201   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6202   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6203   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6204   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
6205   ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
6206   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6207   switch (refiner) {
6208   case REFINER_NOOP:
6209   case REFINER_SIMPLEX_1D:
6210   case REFINER_SIMPLEX_2D:
6211   case REFINER_HEX_2D:
6212   case REFINER_SIMPLEX_3D:
6213   case REFINER_HEX_3D:
6214     break;
6215   case REFINER_HYBRID_SIMPLEX_3D:
6216   case REFINER_HYBRID_HEX_3D:
6217     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
6218   case REFINER_HYBRID_SIMPLEX_2D:
6219   case REFINER_HYBRID_HEX_2D:
6220     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6221     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6222     break;
6223   default:
6224     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6225   }
6226   for (l = 0; l < numLabels; ++l) {
6227     DMLabel         label, labelNew;
6228     const char     *lname;
6229     PetscBool       isDepth;
6230     IS              valueIS;
6231     const PetscInt *values;
6232     PetscInt        defVal;
6233     PetscInt        numValues, val;
6234 
6235     ierr = DMGetLabelName(dm, l, &lname);CHKERRQ(ierr);
6236     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
6237     if (isDepth) continue;
6238     ierr = DMCreateLabel(rdm, lname);CHKERRQ(ierr);
6239     ierr = DMGetLabel(dm, lname, &label);CHKERRQ(ierr);
6240     ierr = DMGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
6241     ierr = DMLabelGetDefaultValue(label,&defVal);CHKERRQ(ierr);
6242     ierr = DMLabelSetDefaultValue(labelNew,defVal);CHKERRQ(ierr);
6243     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
6244     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
6245     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
6246     for (val = 0; val < numValues; ++val) {
6247       IS              pointIS;
6248       const PetscInt *points;
6249       PetscInt        numPoints, n;
6250 
6251       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
6252       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
6253       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
6254       /* Ensure refined label is created with same number of strata as
6255        * original (even if no entries here). */
6256       ierr = DMLabelAddStratum(labelNew, values[val]);CHKERRQ(ierr);
6257       for (n = 0; n < numPoints; ++n) {
6258         const PetscInt p = points[n];
6259         switch (refiner) {
6260         case REFINER_SIMPLEX_1D:
6261           if ((p >= vStart) && (p < vEnd)) {
6262             /* Old vertices stay the same */
6263             newp = vStartNew + (p - vStart);
6264             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6265           } else if ((p >= cStart) && (p < cEnd)) {
6266             /* Old cells add new cells and vertex */
6267             newp = vStartNew + (vEnd - vStart) + (p - cStart);
6268             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6269             for (r = 0; r < 2; ++r) {
6270               newp = cStartNew + (p - cStart)*2 + r;
6271               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6272             }
6273           }
6274           break;
6275         case REFINER_SIMPLEX_2D:
6276           if ((p >= vStart) && (p < vEnd)) {
6277             /* Old vertices stay the same */
6278             newp = vStartNew + (p - vStart);
6279             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6280           } else if ((p >= fStart) && (p < fEnd)) {
6281             /* Old faces add new faces and vertex */
6282             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6283             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6284             for (r = 0; r < 2; ++r) {
6285               newp = fStartNew + (p - fStart)*2 + r;
6286               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6287             }
6288           } else if ((p >= cStart) && (p < cEnd)) {
6289             /* Old cells add new cells and interior faces */
6290             for (r = 0; r < 4; ++r) {
6291               newp = cStartNew + (p - cStart)*4 + r;
6292               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6293             }
6294             for (r = 0; r < 3; ++r) {
6295               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6296               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6297             }
6298           }
6299           break;
6300         case REFINER_HEX_2D:
6301           if ((p >= vStart) && (p < vEnd)) {
6302             /* Old vertices stay the same */
6303             newp = vStartNew + (p - vStart);
6304             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6305           } else if ((p >= fStart) && (p < fEnd)) {
6306             /* Old faces add new faces and vertex */
6307             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6308             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6309             for (r = 0; r < 2; ++r) {
6310               newp = fStartNew + (p - fStart)*2 + r;
6311               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6312             }
6313           } else if ((p >= cStart) && (p < cEnd)) {
6314             /* Old cells add new cells and interior faces and vertex */
6315             for (r = 0; r < 4; ++r) {
6316               newp = cStartNew + (p - cStart)*4 + r;
6317               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6318             }
6319             for (r = 0; r < 4; ++r) {
6320               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
6321               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6322             }
6323             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
6324             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6325           }
6326           break;
6327         case REFINER_HYBRID_SIMPLEX_2D:
6328           if ((p >= vStart) && (p < vEnd)) {
6329             /* Old vertices stay the same */
6330             newp = vStartNew + (p - vStart);
6331             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6332           } else if ((p >= fStart) && (p < fMax)) {
6333             /* Old interior faces add new faces and vertex */
6334             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6335             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6336             for (r = 0; r < 2; ++r) {
6337               newp = fStartNew + (p - fStart)*2 + r;
6338               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6339             }
6340           } else if ((p >= fMax) && (p < fEnd)) {
6341             /* Old hybrid faces stay the same */
6342             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
6343             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6344           } else if ((p >= cStart) && (p < cMax)) {
6345             /* Old interior cells add new cells and interior faces */
6346             for (r = 0; r < 4; ++r) {
6347               newp = cStartNew + (p - cStart)*4 + r;
6348               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6349             }
6350             for (r = 0; r < 3; ++r) {
6351               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6352               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6353             }
6354           } else if ((p >= cMax) && (p < cEnd)) {
6355             /* Old hybrid cells add new cells and hybrid face */
6356             for (r = 0; r < 2; ++r) {
6357               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
6358               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6359             }
6360             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
6361             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6362           }
6363           break;
6364         case REFINER_HYBRID_HEX_2D:
6365           if ((p >= vStart) && (p < vEnd)) {
6366             /* Old vertices stay the same */
6367             newp = vStartNew + (p - vStart);
6368             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6369           } else if ((p >= fStart) && (p < fMax)) {
6370             /* Old interior faces add new faces and vertex */
6371             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6372             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6373             for (r = 0; r < 2; ++r) {
6374               newp = fStartNew + (p - fStart)*2 + r;
6375               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6376             }
6377           } else if ((p >= fMax) && (p < fEnd)) {
6378             /* Old hybrid faces stay the same */
6379             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
6380             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6381           } else if ((p >= cStart) && (p < cMax)) {
6382             /* Old interior cells add new cells, interior faces, and vertex */
6383             for (r = 0; r < 4; ++r) {
6384               newp = cStartNew + (p - cStart)*4 + r;
6385               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6386             }
6387             for (r = 0; r < 4; ++r) {
6388               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
6389               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6390             }
6391             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
6392             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6393           } else if ((p >= cMax) && (p < cEnd)) {
6394             /* Old hybrid cells add new cells and hybrid face */
6395             for (r = 0; r < 2; ++r) {
6396               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
6397               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6398             }
6399             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (p - cMax);
6400             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6401           }
6402           break;
6403         case REFINER_SIMPLEX_3D:
6404           if ((p >= vStart) && (p < vEnd)) {
6405             /* Old vertices stay the same */
6406             newp = vStartNew + (p - vStart);
6407             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6408           } else if ((p >= eStart) && (p < eEnd)) {
6409             /* Old edges add new edges and vertex */
6410             for (r = 0; r < 2; ++r) {
6411               newp = eStartNew + (p - eStart)*2 + r;
6412               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6413             }
6414             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6415             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6416           } else if ((p >= fStart) && (p < fEnd)) {
6417             /* Old faces add new faces and edges */
6418             for (r = 0; r < 4; ++r) {
6419               newp = fStartNew + (p - fStart)*4 + r;
6420               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6421             }
6422             for (r = 0; r < 3; ++r) {
6423               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
6424               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6425             }
6426           } else if ((p >= cStart) && (p < cEnd)) {
6427             /* Old cells add new cells and interior faces and edges */
6428             for (r = 0; r < 8; ++r) {
6429               newp = cStartNew + (p - cStart)*8 + r;
6430               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6431             }
6432             for (r = 0; r < 8; ++r) {
6433               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*8 + r;
6434               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6435             }
6436             for (r = 0; r < 1; ++r) {
6437               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*1 + r;
6438               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6439             }
6440           }
6441           break;
6442         case REFINER_HYBRID_SIMPLEX_3D:
6443           if ((p >= vStart) && (p < vEnd)) {
6444             /* Interior vertices stay the same */
6445             newp = vStartNew + (p - vStart);
6446             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6447           } else if ((p >= eStart) && (p < eMax)) {
6448             /* Interior edges add new edges and vertex */
6449             for (r = 0; r < 2; ++r) {
6450               newp = eStartNew + (p - eStart)*2 + r;
6451               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6452             }
6453             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6454             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6455           } else if ((p >= eMax) && (p < eEnd)) {
6456             /* Hybrid edges stay the same */
6457             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - eMax);
6458             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6459           } else if ((p >= fStart) && (p < fMax)) {
6460             /* Interior faces add new faces and edges */
6461             for (r = 0; r < 4; ++r) {
6462               newp = fStartNew + (p - fStart)*4 + r;
6463               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6464             }
6465             for (r = 0; r < 3; ++r) {
6466               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
6467               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6468             }
6469           } else if ((p >= fMax) && (p < fEnd)) {
6470             /* Hybrid faces add new faces and edges */
6471             for (r = 0; r < 2; ++r) {
6472               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (p - fMax)*2 + r;
6473               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6474             }
6475             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - fMax);
6476             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6477           } else if ((p >= cStart) && (p < cMax)) {
6478             /* Interior cells add new cells, faces, and edges */
6479             for (r = 0; r < 8; ++r) {
6480               newp = cStartNew + (p - cStart)*8 + r;
6481               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6482             }
6483             for (r = 0; r < 8; ++r) {
6484               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*8 + r;
6485               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6486             }
6487             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart);
6488             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6489           } else if ((p >= cMax) && (p < cEnd)) {
6490             /* Hybrid cells add new cells and faces */
6491             for (r = 0; r < 4; ++r) {
6492               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
6493               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6494             }
6495             for (r = 0; r < 3; ++r) {
6496               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
6497               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6498             }
6499           }
6500           break;
6501         case REFINER_HEX_3D:
6502           if ((p >= vStart) && (p < vEnd)) {
6503             /* Old vertices stay the same */
6504             newp = vStartNew + (p - vStart);
6505             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6506           } else if ((p >= eStart) && (p < eEnd)) {
6507             /* Old edges add new edges and vertex */
6508             for (r = 0; r < 2; ++r) {
6509               newp = eStartNew + (p - eStart)*2 + r;
6510               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6511             }
6512             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6513             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6514           } else if ((p >= fStart) && (p < fEnd)) {
6515             /* Old faces add new faces, edges, and vertex */
6516             for (r = 0; r < 4; ++r) {
6517               newp = fStartNew + (p - fStart)*4 + r;
6518               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6519             }
6520             for (r = 0; r < 4; ++r) {
6521               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*4 + r;
6522               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6523             }
6524             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (p - fStart);
6525             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6526           } else if ((p >= cStart) && (p < cEnd)) {
6527             /* Old cells add new cells, faces, edges, and vertex */
6528             for (r = 0; r < 8; ++r) {
6529               newp = cStartNew + (p - cStart)*8 + r;
6530               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6531             }
6532             for (r = 0; r < 12; ++r) {
6533               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*12 + r;
6534               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6535             }
6536             for (r = 0; r < 6; ++r) {
6537               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (p - cStart)*6 + r;
6538               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6539             }
6540             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (p - cStart);
6541             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6542           }
6543           break;
6544         case REFINER_HYBRID_HEX_3D:
6545           if ((p >= vStart) && (p < vEnd)) {
6546             /* Interior vertices stay the same */
6547             newp = vStartNew + (p - vStart);
6548             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6549           } else if ((p >= eStart) && (p < eMax)) {
6550             /* Interior edges add new edges and vertex */
6551             for (r = 0; r < 2; ++r) {
6552               newp = eStartNew + (p - eStart)*2 + r;
6553               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6554             }
6555             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6556             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6557           } else if ((p >= eMax) && (p < eEnd)) {
6558             /* Hybrid edges stay the same */
6559             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - eMax);
6560             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6561           } else if ((p >= fStart) && (p < fMax)) {
6562             /* Interior faces add new faces, edges, and vertex */
6563             for (r = 0; r < 4; ++r) {
6564               newp = fStartNew + (p - fStart)*4 + r;
6565               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6566             }
6567             for (r = 0; r < 4; ++r) {
6568               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*4 + r;
6569               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6570             }
6571             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (p - fStart);
6572             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6573           } else if ((p >= fMax) && (p < fEnd)) {
6574             /* Hybrid faces add new faces and edges */
6575             for (r = 0; r < 2; ++r) {
6576               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (p - fMax)*2 + r;
6577               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6578             }
6579             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - fMax);
6580             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6581           } else if ((p >= cStart) && (p < cMax)) {
6582             /* Interior cells add new cells, faces, edges, and vertex */
6583             for (r = 0; r < 8; ++r) {
6584               newp = cStartNew + (p - cStart)*8 + r;
6585               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6586             }
6587             for (r = 0; r < 12; ++r) {
6588               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*12 + r;
6589               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6590             }
6591             for (r = 0; r < 6; ++r) {
6592               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (p - cStart)*6 + r;
6593               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6594             }
6595             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (p - cStart);
6596             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6597           } else if ((p >= cMax) && (p < cEnd)) {
6598             /* Hybrid cells add new cells, faces, and edges */
6599             for (r = 0; r < 4; ++r) {
6600               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
6601               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6602             }
6603             for (r = 0; r < 4; ++r) {
6604               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (p - cMax)*4 + r;
6605               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6606             }
6607             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (fEnd - fMax) + (p - cMax);
6608             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6609           }
6610           break;
6611         default:
6612           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6613         }
6614       }
6615       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
6616       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
6617     }
6618     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
6619     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
6620     if (0) {
6621       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
6622     }
6623   }
6624   PetscFunctionReturn(0);
6625 }
6626 
6627 /* This will only work for interpolated meshes */
6628 PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
6629 {
6630   DM             rdm;
6631   PetscInt      *depthSize;
6632   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
6633   PetscErrorCode ierr;
6634 
6635   PetscFunctionBegin;
6636   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
6637   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
6638   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6639   ierr = DMSetDimension(rdm, dim);CHKERRQ(ierr);
6640   /* Calculate number of new points of each depth */
6641   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6642   if (depth >= 0 && dim != depth) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Mesh must be interpolated for regular refinement");
6643   ierr = PetscMalloc1(depth+1, &depthSize);CHKERRQ(ierr);
6644   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
6645   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
6646   /* Step 1: Set chart */
6647   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
6648   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
6649   /* Step 2: Set cone/support sizes */
6650   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6651   /* Step 3: Setup refined DM */
6652   ierr = DMSetUp(rdm);CHKERRQ(ierr);
6653   /* Step 4: Set cones and supports */
6654   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6655   /* Step 5: Stratify */
6656   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
6657   /* Step 6: Create pointSF */
6658   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6659   /* Step 7: Set coordinates for vertices */
6660   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6661   /* Step 8: Create labels */
6662   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6663   ierr = PetscFree(depthSize);CHKERRQ(ierr);
6664 
6665   *dmRefined = rdm;
6666   PetscFunctionReturn(0);
6667 }
6668 
6669 /*@
6670   DMPlexCreateCoarsePointIS - Creates an IS covering the coarse DM chart with the fine points as data
6671 
6672   Input Parameter:
6673 . dm - The coarse DM
6674 
6675   Output Parameter:
6676 . fpointIS - The IS of all the fine points which exist in the original coarse mesh
6677 
6678   Level: developer
6679 
6680 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexCreateSubpointIS()
6681 @*/
6682 PetscErrorCode DMPlexCreateCoarsePointIS(DM dm, IS *fpointIS)
6683 {
6684   CellRefiner    cellRefiner;
6685   PetscInt      *depthSize, *fpoints;
6686   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
6687   PetscInt       depth, pStart, pEnd, p, vStart, vEnd, v;
6688   PetscErrorCode ierr;
6689 
6690   PetscFunctionBegin;
6691   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6692   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6693   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6694   ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr);
6695   ierr = PetscMalloc1(depth+1, &depthSize);CHKERRQ(ierr);
6696   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
6697   if (cellRefiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
6698   ierr = PetscMalloc1(pEnd-pStart,&fpoints);CHKERRQ(ierr);
6699   for (p = 0; p < pEnd-pStart; ++p) fpoints[p] = -1;
6700   switch (cellRefiner) {
6701   case REFINER_SIMPLEX_1D:
6702   case REFINER_SIMPLEX_2D:
6703   case REFINER_HYBRID_SIMPLEX_2D:
6704   case REFINER_HEX_2D:
6705   case REFINER_HYBRID_HEX_2D:
6706   case REFINER_SIMPLEX_3D:
6707   case REFINER_HYBRID_SIMPLEX_3D:
6708   case REFINER_HEX_3D:
6709   case REFINER_HYBRID_HEX_3D:
6710     for (v = vStart; v < vEnd; ++v) fpoints[v-pStart] = vStartNew + (v - vStart);
6711     break;
6712   default:
6713     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", cellRefiner);
6714   }
6715   ierr = ISCreateGeneral(PETSC_COMM_SELF, pEnd-pStart, fpoints, PETSC_OWN_POINTER, fpointIS);CHKERRQ(ierr);
6716   ierr = PetscFree(depthSize);CHKERRQ(ierr);
6717   PetscFunctionReturn(0);
6718 }
6719 
6720 /*@
6721   DMPlexSetRefinementUniform - Set the flag for uniform refinement
6722 
6723   Input Parameters:
6724 + dm - The DM
6725 - refinementUniform - The flag for uniform refinement
6726 
6727   Level: developer
6728 
6729 .seealso: DMRefine(), DMPlexGetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
6730 @*/
6731 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
6732 {
6733   DM_Plex *mesh = (DM_Plex*) dm->data;
6734 
6735   PetscFunctionBegin;
6736   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6737   mesh->refinementUniform = refinementUniform;
6738   PetscFunctionReturn(0);
6739 }
6740 
6741 /*@
6742   DMPlexGetRefinementUniform - Retrieve the flag for uniform refinement
6743 
6744   Input Parameter:
6745 . dm - The DM
6746 
6747   Output Parameter:
6748 . refinementUniform - The flag for uniform refinement
6749 
6750   Level: developer
6751 
6752 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
6753 @*/
6754 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
6755 {
6756   DM_Plex *mesh = (DM_Plex*) dm->data;
6757 
6758   PetscFunctionBegin;
6759   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6760   PetscValidPointer(refinementUniform,  2);
6761   *refinementUniform = mesh->refinementUniform;
6762   PetscFunctionReturn(0);
6763 }
6764 
6765 /*@
6766   DMPlexSetRefinementLimit - Set the maximum cell volume for refinement
6767 
6768   Input Parameters:
6769 + dm - The DM
6770 - refinementLimit - The maximum cell volume in the refined mesh
6771 
6772   Level: developer
6773 
6774 .seealso: DMRefine(), DMPlexGetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
6775 @*/
6776 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
6777 {
6778   DM_Plex *mesh = (DM_Plex*) dm->data;
6779 
6780   PetscFunctionBegin;
6781   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6782   mesh->refinementLimit = refinementLimit;
6783   PetscFunctionReturn(0);
6784 }
6785 
6786 /*@
6787   DMPlexGetRefinementLimit - Retrieve the maximum cell volume for refinement
6788 
6789   Input Parameter:
6790 . dm - The DM
6791 
6792   Output Parameter:
6793 . refinementLimit - The maximum cell volume in the refined mesh
6794 
6795   Level: developer
6796 
6797 .seealso: DMRefine(), DMPlexSetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
6798 @*/
6799 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
6800 {
6801   DM_Plex *mesh = (DM_Plex*) dm->data;
6802 
6803   PetscFunctionBegin;
6804   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6805   PetscValidPointer(refinementLimit,  2);
6806   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
6807   *refinementLimit = mesh->refinementLimit;
6808   PetscFunctionReturn(0);
6809 }
6810 
6811 /*@
6812   DMPlexSetRefinementFunction - Set the function giving the maximum cell volume for refinement
6813 
6814   Input Parameters:
6815 + dm - The DM
6816 - refinementFunc - Function giving the maximum cell volume in the refined mesh
6817 
6818   Note: The calling sequence is refinementFunc(coords, limit)
6819 $ coords - Coordinates of the current point, usually a cell centroid
6820 $ limit  - The maximum cell volume for a cell containing this point
6821 
6822   Level: developer
6823 
6824 .seealso: DMRefine(), DMPlexGetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
6825 @*/
6826 PetscErrorCode DMPlexSetRefinementFunction(DM dm, PetscErrorCode (*refinementFunc)(const PetscReal [], PetscReal *))
6827 {
6828   DM_Plex *mesh = (DM_Plex*) dm->data;
6829 
6830   PetscFunctionBegin;
6831   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6832   mesh->refinementFunc = refinementFunc;
6833   PetscFunctionReturn(0);
6834 }
6835 
6836 /*@
6837   DMPlexGetRefinementFunction - Get the function giving the maximum cell volume for refinement
6838 
6839   Input Parameter:
6840 . dm - The DM
6841 
6842   Output Parameter:
6843 . refinementFunc - Function giving the maximum cell volume in the refined mesh
6844 
6845   Note: The calling sequence is refinementFunc(coords, limit)
6846 $ coords - Coordinates of the current point, usually a cell centroid
6847 $ limit  - The maximum cell volume for a cell containing this point
6848 
6849   Level: developer
6850 
6851 .seealso: DMRefine(), DMPlexSetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
6852 @*/
6853 PetscErrorCode DMPlexGetRefinementFunction(DM dm, PetscErrorCode (**refinementFunc)(const PetscReal [], PetscReal *))
6854 {
6855   DM_Plex *mesh = (DM_Plex*) dm->data;
6856 
6857   PetscFunctionBegin;
6858   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6859   PetscValidPointer(refinementFunc,  2);
6860   *refinementFunc = mesh->refinementFunc;
6861   PetscFunctionReturn(0);
6862 }
6863 
6864 PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
6865 {
6866   PetscInt       dim, cStart, cEnd, coneSize, cMax, fMax;
6867   PetscErrorCode ierr;
6868 
6869   PetscFunctionBegin;
6870   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6871   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6872   if (cEnd <= cStart) {*cellRefiner = REFINER_NOOP; PetscFunctionReturn(0);}
6873   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
6874   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, NULL, NULL);CHKERRQ(ierr);
6875   switch (dim) {
6876   case 1:
6877     switch (coneSize) {
6878     case 2:
6879       *cellRefiner = REFINER_SIMPLEX_1D;
6880       break;
6881     default:
6882       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
6883     }
6884     break;
6885   case 2:
6886     switch (coneSize) {
6887     case 3:
6888       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_2D;
6889       else *cellRefiner = REFINER_SIMPLEX_2D;
6890       break;
6891     case 4:
6892       if (cMax >= 0 && fMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_2D;
6893       else *cellRefiner = REFINER_HEX_2D;
6894       break;
6895     default:
6896       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
6897     }
6898     break;
6899   case 3:
6900     switch (coneSize) {
6901     case 4:
6902       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_3D;
6903       else *cellRefiner = REFINER_SIMPLEX_3D;
6904       break;
6905     case 6:
6906       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_3D;
6907       else *cellRefiner = REFINER_HEX_3D;
6908       break;
6909     default:
6910       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
6911     }
6912     break;
6913   default:
6914     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
6915   }
6916   PetscFunctionReturn(0);
6917 }
6918