xref: /petsc/src/dm/impls/plex/plexrefine.c (revision e91eccc2778f456fc991f5a9b142a3a67738bfd5)
1 #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <petscsf.h>
3 
4 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
5 {
6   PetscFunctionBegin;
7   if (cStart) *cStart = 0;
8   if (vStart) *vStart = depth < 0 ? 0 : depthSize[depth];
9   if (fStart) *fStart = depth < 0 ? 0 : depthSize[depth] + depthSize[0];
10   if (eStart) *eStart = depth < 0 ? 0 : depthSize[depth] + depthSize[0] + depthSize[depth-1];
11   PetscFunctionReturn(0);
12 }
13 
14 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
15 {
16   PetscFunctionBegin;
17   if (cEnd) *cEnd = depth < 0 ? 0 : depthSize[depth];
18   if (vEnd) *vEnd = depth < 0 ? 0 : depthSize[depth] + depthSize[0];
19   if (fEnd) *fEnd = depth < 0 ? 0 : depthSize[depth] + depthSize[0] + depthSize[depth-1];
20   if (eEnd) *eEnd = depth < 0 ? 0 : depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
21   PetscFunctionReturn(0);
22 }
23 
24 /* Gets the affine map from the original cell to each subcell */
25 PetscErrorCode CellRefinerGetAffineTransforms_Internal(CellRefiner refiner, PetscInt *numSubcells, PetscReal *v0[], PetscReal *jac[], PetscReal *invjac[])
26 {
27   PetscReal     *v = NULL, *j = NULL, *invj = NULL, detJ;
28   PetscInt       dim, s;
29   PetscErrorCode ierr;
30 
31   PetscFunctionBegin;
32   switch (refiner) {
33   case REFINER_NOOP: break;
34   case REFINER_SIMPLEX_2D:
35     /*
36      2
37      |\
38      | \
39      |  \
40      |   \
41      | C  \
42      |     \
43      |      \
44      2---1---1
45      |\  D  / \
46      | 2   0   \
47      |A \ /  B  \
48      0---0-------1
49      */
50     dim = 2;
51     if (numSubcells) *numSubcells = 4;
52     if (v0) {
53       ierr = PetscMalloc3(4*dim,&v,4*dim*dim,&j,4*dim*dim,&invj);CHKERRQ(ierr);
54       /* A */
55       v[0+0] = -1.0; v[0+1] = -1.0;
56       j[0+0] =  0.5; j[0+1] =  0.0;
57       j[0+2] =  0.0; j[0+3] =  0.5;
58       /* B */
59       v[2+0] =  0.0; v[2+1] = -1.0;
60       j[4+0] =  0.5; j[4+1] =  0.0;
61       j[4+2] =  0.0; j[4+3] =  0.5;
62       /* C */
63       v[4+0] = -1.0; v[4+1] =  0.0;
64       j[8+0] =  0.5; j[8+1] =  0.0;
65       j[8+2] =  0.0; j[8+3] =  0.5;
66       /* D */
67       v[6+0]  =  0.0; v[6+1]  = -1.0;
68       j[12+0] =  0.0; j[12+1] = -0.5;
69       j[12+2] =  0.5; j[12+3] =  0.5;
70       for (s = 0; s < 4; ++s) {
71         DMPlex_Det2D_Internal(&detJ, &j[s*dim*dim]);
72         DMPlex_Invert2D_Internal(&invj[s*dim*dim], &j[s*dim*dim], detJ);
73       }
74     }
75     break;
76   case REFINER_HEX_2D:
77     /*
78      3---------2---------2
79      |         |         |
80      |    D    2    C    |
81      |         |         |
82      3----3----0----1----1
83      |         |         |
84      |    A    0    B    |
85      |         |         |
86      0---------0---------1
87      */
88     dim = 2;
89     if (numSubcells) *numSubcells = 4;
90     if (v0) {
91       ierr = PetscMalloc3(4*dim,&v,4*dim*dim,&j,4*dim*dim,&invj);CHKERRQ(ierr);
92       /* A */
93       v[0+0] = -1.0; v[0+1] = -1.0;
94       j[0+0] =  0.5; j[0+1] =  0.0;
95       j[0+2] =  0.0; j[0+3] =  0.5;
96       /* B */
97       v[2+0] =  0.0; v[2+1] = -1.0;
98       j[4+0] =  0.5; j[4+1] =  0.0;
99       j[4+2] =  0.0; j[4+3] =  0.5;
100       /* C */
101       v[4+0] =  0.0; v[4+1] =  0.0;
102       j[8+0] =  0.5; j[8+1] =  0.0;
103       j[8+2] =  0.0; j[8+3] =  0.5;
104       /* D */
105       v[6+0]  = -1.0; v[6+1]  =  0.0;
106       j[12+0] =  0.5; j[12+1] =  0.0;
107       j[12+2] =  0.0; j[12+3] =  0.5;
108       for (s = 0; s < 4; ++s) {
109         DMPlex_Det2D_Internal(&detJ, &j[s*dim*dim]);
110         DMPlex_Invert2D_Internal(&invj[s*dim*dim], &j[s*dim*dim], detJ);
111       }
112     }
113     break;
114   default:
115     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
116   }
117   if (v0) {*v0 = v; *jac = j; *invjac = invj;}
118   PetscFunctionReturn(0);
119 }
120 
121 PetscErrorCode CellRefinerRestoreAffineTransforms_Internal(CellRefiner refiner, PetscInt *numSubcells, PetscReal *v0[], PetscReal *jac[], PetscReal *invjac[])
122 {
123   PetscErrorCode ierr;
124 
125   PetscFunctionBegin;
126   ierr = PetscFree3(*v0,*jac,*invjac);CHKERRQ(ierr);
127   PetscFunctionReturn(0);
128 }
129 
130 /* Should this be here or in the DualSpace somehow? */
131 PetscErrorCode CellRefinerInCellTest_Internal(CellRefiner refiner, const PetscReal point[], PetscBool *inside)
132 {
133   PetscReal sum = 0.0;
134   PetscInt  d;
135 
136   PetscFunctionBegin;
137   *inside = PETSC_TRUE;
138   switch (refiner) {
139   case REFINER_NOOP: break;
140   case REFINER_SIMPLEX_2D:
141     for (d = 0; d < 2; ++d) {
142       if (point[d] < -1.0) {*inside = PETSC_FALSE; break;}
143       sum += point[d];
144     }
145     if (sum > 1.0e-10) {*inside = PETSC_FALSE; break;}
146     break;
147   case REFINER_HEX_2D:
148     for (d = 0; d < 2; ++d) if ((point[d] < -1.00000000001) || (point[d] > 1.000000000001)) {*inside = PETSC_FALSE; break;}
149     break;
150   default:
151     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
152   }
153   PetscFunctionReturn(0);
154 }
155 
156 static PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
157 {
158   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
159   PetscErrorCode ierr;
160 
161   PetscFunctionBegin;
162   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
163   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
164   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
165   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
166   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
167   switch (refiner) {
168   case REFINER_NOOP:
169     break;
170   case REFINER_SIMPLEX_1D:
171     depthSize[0] = vEnd - vStart + cEnd - cStart;         /* Add a vertex on every cell. */
172     depthSize[1] = 2*(cEnd - cStart);                     /* Split every cell in 2. */
173     break;
174   case REFINER_SIMPLEX_2D:
175     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
176     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
177     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
178     break;
179   case REFINER_HYBRID_SIMPLEX_2D:
180     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
181     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
182     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
183     depthSize[1] = 2*(fMax - fStart) + 3*(cMax - cStart) + (fEnd - fMax) + (cEnd - cMax); /* Every interior face is split into 2 faces, 3 faces are added for each interior cell, and one in each hybrid cell */
184     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
185     break;
186   case REFINER_SIMPLEX_TO_HEX_2D:
187     depthSize[0] = vEnd - vStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every face and cell */
188     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart);         /* Every face is split into 2 faces and 3 faces are added for each cell */
189     depthSize[2] = 3*(cEnd - cStart);                             /* Every cell split into 3 cells */
190     break;
191   case REFINER_HEX_2D:
192     depthSize[0] = vEnd - vStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every face and cell */
193     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
194     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
195     break;
196   case REFINER_HYBRID_HEX_2D:
197     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
198     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
199     /* Quadrilateral */
200     depthSize[0] = vEnd - vStart + fMax - fStart + cMax - cStart;                 /* Add a vertex on every face and cell */
201     depthSize[1] = 2*(fMax - fStart) + 4*(cMax - cStart);                         /* Every face is split into 2 faces, and 4 faces are added for each cell */
202     depthSize[2] = 4*(cMax - cStart);                                             /* Every cell split into 4 cells */
203     /* Segment Prisms */
204     depthSize[0] += 0;                                                            /* No hybrid vertices */
205     depthSize[1] +=   (fEnd - fMax)  +   (cEnd - cMax);                           /* Every hybrid face remains and 1 faces is added for each hybrid cell */
206     depthSize[2] += 2*(cEnd - cMax);                                              /* Every hybrid cell split into 2 cells */
207     break;
208   case REFINER_SIMPLEX_3D:
209     depthSize[0] =    vEnd - vStart  +    eEnd - eStart;                    /* Add a vertex on every edge */
210     depthSize[1] = 2*(eEnd - eStart) + 3*(fEnd - fStart) + (cEnd - cStart); /* Every edge is split into 2 edges, 3 edges are added for each face, and 1 edge for each cell */
211     depthSize[2] = 4*(fEnd - fStart) + 8*(cEnd - cStart);                   /* Every face split into 4 faces and 8 faces are added for each cell */
212     depthSize[3] = 8*(cEnd - cStart);                                       /* Every cell split into 8 cells */
213     break;
214   case REFINER_HYBRID_SIMPLEX_3D:
215     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
216     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
217     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
218     /* Tetrahedra */
219     depthSize[0]  =    vEnd - vStart  +    eMax - eStart;                    /* Add a vertex on every interior edge */
220     depthSize[1]  = 2*(eMax - eStart) + 3*(fMax - fStart) + (cMax - cStart); /* Every interior edge split into 2 edges, 3 edges added for each interior face, 1 edge for each interior cell */
221     depthSize[2]  = 4*(fMax - fStart) + 8*(cMax - cStart);                   /* Every interior face split into 4 faces, 8 faces added for each interior cell */
222     depthSize[3]  = 8*(cMax - cStart);                                       /* Every interior cell split into 8 cells */
223     /* Triangular Prisms */
224     depthSize[0] += 0;                                                       /* No hybrid vertices */
225     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax);                     /* Every hybrid edge remains, 1 edge for every hybrid face */
226     depthSize[2] += 2*(fEnd - fMax)   + 3*(cEnd - cMax);                     /* Every hybrid face split into 2 faces and 3 faces are added for each hybrid cell */
227     depthSize[3] += 4*(cEnd - cMax);                                         /* Every hybrid cell split into 4 cells */
228     break;
229   case REFINER_SIMPLEX_TO_HEX_3D:
230     depthSize[0] = vEnd - vStart + fEnd - fStart + eEnd - eStart + cEnd - cStart; /* Add a vertex on every face, edge and cell */
231     depthSize[1] = 2*(eEnd - eStart) + 3*(fEnd - fStart) + 4*(cEnd - cStart);     /* Every edge is split into 2 edges, 3 edges are added for each face, and 4 for each cell */
232     depthSize[2] = 3*(fEnd - fStart) + 6*(cEnd - cStart);                         /* Every face is split into 3 faces and 6 faces are added for each cell */
233     depthSize[3] = 4*(cEnd - cStart);                                             /* Every cell split into 4 cells */
234     break;
235   case REFINER_HEX_3D:
236     depthSize[0] = vEnd - vStart + eEnd - eStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every edge, face and cell */
237     depthSize[1] = 2*(eEnd - eStart) +  4*(fEnd - fStart) + 6*(cEnd - cStart);    /* Every edge is split into 2 edge, 4 edges are added for each face, and 6 edges for each cell */
238     depthSize[2] = 4*(fEnd - fStart) + 12*(cEnd - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
239     depthSize[3] = 8*(cEnd - cStart);                                             /* Every cell split into 8 cells */
240     break;
241   case REFINER_HYBRID_HEX_3D:
242     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
243     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
244     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
245     /* Hexahedra */
246     depthSize[0] = vEnd - vStart + eMax - eStart + fMax - fStart + cMax - cStart; /* Add a vertex on every edge, face and cell */
247     depthSize[1] = 2*(eMax - eStart) +  4*(fMax - fStart) + 6*(cMax - cStart);    /* Every edge is split into 2 edge, 4 edges are added for each face, and 6 edges for each cell */
248     depthSize[2] = 4*(fMax - fStart) + 12*(cMax - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
249     depthSize[3] = 8*(cMax - cStart);                                             /* Every cell split into 8 cells */
250     /* Quadrilateral Prisms */
251     depthSize[0] += 0;                                                            /* No hybrid vertices */
252     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax)   +   (cEnd - cMax);      /* Every hybrid edge remains, 1 edge for every hybrid face and hybrid cell */
253     depthSize[2] += 2*(fEnd - fMax)   + 4*(cEnd - cMax);                          /* Every hybrid face split into 2 faces and 4 faces are added for each hybrid cell */
254     depthSize[3] += 4*(cEnd - cMax);                                              /* Every hybrid cell split into 4 cells */
255     break;
256   default:
257     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
258   }
259   PetscFunctionReturn(0);
260 }
261 
262 /* Return triangle edge for orientation o, if it is r for o == 0 */
263 PETSC_STATIC_INLINE PetscInt GetTriEdge_Static(PetscInt o, PetscInt r) {
264   return (o < 0 ? 2-(o+r) : o+r)%3;
265 }
266 PETSC_STATIC_INLINE PetscInt GetTriEdgeInverse_Static(PetscInt o, PetscInt s) {
267   return (o < 0 ? 2-(o+s) : 3+s-o)%3;
268 }
269 
270 /* Return triangle subface for orientation o, if it is r for o == 0 */
271 PETSC_STATIC_INLINE PetscInt GetTriSubface_Static(PetscInt o, PetscInt r) {
272   return (o < 0 ? 3-(o+r) : o+r)%3;
273 }
274 PETSC_STATIC_INLINE PetscInt GetTriSubfaceInverse_Static(PetscInt o, PetscInt s) {
275   return (o < 0 ? 3-(o+s) : 3+s-o)%3;
276 }
277 
278 /* Return the interior edge number connecting the midpoints of the triangle edges r
279    and r+1 in the transitive closure for triangle orientation o */
280 PETSC_STATIC_INLINE PetscInt GetTriMidEdge_Static(PetscInt o, PetscInt r) {
281   return (o < 0 ? 1-(o+r) : o+r)%3;
282 }
283 PETSC_STATIC_INLINE PetscInt GetTriMidEdgeInverse_Static(PetscInt o, PetscInt s) {
284   return (o < 0 ? 1-(o+s) : 3+s-o)%3;
285 }
286 
287 /* Return the interior edge number connecting the midpoint of the triangle edge r
288    (in the transitive closure) and the vertex in the interior of the face for triangle orientation o */
289 PETSC_STATIC_INLINE PetscInt GetTriInteriorEdge_Static(PetscInt o, PetscInt r) {
290   return (o < 0 ? 2-(o+r) : o+r)%3;
291 }
292 PETSC_STATIC_INLINE PetscInt GetTriInteriorEdgeInverse_Static(PetscInt o, PetscInt s) {
293   return (o < 0 ? 2-(o+s) : 3+s-o)%3;
294 }
295 
296 /* Return quad edge for orientation o, if it is r for o == 0 */
297 PETSC_STATIC_INLINE PetscInt GetQuadEdge_Static(PetscInt o, PetscInt r) {
298   return (o < 0 ? 3-(o+r) : o+r)%4;
299 }
300 PETSC_STATIC_INLINE PetscInt GetQuadEdgeInverse_Static(PetscInt o, PetscInt s) {
301   return (o < 0 ? 3-(o+s) : 4+s-o)%4;
302 }
303 
304 /* Return quad subface for orientation o, if it is r for o == 0 */
305 PETSC_STATIC_INLINE PetscInt GetQuadSubface_Static(PetscInt o, PetscInt r) {
306   return (o < 0 ? 4-(o+r) : o+r)%4;
307 }
308 PETSC_STATIC_INLINE PetscInt GetQuadSubfaceInverse_Static(PetscInt o, PetscInt s) {
309   return (o < 0 ? 4-(o+s) : 4+s-o)%4;
310 }
311 
312 static PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
313 {
314   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, e, r;
315   PetscErrorCode ierr;
316 
317   PetscFunctionBegin;
318   if (!refiner) PetscFunctionReturn(0);
319   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
320   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
321   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
322   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
323   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
324   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
325   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
326   switch (refiner) {
327   case REFINER_SIMPLEX_1D:
328     /* All cells have 2 vertices */
329     for (c = cStart; c < cEnd; ++c) {
330       for (r = 0; r < 2; ++r) {
331         const PetscInt newp = cStartNew + (c - cStart)*2 + r;
332 
333         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
334       }
335     }
336     /* Old vertices have identical supports */
337     for (v = vStart; v < vEnd; ++v) {
338       const PetscInt newp = vStartNew + (v - vStart);
339       PetscInt       size;
340 
341       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
342       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
343     }
344     /* Cell vertices have support 2 */
345     for (c = cStart; c < cEnd; ++c) {
346       const PetscInt newp = vStartNew + (vEnd - vStart) + (c - cStart);
347 
348       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
349     }
350     break;
351   case REFINER_SIMPLEX_2D:
352     /* All cells have 3 faces */
353     for (c = cStart; c < cEnd; ++c) {
354       for (r = 0; r < 4; ++r) {
355         const PetscInt newp = (c - cStart)*4 + r;
356 
357         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
358       }
359     }
360     /* Split faces have 2 vertices and the same cells as the parent */
361     for (f = fStart; f < fEnd; ++f) {
362       for (r = 0; r < 2; ++r) {
363         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
364         PetscInt       size;
365 
366         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
367         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
368         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
369       }
370     }
371     /* Interior faces have 2 vertices and 2 cells */
372     for (c = cStart; c < cEnd; ++c) {
373       for (r = 0; r < 3; ++r) {
374         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
375 
376         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
377         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
378       }
379     }
380     /* Old vertices have identical supports */
381     for (v = vStart; v < vEnd; ++v) {
382       const PetscInt newp = vStartNew + (v - vStart);
383       PetscInt       size;
384 
385       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
386       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
387     }
388     /* Face vertices have 2 + cells*2 supports */
389     for (f = fStart; f < fEnd; ++f) {
390       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
391       PetscInt       size;
392 
393       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
394       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
395     }
396     break;
397   case REFINER_SIMPLEX_TO_HEX_2D:
398     /* All cells have 4 faces */
399     for (c = cStart; c < cEnd; ++c) {
400       for (r = 0; r < 3; ++r) {
401         const PetscInt newp = (c - cStart)*3 + r;
402 
403         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
404       }
405     }
406     /* Split faces have 2 vertices and the same cells as the parent */
407     for (f = fStart; f < fEnd; ++f) {
408       for (r = 0; r < 2; ++r) {
409         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
410         PetscInt       size;
411 
412         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
413         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
414         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
415       }
416     }
417     /* Interior faces have 2 vertices and 2 cells */
418     for (c = cStart; c < cEnd; ++c) {
419       for (r = 0; r < 3; ++r) {
420         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
421 
422         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
423         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
424       }
425     }
426     /* Old vertices have identical supports */
427     for (v = vStart; v < vEnd; ++v) {
428       const PetscInt newp = vStartNew + (v - vStart);
429       PetscInt       size;
430 
431       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
432       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
433     }
434     /* Split-face vertices have cells + 2 supports */
435     for (f = fStart; f < fEnd; ++f) {
436       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
437       PetscInt       size;
438 
439       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
440       ierr = DMPlexSetSupportSize(rdm, newp, size + 2);CHKERRQ(ierr);
441     }
442     /* Interior vertices have 3 supports */
443     for (c = cStart; c < cEnd; ++c) {
444       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
445 
446       ierr = DMPlexSetSupportSize(rdm, newp, 3);CHKERRQ(ierr);
447     }
448     break;
449   case REFINER_HEX_2D:
450     /* All cells have 4 faces */
451     for (c = cStart; c < cEnd; ++c) {
452       for (r = 0; r < 4; ++r) {
453         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
454 
455         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
456       }
457     }
458     /* Split faces have 2 vertices and the same cells as the parent */
459     for (f = fStart; f < fEnd; ++f) {
460       for (r = 0; r < 2; ++r) {
461         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
462         PetscInt       size;
463 
464         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
465         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
466         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
467       }
468     }
469     /* Interior faces have 2 vertices and 2 cells */
470     for (c = cStart; c < cEnd; ++c) {
471       for (r = 0; r < 4; ++r) {
472         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
473 
474         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
475         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
476       }
477     }
478     /* Old vertices have identical supports */
479     for (v = vStart; v < vEnd; ++v) {
480       const PetscInt newp = vStartNew + (v - vStart);
481       PetscInt       size;
482 
483       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
484       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
485     }
486     /* Face vertices have 2 + cells supports */
487     for (f = fStart; f < fEnd; ++f) {
488       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
489       PetscInt       size;
490 
491       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
492       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
493     }
494     /* Cell vertices have 4 supports */
495     for (c = cStart; c < cEnd; ++c) {
496       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
497 
498       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
499     }
500     break;
501   case REFINER_HYBRID_SIMPLEX_2D:
502     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
503     cMax = PetscMin(cEnd, cMax);
504     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
505     fMax = PetscMin(fEnd, fMax);
506     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
507     /* Interior cells have 3 faces */
508     for (c = cStart; c < cMax; ++c) {
509       for (r = 0; r < 4; ++r) {
510         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
511 
512         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
513       }
514     }
515     /* Hybrid cells have 4 faces */
516     for (c = cMax; c < cEnd; ++c) {
517       for (r = 0; r < 2; ++r) {
518         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
519 
520         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
521       }
522     }
523     /* Interior split faces have 2 vertices and the same cells as the parent */
524     for (f = fStart; f < fMax; ++f) {
525       for (r = 0; r < 2; ++r) {
526         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
527         PetscInt       size;
528 
529         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
530         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
531         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
532       }
533     }
534     /* Interior cell faces have 2 vertices and 2 cells */
535     for (c = cStart; c < cMax; ++c) {
536       for (r = 0; r < 3; ++r) {
537         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
538 
539         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
540         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
541       }
542     }
543     /* Hybrid faces have 2 vertices and the same cells */
544     for (f = fMax; f < fEnd; ++f) {
545       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
546       PetscInt       size;
547 
548       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
549       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
550       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
551     }
552     /* Hybrid cell faces have 2 vertices and 2 cells */
553     for (c = cMax; c < cEnd; ++c) {
554       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
555 
556       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
557       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
558     }
559     /* Old vertices have identical supports */
560     for (v = vStart; v < vEnd; ++v) {
561       const PetscInt newp = vStartNew + (v - vStart);
562       PetscInt       size;
563 
564       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
565       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
566     }
567     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
568     for (f = fStart; f < fMax; ++f) {
569       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
570       const PetscInt *support;
571       PetscInt       size, newSize = 2, s;
572 
573       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
574       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
575       for (s = 0; s < size; ++s) {
576         if (support[s] >= cMax) newSize += 1;
577         else newSize += 2;
578       }
579       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
580     }
581     break;
582   case REFINER_HYBRID_HEX_2D:
583     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
584     cMax = PetscMin(cEnd, cMax);
585     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
586     fMax = PetscMin(fEnd, fMax);
587     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
588     /* Interior cells have 4 faces */
589     for (c = cStart; c < cMax; ++c) {
590       for (r = 0; r < 4; ++r) {
591         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
592 
593         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
594       }
595     }
596     /* Hybrid cells have 4 faces */
597     for (c = cMax; c < cEnd; ++c) {
598       for (r = 0; r < 2; ++r) {
599         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
600 
601         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
602       }
603     }
604     /* Interior split faces have 2 vertices and the same cells as the parent */
605     for (f = fStart; f < fMax; ++f) {
606       for (r = 0; r < 2; ++r) {
607         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
608         PetscInt       size;
609 
610         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
611         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
612         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
613       }
614     }
615     /* Interior cell faces have 2 vertices and 2 cells */
616     for (c = cStart; c < cMax; ++c) {
617       for (r = 0; r < 4; ++r) {
618         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
619 
620         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
621         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
622       }
623     }
624     /* Hybrid faces have 2 vertices and the same cells */
625     for (f = fMax; f < fEnd; ++f) {
626       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
627       PetscInt       size;
628 
629       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
630       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
631       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
632     }
633     /* Hybrid cell faces have 2 vertices and 2 cells */
634     for (c = cMax; c < cEnd; ++c) {
635       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
636 
637       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
638       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
639     }
640     /* Old vertices have identical supports */
641     for (v = vStart; v < vEnd; ++v) {
642       const PetscInt newp = vStartNew + (v - vStart);
643       PetscInt       size;
644 
645       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
646       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
647     }
648     /* Face vertices have 2 + cells supports */
649     for (f = fStart; f < fMax; ++f) {
650       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
651       PetscInt       size;
652 
653       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
654       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
655     }
656     /* Cell vertices have 4 supports */
657     for (c = cStart; c < cMax; ++c) {
658       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
659 
660       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
661     }
662     break;
663   case REFINER_SIMPLEX_3D:
664     /* All cells have 4 faces */
665     for (c = cStart; c < cEnd; ++c) {
666       for (r = 0; r < 8; ++r) {
667         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
668 
669         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
670       }
671     }
672     /* Split faces have 3 edges and the same cells as the parent */
673     for (f = fStart; f < fEnd; ++f) {
674       for (r = 0; r < 4; ++r) {
675         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
676         PetscInt       size;
677 
678         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
679         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
680         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
681       }
682     }
683     /* Interior cell faces have 3 edges and 2 cells */
684     for (c = cStart; c < cEnd; ++c) {
685       for (r = 0; r < 8; ++r) {
686         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + r;
687 
688         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
689         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
690       }
691     }
692     /* Split edges have 2 vertices and the same faces */
693     for (e = eStart; e < eEnd; ++e) {
694       for (r = 0; r < 2; ++r) {
695         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
696         PetscInt       size;
697 
698         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
699         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
700         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
701       }
702     }
703     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
704     for (f = fStart; f < fEnd; ++f) {
705       for (r = 0; r < 3; ++r) {
706         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
707         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
708         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;
709 
710         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
711         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
712         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
713         for (s = 0; s < supportSize; ++s) {
714           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
715           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
716           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
717           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
718           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
719           er = GetTriMidEdgeInverse_Static(ornt[c], r);
720           if (er == eint[c]) {
721             intFaces += 1;
722           } else {
723             intFaces += 2;
724           }
725         }
726         ierr = DMPlexSetSupportSize(rdm, newp, 2+intFaces);CHKERRQ(ierr);
727       }
728     }
729     /* Interior cell edges have 2 vertices and 4 faces */
730     for (c = cStart; c < cEnd; ++c) {
731       const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
732 
733       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
734       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
735     }
736     /* Old vertices have identical supports */
737     for (v = vStart; v < vEnd; ++v) {
738       const PetscInt newp = vStartNew + (v - vStart);
739       PetscInt       size;
740 
741       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
742       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
743     }
744     /* Edge vertices have 2 + faces*2 + cells*0/1 supports */
745     for (e = eStart; e < eEnd; ++e) {
746       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
747       PetscInt       size, *star = NULL, starSize, s, cellSize = 0;
748 
749       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
750       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
751       for (s = 0; s < starSize*2; s += 2) {
752         const PetscInt *cone, *ornt;
753         PetscInt        e01, e23;
754 
755         if ((star[s] >= cStart) && (star[s] < cEnd)) {
756           /* Check edge 0-1 */
757           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
758           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
759           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
760           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
761           /* Check edge 2-3 */
762           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
763           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
764           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
765           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
766           if ((e01 == e) || (e23 == e)) ++cellSize;
767         }
768       }
769       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
770       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2 + cellSize);CHKERRQ(ierr);
771     }
772     break;
773   case REFINER_HYBRID_SIMPLEX_3D:
774     ierr = DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 8*(cMax - cStart),
775                                  eStartNew + 2*(eMax - eStart) + 3*(fMax - fStart) + (cMax - cStart), PETSC_DETERMINE);CHKERRQ(ierr);
776     /* Interior cells have 4 faces */
777     for (c = cStart; c < cMax; ++c) {
778       for (r = 0; r < 8; ++r) {
779         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
780 
781         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
782       }
783     }
784     /* Hybrid cells have 5 faces */
785     for (c = cMax; c < cEnd; ++c) {
786       for (r = 0; r < 4; ++r) {
787         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;
788 
789         ierr = DMPlexSetConeSize(rdm, newp, 5);CHKERRQ(ierr);
790       }
791     }
792     /* Interior split faces have 3 edges and the same cells as the parent */
793     for (f = fStart; f < fMax; ++f) {
794       for (r = 0; r < 4; ++r) {
795         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
796         PetscInt       size;
797 
798         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
799         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
800         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
801       }
802     }
803     /* Interior cell faces have 3 edges and 2 cells */
804     for (c = cStart; c < cMax; ++c) {
805       for (r = 0; r < 8; ++r) {
806         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + r;
807 
808         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
809         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
810       }
811     }
812     /* Hybrid split faces have 4 edges and the same cells as the parent */
813     for (f = fMax; f < fEnd; ++f) {
814       for (r = 0; r < 2; ++r) {
815         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
816         PetscInt       size;
817 
818         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
819         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
820         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
821       }
822     }
823     /* Hybrid cells faces have 4 edges and 2 cells */
824     for (c = cMax; c < cEnd; ++c) {
825       for (r = 0; r < 3; ++r) {
826         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + r;
827 
828         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
829         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
830       }
831     }
832     /* Interior split edges have 2 vertices and the same faces */
833     for (e = eStart; e < eMax; ++e) {
834       for (r = 0; r < 2; ++r) {
835         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
836         PetscInt       size;
837 
838         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
839         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
840         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
841       }
842     }
843     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
844     for (f = fStart; f < fMax; ++f) {
845       for (r = 0; r < 3; ++r) {
846         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
847         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
848         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;
849 
850         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
851         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
852         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
853         for (s = 0; s < supportSize; ++s) {
854           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
855           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
856           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
857           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
858           if (support[s] < cMax) {
859             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
860             er = GetTriMidEdgeInverse_Static(ornt[c], r);
861             if (er == eint[c]) {
862               intFaces += 1;
863             } else {
864               intFaces += 2;
865             }
866           } else {
867             intFaces += 1;
868           }
869         }
870         ierr = DMPlexSetSupportSize(rdm, newp, 2+intFaces);CHKERRQ(ierr);
871       }
872     }
873     /* Interior cell edges have 2 vertices and 4 faces */
874     for (c = cStart; c < cMax; ++c) {
875       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
876 
877       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
878       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
879     }
880     /* Hybrid edges have 2 vertices and the same faces */
881     for (e = eMax; e < eEnd; ++e) {
882       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
883       PetscInt       size;
884 
885       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
886       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
887       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
888     }
889     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
890     for (f = fMax; f < fEnd; ++f) {
891       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
892       PetscInt       size;
893 
894       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
895       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
896       ierr = DMPlexSetSupportSize(rdm, newp, 2+2*size);CHKERRQ(ierr);
897     }
898     /* Interior vertices have identical supports */
899     for (v = vStart; v < vEnd; ++v) {
900       const PetscInt newp = vStartNew + (v - vStart);
901       PetscInt       size;
902 
903       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
904       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
905     }
906     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
907     for (e = eStart; e < eMax; ++e) {
908       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
909       const PetscInt *support;
910       PetscInt        size, *star = NULL, starSize, s, faceSize = 0, cellSize = 0;
911 
912       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
913       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
914       for (s = 0; s < size; ++s) {
915         if (support[s] < fMax) faceSize += 2;
916         else                   faceSize += 1;
917       }
918       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
919       for (s = 0; s < starSize*2; s += 2) {
920         const PetscInt *cone, *ornt;
921         PetscInt        e01, e23;
922 
923         if ((star[s] >= cStart) && (star[s] < cMax)) {
924           /* Check edge 0-1 */
925           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
926           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
927           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
928           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
929           /* Check edge 2-3 */
930           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
931           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
932           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
933           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
934           if ((e01 == e) || (e23 == e)) ++cellSize;
935         }
936       }
937       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
938       ierr = DMPlexSetSupportSize(rdm, newp, 2 + faceSize + cellSize);CHKERRQ(ierr);
939     }
940     break;
941   case REFINER_SIMPLEX_TO_HEX_3D:
942     /* All cells have 6 faces */
943     for (c = cStart; c < cEnd; ++c) {
944       for (r = 0; r < 4; ++r) {
945         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
946 
947         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
948       }
949     }
950     /* Split faces have 4 edges and the same cells as the parent */
951     for (f = fStart; f < fEnd; ++f) {
952       for (r = 0; r < 3; ++r) {
953         const PetscInt newp = fStartNew + (f - fStart)*3 + r;
954         PetscInt       size;
955 
956         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
957         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
958         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
959       }
960     }
961     /* Interior cell faces have 4 edges and 2 cells */
962     for (c = cStart; c < cEnd; ++c) {
963       for (r = 0; r < 6; ++r) {
964         const PetscInt newp = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + r;
965 
966         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
967         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
968       }
969     }
970     /* Split edges have 2 vertices and the same faces */
971     for (e = eStart; e < eEnd; ++e) {
972       for (r = 0; r < 2; ++r) {
973         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
974         PetscInt       size;
975 
976         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
977         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
978         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
979       }
980     }
981     /* Face edges have 2 vertices and 2 + cell faces supports */
982     for (f = fStart; f < fEnd; ++f) {
983       for (r = 0; r < 3; ++r) {
984         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
985         PetscInt        size;
986 
987         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
988         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
989         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
990       }
991     }
992     /* Interior cell edges have 2 vertices and 3 faces */
993     for (c = cStart; c < cEnd; ++c) {
994       for (r = 0; r < 4; ++r) {
995         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + r;
996 
997         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
998         ierr = DMPlexSetSupportSize(rdm, newp, 3);CHKERRQ(ierr);
999       }
1000     }
1001     /* Old vertices have identical supports */
1002     for (v = vStart; v < vEnd; ++v) {
1003       const PetscInt newp = vStartNew + (v - vStart);
1004       PetscInt       size;
1005 
1006       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1007       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1008     }
1009     /* Edge vertices have 2 + faces supports */
1010     for (e = eStart; e < eEnd; ++e) {
1011       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1012       PetscInt       size;
1013 
1014       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1015       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1016     }
1017     /* Face vertices have 3 + cells supports */
1018     for (f = fStart; f < fEnd; ++f) {
1019       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + f - fStart;
1020       PetscInt       size;
1021 
1022       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1023       ierr = DMPlexSetSupportSize(rdm, newp, 3 + size);CHKERRQ(ierr);
1024     }
1025     /* Interior cell vertices have 4 supports */
1026     for (c = cStart; c < cEnd; ++c) {
1027       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + fEnd - fStart + c - cStart;
1028 
1029       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1030     }
1031     break;
1032   case REFINER_HEX_3D:
1033     /* All cells have 6 faces */
1034     for (c = cStart; c < cEnd; ++c) {
1035       for (r = 0; r < 8; ++r) {
1036         const PetscInt newp = (c - cStart)*8 + r;
1037 
1038         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1039       }
1040     }
1041     /* Split faces have 4 edges and the same cells as the parent */
1042     for (f = fStart; f < fEnd; ++f) {
1043       for (r = 0; r < 4; ++r) {
1044         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
1045         PetscInt       size;
1046 
1047         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1048         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1049         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1050       }
1051     }
1052     /* Interior faces have 4 edges and 2 cells */
1053     for (c = cStart; c < cEnd; ++c) {
1054       for (r = 0; r < 12; ++r) {
1055         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
1056 
1057         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1058         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1059       }
1060     }
1061     /* Split edges have 2 vertices and the same faces as the parent */
1062     for (e = eStart; e < eEnd; ++e) {
1063       for (r = 0; r < 2; ++r) {
1064         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1065         PetscInt       size;
1066 
1067         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1068         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1069         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1070       }
1071     }
1072     /* Face edges have 2 vertices and 2+cells faces */
1073     for (f = fStart; f < fEnd; ++f) {
1074       for (r = 0; r < 4; ++r) {
1075         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
1076         PetscInt       size;
1077 
1078         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1079         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1080         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1081       }
1082     }
1083     /* Cell edges have 2 vertices and 4 faces */
1084     for (c = cStart; c < cEnd; ++c) {
1085       for (r = 0; r < 6; ++r) {
1086         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
1087 
1088         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1089         ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1090       }
1091     }
1092     /* Old vertices have identical supports */
1093     for (v = vStart; v < vEnd; ++v) {
1094       const PetscInt newp = vStartNew + (v - vStart);
1095       PetscInt       size;
1096 
1097       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1098       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1099     }
1100     /* Edge vertices have 2 + faces supports */
1101     for (e = eStart; e < eEnd; ++e) {
1102       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1103       PetscInt       size;
1104 
1105       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1106       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1107     }
1108     /* Face vertices have 4 + cells supports */
1109     for (f = fStart; f < fEnd; ++f) {
1110       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
1111       PetscInt       size;
1112 
1113       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1114       ierr = DMPlexSetSupportSize(rdm, newp, 4 + size);CHKERRQ(ierr);
1115     }
1116     /* Cell vertices have 6 supports */
1117     for (c = cStart; c < cEnd; ++c) {
1118       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
1119 
1120       ierr = DMPlexSetSupportSize(rdm, newp, 6);CHKERRQ(ierr);
1121     }
1122     break;
1123   case REFINER_HYBRID_HEX_3D:
1124     ierr = DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 12*(cMax - cStart),
1125                                  eStartNew + 2*(eMax - eStart) + 4*(fMax - fStart) + 6*(cMax - cStart), PETSC_DETERMINE);CHKERRQ(ierr);
1126     /* Interior cells have 6 faces */
1127     for (c = cStart; c < cMax; ++c) {
1128       for (r = 0; r < 8; ++r) {
1129         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
1130 
1131         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1132       }
1133     }
1134     /* Hybrid cells have 6 faces */
1135     for (c = cMax; c < cEnd; ++c) {
1136       for (r = 0; r < 4; ++r) {
1137         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;
1138 
1139         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
1140       }
1141     }
1142     /* Interior split faces have 4 edges and the same cells as the parent */
1143     for (f = fStart; f < fMax; ++f) {
1144       for (r = 0; r < 4; ++r) {
1145         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
1146         PetscInt       size;
1147 
1148         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1149         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1150         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1151       }
1152     }
1153     /* Interior cell faces have 4 edges and 2 cells */
1154     for (c = cStart; c < cMax; ++c) {
1155       for (r = 0; r < 12; ++r) {
1156         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
1157 
1158         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1159         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1160       }
1161     }
1162     /* Hybrid split faces have 4 edges and the same cells as the parent */
1163     for (f = fMax; f < fEnd; ++f) {
1164       for (r = 0; r < 2; ++r) {
1165         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
1166         PetscInt       size;
1167 
1168         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1169         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1170         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1171       }
1172     }
1173     /* Hybrid cells faces have 4 edges and 2 cells */
1174     for (c = cMax; c < cEnd; ++c) {
1175       for (r = 0; r < 4; ++r) {
1176         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + r;
1177 
1178         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1179         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1180       }
1181     }
1182     /* Interior split edges have 2 vertices and the same faces as the parent */
1183     for (e = eStart; e < eMax; ++e) {
1184       for (r = 0; r < 2; ++r) {
1185         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1186         PetscInt       size;
1187 
1188         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1189         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1190         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1191       }
1192     }
1193     /* Interior face edges have 2 vertices and 2+cells faces */
1194     for (f = fStart; f < fMax; ++f) {
1195       for (r = 0; r < 4; ++r) {
1196         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
1197         PetscInt       size;
1198 
1199         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1200         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1201         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1202       }
1203     }
1204     /* Interior cell edges have 2 vertices and 4 faces */
1205     for (c = cStart; c < cMax; ++c) {
1206       for (r = 0; r < 6; ++r) {
1207         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
1208 
1209         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1210         ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1211       }
1212     }
1213     /* Hybrid edges have 2 vertices and the same faces */
1214     for (e = eMax; e < eEnd; ++e) {
1215       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
1216       PetscInt       size;
1217 
1218       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1219       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1220       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1221     }
1222     /* Hybrid face edges have 2 vertices and 2+cells faces */
1223     for (f = fMax; f < fEnd; ++f) {
1224       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
1225       PetscInt       size;
1226 
1227       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1228       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1229       ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1230     }
1231     /* Hybrid cell edges have 2 vertices and 4 faces */
1232     for (c = cMax; c < cEnd; ++c) {
1233       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
1234 
1235       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1236       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1237     }
1238     /* Interior vertices have identical supports */
1239     for (v = vStart; v < vEnd; ++v) {
1240       const PetscInt newp = vStartNew + (v - vStart);
1241       PetscInt       size;
1242 
1243       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1244       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1245     }
1246     /* Interior edge vertices have 2 + faces supports */
1247     for (e = eStart; e < eMax; ++e) {
1248       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1249       PetscInt       size;
1250 
1251       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1252       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1253     }
1254     /* Interior face vertices have 4 + cells supports */
1255     for (f = fStart; f < fMax; ++f) {
1256       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
1257       PetscInt       size;
1258 
1259       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1260       ierr = DMPlexSetSupportSize(rdm, newp, 4 + size);CHKERRQ(ierr);
1261     }
1262     /* Interior cell vertices have 6 supports */
1263     for (c = cStart; c < cMax; ++c) {
1264       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
1265 
1266       ierr = DMPlexSetSupportSize(rdm, newp, 6);CHKERRQ(ierr);
1267     }
1268     break;
1269   default:
1270     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
1271   }
1272   PetscFunctionReturn(0);
1273 }
1274 
1275 static PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
1276 {
1277   const PetscInt *faces, cellInd[4] = {0, 1, 2, 3};
1278   PetscInt        cStart,    cEnd,    cMax,    vStart,    vEnd, vMax, fStart,    fEnd,    fMax,    eStart,    eEnd,    eMax;
1279   PetscInt        cStartNew, cEndNew, cMaxNew, vStartNew, vEndNew,    fStartNew, fEndNew, fMaxNew, eStartNew, eEndNew, eMaxNew;
1280   PetscInt        depth, maxSupportSize, *supportRef, c, f, e, v, r, p;
1281   PetscErrorCode  ierr;
1282 
1283   PetscFunctionBegin;
1284   if (!refiner) PetscFunctionReturn(0);
1285   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1286   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
1287   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
1288   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1289   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
1290   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
1291   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
1292   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
1293   switch (refiner) {
1294   case REFINER_SIMPLEX_1D:
1295     /* Max support size of refined mesh is 2 */
1296     ierr = PetscMalloc1(2, &supportRef);CHKERRQ(ierr);
1297     /* All cells have 2 vertices */
1298     for (c = cStart; c < cEnd; ++c) {
1299       const PetscInt  newv = vStartNew + (vEnd - vStart) + (c - cStart);
1300 
1301       for (r = 0; r < 2; ++r) {
1302         const PetscInt newp = cStartNew + (c - cStart)*2 + r;
1303         const PetscInt *cone;
1304         PetscInt        coneNew[2];
1305 
1306         ierr             = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1307         coneNew[0]       = vStartNew + (cone[0] - vStart);
1308         coneNew[1]       = vStartNew + (cone[1] - vStart);
1309         coneNew[(r+1)%2] = newv;
1310         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1311 #if 1
1312         if ((newp < cStartNew) || (newp >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp, cStartNew, cEndNew);
1313         for (p = 0; p < 2; ++p) {
1314           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
1315         }
1316 #endif
1317       }
1318     }
1319     /* Old vertices have identical supports */
1320     for (v = vStart; v < vEnd; ++v) {
1321       const PetscInt  newp = vStartNew + (v - vStart);
1322       const PetscInt *support, *cone;
1323       PetscInt        size, s;
1324 
1325       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1326       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1327       for (s = 0; s < size; ++s) {
1328         PetscInt r = 0;
1329 
1330         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1331         if (cone[1] == v) r = 1;
1332         supportRef[s] = cStartNew + (support[s] - cStart)*2 + r;
1333       }
1334       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1335 #if 1
1336       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1337       for (p = 0; p < size; ++p) {
1338         if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
1339       }
1340 #endif
1341     }
1342     /* Cell vertices have support of 2 cells */
1343     for (c = cStart; c < cEnd; ++c) {
1344       const PetscInt  newp = vStartNew + (vEnd - vStart) + (c - cStart);
1345 
1346       supportRef[0] = cStartNew + (c - cStart)*2 + 0;
1347       supportRef[1] = cStartNew + (c - cStart)*2 + 1;
1348       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1349 #if 1
1350       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1351       for (p = 0; p < 2; ++p) {
1352         if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
1353       }
1354 #endif
1355     }
1356     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1357     break;
1358   case REFINER_SIMPLEX_2D:
1359     /*
1360      2
1361      |\
1362      | \
1363      |  \
1364      |   \
1365      | C  \
1366      |     \
1367      |      \
1368      2---1---1
1369      |\  D  / \
1370      | 2   0   \
1371      |A \ /  B  \
1372      0---0-------1
1373      */
1374     /* All cells have 3 faces */
1375     for (c = cStart; c < cEnd; ++c) {
1376       const PetscInt  newp = cStartNew + (c - cStart)*4;
1377       const PetscInt *cone, *ornt;
1378       PetscInt        coneNew[3], orntNew[3];
1379 
1380       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1381       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1382       /* A triangle */
1383       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1384       orntNew[0] = ornt[0];
1385       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1386       orntNew[1] = -2;
1387       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1388       orntNew[2] = ornt[2];
1389       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1390       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1391 #if 1
1392       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
1393       for (p = 0; p < 3; ++p) {
1394         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1395       }
1396 #endif
1397       /* B triangle */
1398       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1399       orntNew[0] = ornt[0];
1400       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1401       orntNew[1] = ornt[1];
1402       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1403       orntNew[2] = -2;
1404       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1405       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1406 #if 1
1407       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
1408       for (p = 0; p < 3; ++p) {
1409         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1410       }
1411 #endif
1412       /* C triangle */
1413       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1414       orntNew[0] = -2;
1415       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1416       orntNew[1] = ornt[1];
1417       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1418       orntNew[2] = ornt[2];
1419       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1420       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1421 #if 1
1422       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
1423       for (p = 0; p < 3; ++p) {
1424         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1425       }
1426 #endif
1427       /* D triangle */
1428       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1429       orntNew[0] = 0;
1430       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1431       orntNew[1] = 0;
1432       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1433       orntNew[2] = 0;
1434       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1435       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1436 #if 1
1437       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
1438       for (p = 0; p < 3; ++p) {
1439         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1440       }
1441 #endif
1442     }
1443     /* Split faces have 2 vertices and the same cells as the parent */
1444     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1445     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
1446     for (f = fStart; f < fEnd; ++f) {
1447       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1448 
1449       for (r = 0; r < 2; ++r) {
1450         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1451         const PetscInt *cone, *ornt, *support;
1452         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1453 
1454         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1455         coneNew[0]       = vStartNew + (cone[0] - vStart);
1456         coneNew[1]       = vStartNew + (cone[1] - vStart);
1457         coneNew[(r+1)%2] = newv;
1458         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1459 #if 1
1460         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1461         for (p = 0; p < 2; ++p) {
1462           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
1463         }
1464 #endif
1465         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1466         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1467         for (s = 0; s < supportSize; ++s) {
1468           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1469           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1470           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1471           for (c = 0; c < coneSize; ++c) {
1472             if (cone[c] == f) break;
1473           }
1474           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1475         }
1476         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1477 #if 1
1478         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1479         for (p = 0; p < supportSize; ++p) {
1480           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
1481         }
1482 #endif
1483       }
1484     }
1485     /* Interior faces have 2 vertices and 2 cells */
1486     for (c = cStart; c < cEnd; ++c) {
1487       const PetscInt *cone;
1488 
1489       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1490       for (r = 0; r < 3; ++r) {
1491         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
1492         PetscInt       coneNew[2];
1493         PetscInt       supportNew[2];
1494 
1495         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
1496         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
1497         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1498 #if 1
1499         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1500         for (p = 0; p < 2; ++p) {
1501           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
1502         }
1503 #endif
1504         supportNew[0] = (c - cStart)*4 + (r+1)%3;
1505         supportNew[1] = (c - cStart)*4 + 3;
1506         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1507 #if 1
1508         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1509         for (p = 0; p < 2; ++p) {
1510           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
1511         }
1512 #endif
1513       }
1514     }
1515     /* Old vertices have identical supports */
1516     for (v = vStart; v < vEnd; ++v) {
1517       const PetscInt  newp = vStartNew + (v - vStart);
1518       const PetscInt *support, *cone;
1519       PetscInt        size, s;
1520 
1521       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1522       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1523       for (s = 0; s < size; ++s) {
1524         PetscInt r = 0;
1525 
1526         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1527         if (cone[1] == v) r = 1;
1528         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1529       }
1530       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1531 #if 1
1532       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1533       for (p = 0; p < size; ++p) {
1534         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
1535       }
1536 #endif
1537     }
1538     /* Face vertices have 2 + cells*2 supports */
1539     for (f = fStart; f < fEnd; ++f) {
1540       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1541       const PetscInt *cone, *support;
1542       PetscInt        size, s;
1543 
1544       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1545       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1546       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1547       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1548       for (s = 0; s < size; ++s) {
1549         PetscInt r = 0;
1550 
1551         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1552         if      (cone[1] == f) r = 1;
1553         else if (cone[2] == f) r = 2;
1554         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
1555         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
1556       }
1557       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1558 #if 1
1559       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1560       for (p = 0; p < 2+size*2; ++p) {
1561         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
1562       }
1563 #endif
1564     }
1565     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1566     break;
1567   case REFINER_SIMPLEX_TO_HEX_2D:
1568     /*
1569      2
1570      |\
1571      | \
1572      |  \
1573      |   \
1574      | C  \
1575      |     \
1576      2      1
1577      |\    / \
1578      | 2  1   \
1579      |  \/     \
1580      |   |      \
1581      |A  |   B   \
1582      |   0        \
1583      |   |         \
1584      0---0----------1
1585      */
1586     /* All cells have 4 faces */
1587     for (c = cStart; c < cEnd; ++c) {
1588       const PetscInt  newp = cStartNew + (c - cStart)*3;
1589       const PetscInt *cone, *ornt;
1590       PetscInt        coneNew[4], orntNew[4];
1591 
1592       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1593       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1594       /* A quad */
1595       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1596       orntNew[0] = ornt[0];
1597       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1598       orntNew[1] = 0;
1599       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1600       orntNew[2] = -2;
1601       coneNew[3] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1602       orntNew[3] = ornt[2];
1603       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1604       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1605 #if 1
1606       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
1607       for (p = 0; p < 4; ++p) {
1608         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1609       }
1610 #endif
1611       /* B quad */
1612       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1613       orntNew[0] = ornt[0];
1614       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1615       orntNew[1] = ornt[1];
1616       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1617       orntNew[2] = 0;
1618       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1619       orntNew[3] = -2;
1620       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1621       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1622 #if 1
1623       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
1624       for (p = 0; p < 4; ++p) {
1625         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1626       }
1627 #endif
1628       /* C quad */
1629       coneNew[0] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1630       orntNew[0] = ornt[1];
1631       coneNew[1] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1632       orntNew[1] = ornt[2];
1633       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1634       orntNew[2] = 0;
1635       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1636       orntNew[3] = -2;
1637       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1638       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1639 #if 1
1640       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
1641       for (p = 0; p < 4; ++p) {
1642         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1643       }
1644 #endif
1645     }
1646     /* Split faces have 2 vertices and the same cells as the parent */
1647     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1648     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
1649     for (f = fStart; f < fEnd; ++f) {
1650       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1651 
1652       for (r = 0; r < 2; ++r) {
1653         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1654         const PetscInt *cone, *ornt, *support;
1655         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1656 
1657         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1658         coneNew[0]       = vStartNew + (cone[0] - vStart);
1659         coneNew[1]       = vStartNew + (cone[1] - vStart);
1660         coneNew[(r+1)%2] = newv;
1661         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1662 #if 1
1663         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1664         for (p = 0; p < 2; ++p) {
1665           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
1666         }
1667 #endif
1668         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1669         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1670         for (s = 0; s < supportSize; ++s) {
1671           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1672           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1673           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1674           for (c = 0; c < coneSize; ++c) {
1675             if (cone[c] == f) break;
1676           }
1677           supportRef[s] = cStartNew + (support[s] - cStart)*3 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1678         }
1679         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1680 #if 1
1681         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1682         for (p = 0; p < supportSize; ++p) {
1683           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
1684         }
1685 #endif
1686       }
1687     }
1688     /* Interior faces have 2 vertices and 2 cells */
1689     for (c = cStart; c < cEnd; ++c) {
1690       const PetscInt *cone;
1691 
1692       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1693       for (r = 0; r < 3; ++r) {
1694         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
1695         PetscInt       coneNew[2];
1696         PetscInt       supportNew[2];
1697 
1698         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
1699         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
1700         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1701 #if 1
1702         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1703         for (p = 0; p < 2; ++p) {
1704           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
1705         }
1706 #endif
1707         supportNew[0] = (c - cStart)*3 + r%3;
1708         supportNew[1] = (c - cStart)*3 + (r+1)%3;
1709         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1710 #if 1
1711         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1712         for (p = 0; p < 2; ++p) {
1713           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
1714         }
1715 #endif
1716       }
1717     }
1718     /* Old vertices have identical supports */
1719     for (v = vStart; v < vEnd; ++v) {
1720       const PetscInt  newp = vStartNew + (v - vStart);
1721       const PetscInt *support, *cone;
1722       PetscInt        size, s;
1723 
1724       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1725       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1726       for (s = 0; s < size; ++s) {
1727         PetscInt r = 0;
1728 
1729         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1730         if (cone[1] == v) r = 1;
1731         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1732       }
1733       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1734 #if 1
1735       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1736       for (p = 0; p < size; ++p) {
1737         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
1738       }
1739 #endif
1740     }
1741     /* Split-face vertices have cells + 2 supports */
1742     for (f = fStart; f < fEnd; ++f) {
1743       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1744       const PetscInt *cone, *support;
1745       PetscInt        size, s;
1746 
1747       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1748       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1749       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1750       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1751       for (s = 0; s < size; ++s) {
1752         PetscInt r = 0;
1753 
1754         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1755         if      (cone[1] == f) r = 1;
1756         else if (cone[2] == f) r = 2;
1757         supportRef[2+s+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
1758       }
1759       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1760 #if 1
1761       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1762       for (p = 0; p < 2+size; ++p) {
1763         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
1764       }
1765 #endif
1766     }
1767     /* Interior vertices vertices have 3 supports */
1768     for (c = cStart; c < cEnd; ++c) {
1769       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + c - cStart;
1770 
1771       supportRef[0] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 0;
1772       supportRef[1] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 1;
1773       supportRef[2] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + 2;
1774       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1775     }
1776     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1777     break;
1778   case REFINER_HEX_2D:
1779     /*
1780      3---------2---------2
1781      |         |         |
1782      |    D    2    C    |
1783      |         |         |
1784      3----3----0----1----1
1785      |         |         |
1786      |    A    0    B    |
1787      |         |         |
1788      0---------0---------1
1789      */
1790     /* All cells have 4 faces */
1791     for (c = cStart; c < cEnd; ++c) {
1792       const PetscInt  newp = (c - cStart)*4;
1793       const PetscInt *cone, *ornt;
1794       PetscInt        coneNew[4], orntNew[4];
1795 
1796       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1797       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1798       /* A quad */
1799       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1800       orntNew[0] = ornt[0];
1801       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
1802       orntNew[1] = 0;
1803       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
1804       orntNew[2] = -2;
1805       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
1806       orntNew[3] = ornt[3];
1807       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1808       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1809 #if 1
1810       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
1811       for (p = 0; p < 4; ++p) {
1812         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1813       }
1814 #endif
1815       /* B quad */
1816       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1817       orntNew[0] = ornt[0];
1818       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1819       orntNew[1] = ornt[1];
1820       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
1821       orntNew[2] = -2;
1822       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
1823       orntNew[3] = -2;
1824       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1825       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1826 #if 1
1827       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
1828       for (p = 0; p < 4; ++p) {
1829         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1830       }
1831 #endif
1832       /* C quad */
1833       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
1834       orntNew[0] = 0;
1835       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1836       orntNew[1] = ornt[1];
1837       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1838       orntNew[2] = ornt[2];
1839       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
1840       orntNew[3] = -2;
1841       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1842       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1843 #if 1
1844       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
1845       for (p = 0; p < 4; ++p) {
1846         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1847       }
1848 #endif
1849       /* D quad */
1850       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
1851       orntNew[0] = 0;
1852       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
1853       orntNew[1] = 0;
1854       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1855       orntNew[2] = ornt[2];
1856       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
1857       orntNew[3] = ornt[3];
1858       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1859       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1860 #if 1
1861       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
1862       for (p = 0; p < 4; ++p) {
1863         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
1864       }
1865 #endif
1866     }
1867     /* Split faces have 2 vertices and the same cells as the parent */
1868     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1869     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
1870     for (f = fStart; f < fEnd; ++f) {
1871       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1872 
1873       for (r = 0; r < 2; ++r) {
1874         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1875         const PetscInt *cone, *ornt, *support;
1876         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1877 
1878         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1879         coneNew[0]       = vStartNew + (cone[0] - vStart);
1880         coneNew[1]       = vStartNew + (cone[1] - vStart);
1881         coneNew[(r+1)%2] = newv;
1882         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1883 #if 1
1884         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1885         for (p = 0; p < 2; ++p) {
1886           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
1887         }
1888 #endif
1889         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1890         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1891         for (s = 0; s < supportSize; ++s) {
1892           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1893           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1894           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1895           for (c = 0; c < coneSize; ++c) {
1896             if (cone[c] == f) break;
1897           }
1898           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
1899         }
1900         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1901 #if 1
1902         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1903         for (p = 0; p < supportSize; ++p) {
1904           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
1905         }
1906 #endif
1907       }
1908     }
1909     /* Interior faces have 2 vertices and 2 cells */
1910     for (c = cStart; c < cEnd; ++c) {
1911       const PetscInt *cone;
1912       PetscInt        coneNew[2], supportNew[2];
1913 
1914       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1915       for (r = 0; r < 4; ++r) {
1916         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
1917 
1918 	if (r==1 || r==2) {
1919           coneNew[0] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
1920           coneNew[1] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
1921 	} else {
1922           coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
1923           coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
1924 	}
1925 	ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1926 #if 1
1927         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1928         for (p = 0; p < 2; ++p) {
1929           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
1930         }
1931 #endif
1932         supportNew[0] = (c - cStart)*4 + r;
1933         supportNew[1] = (c - cStart)*4 + (r+1)%4;
1934         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1935 #if 1
1936         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1937         for (p = 0; p < 2; ++p) {
1938           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
1939         }
1940 #endif
1941       }
1942     }
1943     /* Old vertices have identical supports */
1944     for (v = vStart; v < vEnd; ++v) {
1945       const PetscInt  newp = vStartNew + (v - vStart);
1946       const PetscInt *support, *cone;
1947       PetscInt        size, s;
1948 
1949       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1950       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1951       for (s = 0; s < size; ++s) {
1952         PetscInt r = 0;
1953 
1954         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1955         if (cone[1] == v) r = 1;
1956         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1957       }
1958       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1959 #if 1
1960       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1961       for (p = 0; p < size; ++p) {
1962         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
1963       }
1964 #endif
1965     }
1966     /* Face vertices have 2 + cells supports */
1967     for (f = fStart; f < fEnd; ++f) {
1968       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1969       const PetscInt *cone, *support;
1970       PetscInt        size, s;
1971 
1972       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1973       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1974       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1975       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1976       for (s = 0; s < size; ++s) {
1977         PetscInt r = 0;
1978 
1979         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1980         if      (cone[1] == f) r = 1;
1981         else if (cone[2] == f) r = 2;
1982         else if (cone[3] == f) r = 3;
1983         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
1984       }
1985       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1986 #if 1
1987       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1988       for (p = 0; p < 2+size; ++p) {
1989         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
1990       }
1991 #endif
1992     }
1993     /* Cell vertices have 4 supports */
1994     for (c = cStart; c < cEnd; ++c) {
1995       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
1996       PetscInt       supportNew[4];
1997 
1998       for (r = 0; r < 4; ++r) {
1999         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
2000       }
2001       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2002     }
2003     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2004     break;
2005   case REFINER_HYBRID_SIMPLEX_2D:
2006     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
2007     cMax = PetscMin(cEnd, cMax);
2008     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
2009     fMax = PetscMin(fEnd, fMax);
2010     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);CHKERRQ(ierr);
2011     /* Interior cells have 3 faces */
2012     for (c = cStart; c < cMax; ++c) {
2013       const PetscInt  newp = cStartNew + (c - cStart)*4;
2014       const PetscInt *cone, *ornt;
2015       PetscInt        coneNew[3], orntNew[3];
2016 
2017       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2018       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2019       /* A triangle */
2020       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2021       orntNew[0] = ornt[0];
2022       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
2023       orntNew[1] = -2;
2024       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2025       orntNew[2] = ornt[2];
2026       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2027       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2028 #if 1
2029       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+0, cStartNew, cMaxNew);
2030       for (p = 0; p < 3; ++p) {
2031         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2032       }
2033 #endif
2034       /* B triangle */
2035       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2036       orntNew[0] = ornt[0];
2037       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2038       orntNew[1] = ornt[1];
2039       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
2040       orntNew[2] = -2;
2041       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2042       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2043 #if 1
2044       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+1, cStartNew, cMaxNew);
2045       for (p = 0; p < 3; ++p) {
2046         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2047       }
2048 #endif
2049       /* C triangle */
2050       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
2051       orntNew[0] = -2;
2052       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2053       orntNew[1] = ornt[1];
2054       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2055       orntNew[2] = ornt[2];
2056       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2057       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2058 #if 1
2059       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+2, cStartNew, cMaxNew);
2060       for (p = 0; p < 3; ++p) {
2061         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2062       }
2063 #endif
2064       /* D triangle */
2065       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
2066       orntNew[0] = 0;
2067       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
2068       orntNew[1] = 0;
2069       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
2070       orntNew[2] = 0;
2071       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2072       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2073 #if 1
2074       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+3, cStartNew, cMaxNew);
2075       for (p = 0; p < 3; ++p) {
2076         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2077       }
2078 #endif
2079     }
2080     /*
2081      2----3----3
2082      |         |
2083      |    B    |
2084      |         |
2085      0----4--- 1
2086      |         |
2087      |    A    |
2088      |         |
2089      0----2----1
2090      */
2091     /* Hybrid cells have 4 faces */
2092     for (c = cMax; c < cEnd; ++c) {
2093       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
2094       const PetscInt *cone, *ornt;
2095       PetscInt        coneNew[4], orntNew[4], r;
2096 
2097       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2098       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2099       r    = (ornt[0] < 0 ? 1 : 0);
2100       /* A quad */
2101       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + r;
2102       orntNew[0]   = ornt[0];
2103       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + r;
2104       orntNew[1]   = ornt[1];
2105       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2+r] - fMax);
2106       orntNew[2+r] = 0;
2107       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
2108       orntNew[3-r] = 0;
2109       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2110       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2111 #if 1
2112       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
2113       for (p = 0; p < 4; ++p) {
2114         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2115       }
2116 #endif
2117       /* B quad */
2118       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + 1-r;
2119       orntNew[0]   = ornt[0];
2120       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + 1-r;
2121       orntNew[1]   = ornt[1];
2122       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
2123       orntNew[2+r] = 0;
2124       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3-r] - fMax);
2125       orntNew[3-r] = 0;
2126       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2127       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2128 #if 1
2129       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
2130       for (p = 0; p < 4; ++p) {
2131         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2132       }
2133 #endif
2134     }
2135     /* Interior split faces have 2 vertices and the same cells as the parent */
2136     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2137     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2138     for (f = fStart; f < fMax; ++f) {
2139       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
2140 
2141       for (r = 0; r < 2; ++r) {
2142         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2143         const PetscInt *cone, *ornt, *support;
2144         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2145 
2146         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2147         coneNew[0]       = vStartNew + (cone[0] - vStart);
2148         coneNew[1]       = vStartNew + (cone[1] - vStart);
2149         coneNew[(r+1)%2] = newv;
2150         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2151 #if 1
2152         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2153         for (p = 0; p < 2; ++p) {
2154           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2155         }
2156 #endif
2157         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2158         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2159         for (s = 0; s < supportSize; ++s) {
2160           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2161           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2162           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2163           for (c = 0; c < coneSize; ++c) if (cone[c] == f) break;
2164           if (support[s] >= cMax) {
2165             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[c] < 0 ? 1-r : r);
2166           } else {
2167             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
2168           }
2169         }
2170         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2171 #if 1
2172         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2173         for (p = 0; p < supportSize; ++p) {
2174           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
2175         }
2176 #endif
2177       }
2178     }
2179     /* Interior cell faces have 2 vertices and 2 cells */
2180     for (c = cStart; c < cMax; ++c) {
2181       const PetscInt *cone;
2182 
2183       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2184       for (r = 0; r < 3; ++r) {
2185         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
2186         PetscInt       coneNew[2];
2187         PetscInt       supportNew[2];
2188 
2189         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
2190         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
2191         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2192 #if 1
2193         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2194         for (p = 0; p < 2; ++p) {
2195           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2196         }
2197 #endif
2198         supportNew[0] = (c - cStart)*4 + (r+1)%3;
2199         supportNew[1] = (c - cStart)*4 + 3;
2200         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2201 #if 1
2202         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2203         for (p = 0; p < 2; ++p) {
2204           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
2205         }
2206 #endif
2207       }
2208     }
2209     /* Interior hybrid faces have 2 vertices and the same cells */
2210     for (f = fMax; f < fEnd; ++f) {
2211       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
2212       const PetscInt *cone, *ornt;
2213       const PetscInt *support;
2214       PetscInt        coneNew[2];
2215       PetscInt        supportNew[2];
2216       PetscInt        size, s, r;
2217 
2218       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2219       coneNew[0] = vStartNew + (cone[0] - vStart);
2220       coneNew[1] = vStartNew + (cone[1] - vStart);
2221       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2222 #if 1
2223       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2224       for (p = 0; p < 2; ++p) {
2225         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2226       }
2227 #endif
2228       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2229       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2230       for (s = 0; s < size; ++s) {
2231         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2232         ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2233         for (r = 0; r < 2; ++r) {
2234           if (cone[r+2] == f) break;
2235         }
2236         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[0] < 0 ? 1-r : r);
2237       }
2238       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2239 #if 1
2240       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2241       for (p = 0; p < size; ++p) {
2242         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
2243       }
2244 #endif
2245     }
2246     /* Cell hybrid faces have 2 vertices and 2 cells */
2247     for (c = cMax; c < cEnd; ++c) {
2248       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
2249       const PetscInt *cone;
2250       PetscInt        coneNew[2];
2251       PetscInt        supportNew[2];
2252 
2253       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2254       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
2255       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
2256       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2257 #if 1
2258       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2259       for (p = 0; p < 2; ++p) {
2260         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2261       }
2262 #endif
2263       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
2264       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
2265       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2266 #if 1
2267       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2268       for (p = 0; p < 2; ++p) {
2269         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
2270       }
2271 #endif
2272     }
2273     /* Old vertices have identical supports */
2274     for (v = vStart; v < vEnd; ++v) {
2275       const PetscInt  newp = vStartNew + (v - vStart);
2276       const PetscInt *support, *cone;
2277       PetscInt        size, s;
2278 
2279       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2280       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2281       for (s = 0; s < size; ++s) {
2282         if (support[s] >= fMax) {
2283           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
2284         } else {
2285           PetscInt r = 0;
2286 
2287           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2288           if (cone[1] == v) r = 1;
2289           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2290         }
2291       }
2292       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2293 #if 1
2294       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2295       for (p = 0; p < size; ++p) {
2296         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
2297       }
2298 #endif
2299     }
2300     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
2301     for (f = fStart; f < fMax; ++f) {
2302       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2303       const PetscInt *cone, *support;
2304       PetscInt        size, newSize = 2, s;
2305 
2306       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2307       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2308       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2309       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2310       for (s = 0; s < size; ++s) {
2311         PetscInt r = 0;
2312 
2313         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2314         if (support[s] >= cMax) {
2315           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
2316 
2317           newSize += 1;
2318         } else {
2319           if      (cone[1] == f) r = 1;
2320           else if (cone[2] == f) r = 2;
2321           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
2322           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
2323 
2324           newSize += 2;
2325         }
2326       }
2327       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2328 #if 1
2329       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2330       for (p = 0; p < newSize; ++p) {
2331         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
2332       }
2333 #endif
2334     }
2335     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2336     break;
2337   case REFINER_HYBRID_HEX_2D:
2338     /* Hybrid Hex 2D */
2339     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
2340     cMax = PetscMin(cEnd, cMax);
2341     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
2342     fMax = PetscMin(fEnd, fMax);
2343     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);CHKERRQ(ierr);
2344     /* Interior cells have 4 faces */
2345     for (c = cStart; c < cMax; ++c) {
2346       const PetscInt  newp = cStartNew + (c - cStart)*4;
2347       const PetscInt *cone, *ornt;
2348       PetscInt        coneNew[4], orntNew[4];
2349 
2350       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2351       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2352       /* A quad */
2353       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2354       orntNew[0] = ornt[0];
2355       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
2356       orntNew[1] = 0;
2357       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
2358       orntNew[2] = -2;
2359       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
2360       orntNew[3] = ornt[3];
2361       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2362       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2363 #if 1
2364       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+0, cStartNew, cMaxNew);
2365       for (p = 0; p < 4; ++p) {
2366         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2367       }
2368 #endif
2369       /* B quad */
2370       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2371       orntNew[0] = ornt[0];
2372       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2373       orntNew[1] = ornt[1];
2374       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
2375       orntNew[2] = 0;
2376       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
2377       orntNew[3] = -2;
2378       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2379       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2380 #if 1
2381       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+1, cStartNew, cMaxNew);
2382       for (p = 0; p < 4; ++p) {
2383         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2384       }
2385 #endif
2386       /* C quad */
2387       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
2388       orntNew[0] = -2;
2389       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2390       orntNew[1] = ornt[1];
2391       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2392       orntNew[2] = ornt[2];
2393       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
2394       orntNew[3] = 0;
2395       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2396       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2397 #if 1
2398       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+2, cStartNew, cMaxNew);
2399       for (p = 0; p < 4; ++p) {
2400         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2401       }
2402 #endif
2403       /* D quad */
2404       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
2405       orntNew[0] = 0;
2406       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
2407       orntNew[1] = -2;
2408       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2409       orntNew[2] = ornt[2];
2410       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
2411       orntNew[3] = ornt[3];
2412       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2413       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2414 #if 1
2415       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior cell [%d, %d)", newp+3, cStartNew, cMaxNew);
2416       for (p = 0; p < 4; ++p) {
2417         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
2418       }
2419 #endif
2420     }
2421     /*
2422      2----3----3
2423      |         |
2424      |    B    |
2425      |         |
2426      0----4--- 1
2427      |         |
2428      |    A    |
2429      |         |
2430      0----2----1
2431      */
2432     /* Hybrid cells have 4 faces */
2433     for (c = cMax; c < cEnd; ++c) {
2434       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
2435       const PetscInt *cone, *ornt;
2436       PetscInt        coneNew[4], orntNew[4];
2437 
2438       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2439       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2440       /* A quad */
2441       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2442       orntNew[0] = ornt[0];
2443       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2444       orntNew[1] = ornt[1];
2445       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[2] - fMax);
2446       orntNew[2] = 0;
2447       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
2448       orntNew[3] = 0;
2449       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2450       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2451 #if 1
2452       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
2453       for (p = 0; p < 4; ++p) {
2454         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2455       }
2456 #endif
2457       /* B quad */
2458       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2459       orntNew[0] = ornt[0];
2460       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2461       orntNew[1] = ornt[1];
2462       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
2463       orntNew[2] = 0;
2464       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[3] - fMax);
2465       orntNew[3] = 0;
2466       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2467       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2468 #if 1
2469       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
2470       for (p = 0; p < 4; ++p) {
2471         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2472       }
2473 #endif
2474     }
2475     /* Interior split faces have 2 vertices and the same cells as the parent */
2476     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2477     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2478     for (f = fStart; f < fMax; ++f) {
2479       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
2480 
2481       for (r = 0; r < 2; ++r) {
2482         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2483         const PetscInt *cone, *ornt, *support;
2484         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2485 
2486         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2487         coneNew[0]       = vStartNew + (cone[0] - vStart);
2488         coneNew[1]       = vStartNew + (cone[1] - vStart);
2489         coneNew[(r+1)%2] = newv;
2490         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2491 #if 1
2492         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2493         for (p = 0; p < 2; ++p) {
2494           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2495         }
2496 #endif
2497         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2498         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2499         for (s = 0; s < supportSize; ++s) {
2500           if (support[s] >= cMax) {
2501             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
2502           } else {
2503             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2504             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2505             ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2506             for (c = 0; c < coneSize; ++c) {
2507               if (cone[c] == f) break;
2508             }
2509             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
2510           }
2511         }
2512         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2513 #if 1
2514         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2515         for (p = 0; p < supportSize; ++p) {
2516           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
2517         }
2518 #endif
2519       }
2520     }
2521     /* Interior cell faces have 2 vertices and 2 cells */
2522     for (c = cStart; c < cMax; ++c) {
2523       const PetscInt *cone;
2524 
2525       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2526       for (r = 0; r < 4; ++r) {
2527         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
2528         PetscInt       coneNew[2], supportNew[2];
2529 
2530         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2531         coneNew[1] = vStartNew + (vEnd - vStart) + (fMax    - fStart) + (c - cStart);
2532         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2533 #if 1
2534         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2535         for (p = 0; p < 2; ++p) {
2536           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2537         }
2538 #endif
2539         supportNew[0] = (c - cStart)*4 + r;
2540         supportNew[1] = (c - cStart)*4 + (r+1)%4;
2541         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2542 #if 1
2543         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2544         for (p = 0; p < 2; ++p) {
2545           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
2546         }
2547 #endif
2548       }
2549     }
2550     /* Hybrid faces have 2 vertices and the same cells */
2551     for (f = fMax; f < fEnd; ++f) {
2552       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
2553       const PetscInt *cone, *support;
2554       PetscInt        coneNew[2], supportNew[2];
2555       PetscInt        size, s, r;
2556 
2557       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2558       coneNew[0] = vStartNew + (cone[0] - vStart);
2559       coneNew[1] = vStartNew + (cone[1] - vStart);
2560       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2561 #if 1
2562       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2563       for (p = 0; p < 2; ++p) {
2564         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2565       }
2566 #endif
2567       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2568       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2569       for (s = 0; s < size; ++s) {
2570         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2571         for (r = 0; r < 2; ++r) {
2572           if (cone[r+2] == f) break;
2573         }
2574         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
2575       }
2576       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2577 #if 1
2578       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2579       for (p = 0; p < size; ++p) {
2580         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
2581       }
2582 #endif
2583     }
2584     /* Cell hybrid faces have 2 vertices and 2 cells */
2585     for (c = cMax; c < cEnd; ++c) {
2586       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
2587       const PetscInt *cone;
2588       PetscInt        coneNew[2], supportNew[2];
2589 
2590       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2591       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
2592       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
2593       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2594 #if 1
2595       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2596       for (p = 0; p < 2; ++p) {
2597         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
2598       }
2599 #endif
2600       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
2601       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
2602       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2603 #if 1
2604       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2605       for (p = 0; p < 2; ++p) {
2606         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
2607       }
2608 #endif
2609     }
2610     /* Old vertices have identical supports */
2611     for (v = vStart; v < vEnd; ++v) {
2612       const PetscInt  newp = vStartNew + (v - vStart);
2613       const PetscInt *support, *cone;
2614       PetscInt        size, s;
2615 
2616       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2617       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2618       for (s = 0; s < size; ++s) {
2619         if (support[s] >= fMax) {
2620           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (support[s] - fMax);
2621         } else {
2622           PetscInt r = 0;
2623 
2624           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2625           if (cone[1] == v) r = 1;
2626           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2627         }
2628       }
2629       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2630 #if 1
2631       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2632       for (p = 0; p < size; ++p) {
2633         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
2634       }
2635 #endif
2636     }
2637     /* Face vertices have 2 + cells supports */
2638     for (f = fStart; f < fMax; ++f) {
2639       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2640       const PetscInt *cone, *support;
2641       PetscInt        size, s;
2642 
2643       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2644       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2645       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2646       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2647       for (s = 0; s < size; ++s) {
2648         PetscInt r = 0;
2649 
2650         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2651         if (support[s] >= cMax) {
2652           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (support[s] - cMax);
2653         } else {
2654           if      (cone[1] == f) r = 1;
2655           else if (cone[2] == f) r = 2;
2656           else if (cone[3] == f) r = 3;
2657           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*4 + r;
2658         }
2659       }
2660       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2661 #if 1
2662       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2663       for (p = 0; p < 2+size; ++p) {
2664         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
2665       }
2666 #endif
2667     }
2668     /* Cell vertices have 4 supports */
2669     for (c = cStart; c < cMax; ++c) {
2670       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
2671       PetscInt       supportNew[4];
2672 
2673       for (r = 0; r < 4; ++r) {
2674         supportNew[r] = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
2675       }
2676       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2677     }
2678     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2679     break;
2680   case REFINER_SIMPLEX_3D:
2681     /* All cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
2682     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
2683     for (c = cStart; c < cEnd; ++c) {
2684       const PetscInt  newp = cStartNew + (c - cStart)*8;
2685       const PetscInt *cone, *ornt;
2686       PetscInt        coneNew[4], orntNew[4];
2687 
2688       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2689       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2690       /* A tetrahedron: {0, a, c, d} */
2691       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
2692       orntNew[0] = ornt[0];
2693       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
2694       orntNew[1] = ornt[1];
2695       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
2696       orntNew[2] = ornt[2];
2697       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
2698       orntNew[3] = 0;
2699       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2700       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2701 #if 1
2702       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
2703       for (p = 0; p < 4; ++p) {
2704         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2705       }
2706 #endif
2707       /* B tetrahedron: {a, 1, b, e} */
2708       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
2709       orntNew[0] = ornt[0];
2710       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
2711       orntNew[1] = ornt[1];
2712       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
2713       orntNew[2] = 0;
2714       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
2715       orntNew[3] = ornt[3];
2716       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2717       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2718 #if 1
2719       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
2720       for (p = 0; p < 4; ++p) {
2721         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2722       }
2723 #endif
2724       /* C tetrahedron: {c, b, 2, f} */
2725       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
2726       orntNew[0] = ornt[0];
2727       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
2728       orntNew[1] = 0;
2729       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
2730       orntNew[2] = ornt[2];
2731       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
2732       orntNew[3] = ornt[3];
2733       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2734       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2735 #if 1
2736       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
2737       for (p = 0; p < 4; ++p) {
2738         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2739       }
2740 #endif
2741       /* D tetrahedron: {d, e, f, 3} */
2742       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
2743       orntNew[0] = 0;
2744       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
2745       orntNew[1] = ornt[1];
2746       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
2747       orntNew[2] = ornt[2];
2748       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
2749       orntNew[3] = ornt[3];
2750       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2751       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2752 #if 1
2753       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
2754       for (p = 0; p < 4; ++p) {
2755         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2756       }
2757 #endif
2758       /* A' tetrahedron: {c, d, a, f} */
2759       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
2760       orntNew[0] = -3;
2761       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
2762       orntNew[1] = ornt[2] < 0 ? -(GetTriMidEdge_Static(ornt[2], 0)+1) : GetTriMidEdge_Static(ornt[2], 0);
2763       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
2764       orntNew[2] = 0;
2765       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
2766       orntNew[3] = 2;
2767       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
2768       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
2769 #if 1
2770       if ((newp+4 < cStartNew) || (newp+4 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+4, cStartNew, cEndNew);
2771       for (p = 0; p < 4; ++p) {
2772         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2773       }
2774 #endif
2775       /* B' tetrahedron: {e, b, a, f} */
2776       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
2777       orntNew[0] = -2;
2778       coneNew[1] = fStartNew + (cone[3] - fStart)*4 + 3;
2779       orntNew[1] = ornt[3] < 0 ? -(GetTriMidEdge_Static(ornt[3], 1)+1) : GetTriMidEdge_Static(ornt[3], 1);
2780       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
2781       orntNew[2] = 0;
2782       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
2783       orntNew[3] = 0;
2784       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
2785       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
2786 #if 1
2787       if ((newp+5 < cStartNew) || (newp+5 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+5, cStartNew, cEndNew);
2788       for (p = 0; p < 4; ++p) {
2789         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2790       }
2791 #endif
2792       /* C' tetrahedron: {f, a, c, b} */
2793       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
2794       orntNew[0] = -2;
2795       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
2796       orntNew[1] = -2;
2797       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
2798       orntNew[2] = -1;
2799       coneNew[3] = fStartNew + (cone[0] - fStart)*4 + 3;
2800       orntNew[3] = ornt[0] < 0 ? -(GetTriMidEdge_Static(ornt[0], 2)+1) : GetTriMidEdge_Static(ornt[0], 2);
2801       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
2802       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
2803 #if 1
2804       if ((newp+6 < cStartNew) || (newp+6 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+6, cStartNew, cEndNew);
2805       for (p = 0; p < 4; ++p) {
2806         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2807       }
2808 #endif
2809       /* D' tetrahedron: {f, a, e, d} */
2810       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
2811       orntNew[0] = -2;
2812       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
2813       orntNew[1] = -1;
2814       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
2815       orntNew[2] = -2;
2816       coneNew[3] = fStartNew + (cone[1] - fStart)*4 + 3;
2817       orntNew[3] = ornt[1] < 0 ? -(GetTriMidEdge_Static(ornt[1], 1)+1) : GetTriMidEdge_Static(ornt[1], 1);
2818       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
2819       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
2820 #if 1
2821       if ((newp+7 < cStartNew) || (newp+7 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+7, cStartNew, cEndNew);
2822       for (p = 0; p < 4; ++p) {
2823         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
2824       }
2825 #endif
2826     }
2827     /* Split faces have 3 edges and the same cells as the parent */
2828     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2829     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2830     for (f = fStart; f < fEnd; ++f) {
2831       const PetscInt  newp = fStartNew + (f - fStart)*4;
2832       const PetscInt *cone, *ornt, *support;
2833       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
2834 
2835       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2836       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
2837       /* A triangle */
2838       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
2839       orntNew[0] = ornt[0];
2840       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
2841       orntNew[1] = -2;
2842       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
2843       orntNew[2] = ornt[2];
2844       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2845       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2846 #if 1
2847       if ((newp+0 < fStartNew) || (newp+0 >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+0, fStartNew, fEndNew);
2848       for (p = 0; p < 3; ++p) {
2849         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
2850       }
2851 #endif
2852       /* B triangle */
2853       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
2854       orntNew[0] = ornt[0];
2855       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
2856       orntNew[1] = ornt[1];
2857       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
2858       orntNew[2] = -2;
2859       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2860       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2861 #if 1
2862       if ((newp+1 < fStartNew) || (newp+1 >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+1, fStartNew, fEndNew);
2863       for (p = 0; p < 3; ++p) {
2864         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
2865       }
2866 #endif
2867       /* C triangle */
2868       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
2869       orntNew[0] = -2;
2870       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
2871       orntNew[1] = ornt[1];
2872       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
2873       orntNew[2] = ornt[2];
2874       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2875       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2876 #if 1
2877       if ((newp+2 < fStartNew) || (newp+2 >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+2, fStartNew, fEndNew);
2878       for (p = 0; p < 3; ++p) {
2879         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
2880       }
2881 #endif
2882       /* D triangle */
2883       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
2884       orntNew[0] = 0;
2885       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
2886       orntNew[1] = 0;
2887       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
2888       orntNew[2] = 0;
2889       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2890       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2891 #if 1
2892       if ((newp+3 < fStartNew) || (newp+3 >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+3, fStartNew, fEndNew);
2893       for (p = 0; p < 3; ++p) {
2894         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
2895       }
2896 #endif
2897       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2898       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2899       for (r = 0; r < 4; ++r) {
2900         for (s = 0; s < supportSize; ++s) {
2901           PetscInt subf;
2902           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2903           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2904           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2905           for (c = 0; c < coneSize; ++c) {
2906             if (cone[c] == f) break;
2907           }
2908           subf = GetTriSubfaceInverse_Static(ornt[c], r);
2909           supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
2910         }
2911         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
2912 #if 1
2913         if ((newp+r < fStartNew) || (newp+r >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+r, fStartNew, fEndNew);
2914         for (p = 0; p < supportSize; ++p) {
2915           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
2916         }
2917 #endif
2918       }
2919     }
2920     /* Interior faces have 3 edges and 2 cells */
2921     for (c = cStart; c < cEnd; ++c) {
2922       PetscInt        newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8;
2923       const PetscInt *cone, *ornt;
2924       PetscInt        coneNew[3], orntNew[3];
2925       PetscInt        supportNew[2];
2926 
2927       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2928       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2929       /* Face A: {c, a, d} */
2930       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
2931       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2932       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
2933       orntNew[1] = ornt[1] < 0 ? -2 : 0;
2934       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 2);
2935       orntNew[2] = ornt[2] < 0 ? -2 : 0;
2936       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2937       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2938 #if 1
2939       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2940       for (p = 0; p < 3; ++p) {
2941         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
2942       }
2943 #endif
2944       supportNew[0] = (c - cStart)*8 + 0;
2945       supportNew[1] = (c - cStart)*8 + 0+4;
2946       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2947 #if 1
2948       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2949       for (p = 0; p < 2; ++p) {
2950         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
2951       }
2952 #endif
2953       ++newp;
2954       /* Face B: {a, b, e} */
2955       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
2956       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2957       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 0);
2958       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2959       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
2960       orntNew[2] = ornt[1] < 0 ? -2 : 0;
2961       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2962       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2963 #if 1
2964       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2965       for (p = 0; p < 3; ++p) {
2966         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
2967       }
2968 #endif
2969       supportNew[0] = (c - cStart)*8 + 1;
2970       supportNew[1] = (c - cStart)*8 + 1+4;
2971       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2972 #if 1
2973       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2974       for (p = 0; p < 2; ++p) {
2975         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
2976       }
2977 #endif
2978       ++newp;
2979       /* Face C: {c, f, b} */
2980       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
2981       orntNew[0] = ornt[2] < 0 ? -2 : 0;
2982       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
2983       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2984       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 1);
2985       orntNew[2] = ornt[0] < 0 ? -2 : 0;
2986       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2987       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2988 #if 1
2989       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2990       for (p = 0; p < 3; ++p) {
2991         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
2992       }
2993 #endif
2994       supportNew[0] = (c - cStart)*8 + 2;
2995       supportNew[1] = (c - cStart)*8 + 2+4;
2996       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2997 #if 1
2998       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2999       for (p = 0; p < 2; ++p) {
3000         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
3001       }
3002 #endif
3003       ++newp;
3004       /* Face D: {d, e, f} */
3005       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 0);
3006       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3007       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3008       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3009       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3010       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3011       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3012       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3013 #if 1
3014       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3015       for (p = 0; p < 3; ++p) {
3016         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3017       }
3018 #endif
3019       supportNew[0] = (c - cStart)*8 + 3;
3020       supportNew[1] = (c - cStart)*8 + 3+4;
3021       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3022 #if 1
3023       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3024       for (p = 0; p < 2; ++p) {
3025         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
3026       }
3027 #endif
3028       ++newp;
3029       /* Face E: {d, f, a} */
3030       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3031       orntNew[0] = ornt[2] < 0 ? 0 : -2;
3032       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3033       orntNew[1] = -2;
3034       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3035       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3036       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3037       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3038 #if 1
3039       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3040       for (p = 0; p < 3; ++p) {
3041         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3042       }
3043 #endif
3044       supportNew[0] = (c - cStart)*8 + 0+4;
3045       supportNew[1] = (c - cStart)*8 + 3+4;
3046       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3047 #if 1
3048       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3049       for (p = 0; p < 2; ++p) {
3050         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
3051       }
3052 #endif
3053       ++newp;
3054       /* Face F: {c, a, f} */
3055       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3056       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3057       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3058       orntNew[1] = 0;
3059       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3060       orntNew[2] = ornt[2] < 0 ? 0 : -2;
3061       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3062       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3063 #if 1
3064       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3065       for (p = 0; p < 3; ++p) {
3066         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3067       }
3068 #endif
3069       supportNew[0] = (c - cStart)*8 + 0+4;
3070       supportNew[1] = (c - cStart)*8 + 2+4;
3071       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3072 #if 1
3073       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3074       for (p = 0; p < 2; ++p) {
3075         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
3076       }
3077 #endif
3078       ++newp;
3079       /* Face G: {e, a, f} */
3080       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3081       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3082       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3083       orntNew[1] = 0;
3084       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3085       orntNew[2] = ornt[3] < 0 ? 0 : -2;
3086       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3087       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3088 #if 1
3089       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3090       for (p = 0; p < 3; ++p) {
3091         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3092       }
3093 #endif
3094       supportNew[0] = (c - cStart)*8 + 1+4;
3095       supportNew[1] = (c - cStart)*8 + 3+4;
3096       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3097 #if 1
3098       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3099       for (p = 0; p < 2; ++p) {
3100         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
3101       }
3102 #endif
3103       ++newp;
3104       /* Face H: {a, b, f} */
3105       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3106       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3107       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3108       orntNew[1] = ornt[3] < 0 ? 0 : -2;
3109       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3110       orntNew[2] = -2;
3111       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3112       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3113 #if 1
3114       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3115       for (p = 0; p < 3; ++p) {
3116         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
3117       }
3118 #endif
3119       supportNew[0] = (c - cStart)*8 + 1+4;
3120       supportNew[1] = (c - cStart)*8 + 2+4;
3121       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3122 #if 1
3123       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
3124       for (p = 0; p < 2; ++p) {
3125         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
3126       }
3127 #endif
3128       ++newp;
3129     }
3130     /* Split Edges have 2 vertices and the same faces as the parent */
3131     for (e = eStart; e < eEnd; ++e) {
3132       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
3133 
3134       for (r = 0; r < 2; ++r) {
3135         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
3136         const PetscInt *cone, *ornt, *support;
3137         PetscInt        coneNew[2], coneSize, c, supportSize, s;
3138 
3139         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3140         coneNew[0]       = vStartNew + (cone[0] - vStart);
3141         coneNew[1]       = vStartNew + (cone[1] - vStart);
3142         coneNew[(r+1)%2] = newv;
3143         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3144 #if 1
3145         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3146         for (p = 0; p < 2; ++p) {
3147           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
3148         }
3149 #endif
3150         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
3151         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3152         for (s = 0; s < supportSize; ++s) {
3153           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3154           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3155           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3156           for (c = 0; c < coneSize; ++c) {
3157             if (cone[c] == e) break;
3158           }
3159           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
3160         }
3161         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3162 #if 1
3163         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3164         for (p = 0; p < supportSize; ++p) {
3165           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
3166         }
3167 #endif
3168       }
3169     }
3170     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
3171     for (f = fStart; f < fEnd; ++f) {
3172       const PetscInt *cone, *ornt, *support;
3173       PetscInt        coneSize, supportSize, s;
3174 
3175       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3176       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3177       for (r = 0; r < 3; ++r) {
3178         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
3179         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
3180         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
3181                                     -1, -1,  1,  6,  0,  4,
3182                                      2,  5,  3,  4, -1, -1,
3183                                     -1, -1,  3,  6,  2,  7};
3184 
3185         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3186         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
3187         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
3188         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3189 #if 1
3190         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3191         for (p = 0; p < 2; ++p) {
3192           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
3193         }
3194 #endif
3195         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
3196         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
3197         for (s = 0; s < supportSize; ++s) {
3198           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3199           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3200           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3201           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
3202           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
3203           er = GetTriMidEdgeInverse_Static(ornt[c], r);
3204           if (er == eint[c]) {
3205             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
3206           } else {
3207             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
3208             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
3209           }
3210         }
3211         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3212 #if 1
3213         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3214         for (p = 0; p < intFaces; ++p) {
3215           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
3216         }
3217 #endif
3218       }
3219     }
3220     /* Interior edges have 2 vertices and 4 faces */
3221     for (c = cStart; c < cEnd; ++c) {
3222       const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
3223       const PetscInt *cone, *ornt, *fcone;
3224       PetscInt        coneNew[2], supportNew[4], find;
3225 
3226       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3227       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3228       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
3229       find = GetTriEdge_Static(ornt[0], 0);
3230       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3231       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
3232       find = GetTriEdge_Static(ornt[2], 1);
3233       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3234       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3235 #if 1
3236       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3237       for (p = 0; p < 2; ++p) {
3238         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
3239       }
3240 #endif
3241       supportNew[0] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 4;
3242       supportNew[1] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 5;
3243       supportNew[2] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 6;
3244       supportNew[3] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 7;
3245       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3246 #if 1
3247       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
3248       for (p = 0; p < 4; ++p) {
3249         if ((supportNew[p] < fStartNew) || (supportNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportNew[p], fStartNew, fEndNew);
3250       }
3251 #endif
3252     }
3253     /* Old vertices have identical supports */
3254     for (v = vStart; v < vEnd; ++v) {
3255       const PetscInt  newp = vStartNew + (v - vStart);
3256       const PetscInt *support, *cone;
3257       PetscInt        size, s;
3258 
3259       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
3260       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
3261       for (s = 0; s < size; ++s) {
3262         PetscInt r = 0;
3263 
3264         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3265         if (cone[1] == v) r = 1;
3266         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
3267       }
3268       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3269 #if 1
3270       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3271       for (p = 0; p < size; ++p) {
3272         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
3273       }
3274 #endif
3275     }
3276     /* Edge vertices have 2 + face*2 + 0/1 supports */
3277     for (e = eStart; e < eEnd; ++e) {
3278       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
3279       const PetscInt *cone, *support;
3280       PetscInt       *star = NULL, starSize, cellSize = 0, coneSize, size, s;
3281 
3282       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
3283       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3284       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
3285       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
3286       for (s = 0; s < size; ++s) {
3287         PetscInt r = 0;
3288 
3289         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3290         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3291         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
3292         supportRef[2+s*2+0] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
3293         supportRef[2+s*2+1] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
3294       }
3295       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
3296       for (s = 0; s < starSize*2; s += 2) {
3297         const PetscInt *cone, *ornt;
3298         PetscInt        e01, e23;
3299 
3300         if ((star[s] >= cStart) && (star[s] < cEnd)) {
3301           /* Check edge 0-1 */
3302           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
3303           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
3304           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
3305           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
3306           /* Check edge 2-3 */
3307           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
3308           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
3309           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
3310           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
3311           if ((e01 == e) || (e23 == e)) {supportRef[2+size*2+cellSize++] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (star[s] - cStart);}
3312         }
3313       }
3314       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
3315       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3316 #if 1
3317       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3318       for (p = 0; p < 2+size*2+cellSize; ++p) {
3319         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
3320       }
3321 #endif
3322     }
3323     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3324     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
3325     break;
3326   case REFINER_HYBRID_SIMPLEX_3D:
3327     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
3328     /* Interior cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
3329     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
3330     for (c = cStart; c < cMax; ++c) {
3331       const PetscInt  newp = cStartNew + (c - cStart)*8;
3332       const PetscInt *cone, *ornt;
3333       PetscInt        coneNew[4], orntNew[4];
3334 
3335       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3336       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3337       /* A tetrahedron: {0, a, c, d} */
3338       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
3339       orntNew[0] = ornt[0];
3340       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
3341       orntNew[1] = ornt[1];
3342       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
3343       orntNew[2] = ornt[2];
3344       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
3345       orntNew[3] = 0;
3346       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3347       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3348 #if 1
3349       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cMaxNew);
3350       for (p = 0; p < 4; ++p) {
3351         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3352       }
3353 #endif
3354       /* B tetrahedron: {a, 1, b, e} */
3355       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
3356       orntNew[0] = ornt[0];
3357       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
3358       orntNew[1] = ornt[1];
3359       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
3360       orntNew[2] = 0;
3361       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
3362       orntNew[3] = ornt[3];
3363       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3364       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3365 #if 1
3366       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cMaxNew);
3367       for (p = 0; p < 4; ++p) {
3368         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3369       }
3370 #endif
3371       /* C tetrahedron: {c, b, 2, f} */
3372       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
3373       orntNew[0] = ornt[0];
3374       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
3375       orntNew[1] = 0;
3376       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
3377       orntNew[2] = ornt[2];
3378       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
3379       orntNew[3] = ornt[3];
3380       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3381       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3382 #if 1
3383       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cMaxNew);
3384       for (p = 0; p < 4; ++p) {
3385         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3386       }
3387 #endif
3388       /* D tetrahedron: {d, e, f, 3} */
3389       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
3390       orntNew[0] = 0;
3391       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
3392       orntNew[1] = ornt[1];
3393       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
3394       orntNew[2] = ornt[2];
3395       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
3396       orntNew[3] = ornt[3];
3397       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3398       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3399 #if 1
3400       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cMaxNew);
3401       for (p = 0; p < 4; ++p) {
3402         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3403       }
3404 #endif
3405       /* A' tetrahedron: {d, a, c, f} */
3406       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
3407       orntNew[0] = -3;
3408       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
3409       orntNew[1] = ornt[2] < 0 ? -(GetTriMidEdge_Static(ornt[2], 0)+1) : GetTriMidEdge_Static(ornt[2], 0);
3410       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
3411       orntNew[2] = 0;
3412       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
3413       orntNew[3] = 2;
3414       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
3415       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
3416 #if 1
3417       if ((newp+4 < cStartNew) || (newp+4 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+4, cStartNew, cMaxNew);
3418       for (p = 0; p < 4; ++p) {
3419         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3420       }
3421 #endif
3422       /* B' tetrahedron: {e, b, a, f} */
3423       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
3424       orntNew[0] = -3;
3425       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
3426       orntNew[1] = 1;
3427       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
3428       orntNew[2] = 0;
3429       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + 3;
3430       orntNew[3] = ornt[3] < 0 ? -(GetTriMidEdge_Static(ornt[3], 0)+1) : GetTriMidEdge_Static(ornt[3], 0);
3431       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
3432       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
3433 #if 1
3434       if ((newp+5 < cStartNew) || (newp+5 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+5, cStartNew, cMaxNew);
3435       for (p = 0; p < 4; ++p) {
3436         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3437       }
3438 #endif
3439       /* C' tetrahedron: {b, f, c, a} */
3440       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
3441       orntNew[0] = -3;
3442       coneNew[1] = fStartNew + (cone[0] - fStart)*4 + 3;
3443       orntNew[1] = ornt[0] < 0 ? -(GetTriMidEdge_Static(ornt[0], 2)+1) : GetTriMidEdge_Static(ornt[0], 2);
3444       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
3445       orntNew[2] = -3;
3446       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
3447       orntNew[3] = -2;
3448       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
3449       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
3450 #if 1
3451       if ((newp+6 < cStartNew) || (newp+6 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+6, cStartNew, cMaxNew);
3452       for (p = 0; p < 4; ++p) {
3453         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3454       }
3455 #endif
3456       /* D' tetrahedron: {f, e, d, a} */
3457       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
3458       orntNew[0] = -3;
3459       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
3460       orntNew[1] = -3;
3461       coneNew[2] = fStartNew + (cone[1] - fStart)*4 + 3;
3462       orntNew[2] = ornt[1] < 0 ? -(GetTriMidEdge_Static(ornt[1], 0)+1) : GetTriMidEdge_Static(ornt[1], 0);
3463       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
3464       orntNew[3] = -3;
3465       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
3466       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
3467 #if 1
3468       if ((newp+7 < cStartNew) || (newp+7 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+7, cStartNew, cMaxNew);
3469       for (p = 0; p < 4; ++p) {
3470         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3471       }
3472 #endif
3473     }
3474     /* Hybrid cells have 5 faces */
3475     for (c = cMax; c < cEnd; ++c) {
3476       const PetscInt  newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4;
3477       const PetscInt *cone, *ornt, *fornt;
3478       PetscInt        coneNew[5], orntNew[5], o, of, i;
3479 
3480       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3481       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3482       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
3483       o = ornt[0] < 0 ? -1 : 1;
3484       for (r = 0; r < 3; ++r) {
3485         coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], r);
3486         orntNew[0] = ornt[0];
3487         coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], r);
3488         orntNew[1] = ornt[1];
3489         of = fornt[GetTriEdge_Static(ornt[0], r)]       < 0 ? -1 : 1;
3490         i  = GetTriEdgeInverse_Static(ornt[0], r)       + 2;
3491         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], r)]       - fMax)*2 + (o*of < 0 ? 1 : 0);
3492         orntNew[i] = 0;
3493         i  = GetTriEdgeInverse_Static(ornt[0], (r+1)%3) + 2;
3494         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + GetTriSubface_Static(ornt[0], r);
3495         orntNew[i] = 0;
3496         of = fornt[GetTriEdge_Static(ornt[0], (r+2)%3)] < 0 ? -1 : 1;
3497         i  = GetTriEdgeInverse_Static(ornt[0], (r+2)%3) + 2;
3498         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], (r+2)%3)] - fMax)*2 + (o*of < 0 ? 0 : 1);
3499         orntNew[i] = 0;
3500         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
3501         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
3502 #if 1
3503         if ((newp+r < cMaxNew) || (newp+r >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", newp+r, cMaxNew, cEndNew);
3504         for (p = 0; p < 2; ++p) {
3505           if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3506         }
3507         for (p = 2; p < 5; ++p) {
3508           if ((coneNew[p] < fMaxNew)   || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", coneNew[p], fMaxNew, fEndNew);
3509         }
3510 #endif
3511       }
3512       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + 3;
3513       orntNew[0] = 0;
3514       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + 3;
3515       orntNew[1] = 0;
3516       coneNew[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
3517       orntNew[2] = 0;
3518       coneNew[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
3519       orntNew[3] = 0;
3520       coneNew[4] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
3521       orntNew[4] = 0;
3522       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3523       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3524 #if 1
3525       if ((newp+3 < cMaxNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", newp+3, cMaxNew, cEndNew);
3526       for (p = 0; p < 2; ++p) {
3527         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3528       }
3529       for (p = 2; p < 5; ++p) {
3530         if ((coneNew[p] < fMaxNew)   || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", coneNew[p], fMaxNew, fEndNew);
3531       }
3532 #endif
3533     }
3534     /* Split faces have 3 edges and the same cells as the parent */
3535     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3536     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
3537     for (f = fStart; f < fMax; ++f) {
3538       const PetscInt  newp = fStartNew + (f - fStart)*4;
3539       const PetscInt *cone, *ornt, *support;
3540       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
3541 
3542       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3543       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3544       /* A triangle */
3545       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
3546       orntNew[0] = ornt[0];
3547       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
3548       orntNew[1] = -2;
3549       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
3550       orntNew[2] = ornt[2];
3551       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3552       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3553 #if 1
3554       if ((newp+0 < fStartNew) || (newp+0 >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+0, fStartNew, fMaxNew);
3555       for (p = 0; p < 3; ++p) {
3556         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3557       }
3558 #endif
3559       /* B triangle */
3560       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
3561       orntNew[0] = ornt[0];
3562       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
3563       orntNew[1] = ornt[1];
3564       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
3565       orntNew[2] = -2;
3566       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3567       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3568 #if 1
3569       if ((newp+1 < fStartNew) || (newp+1 >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+1, fStartNew, fMaxNew);
3570       for (p = 0; p < 3; ++p) {
3571         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3572       }
3573 #endif
3574       /* C triangle */
3575       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
3576       orntNew[0] = -2;
3577       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
3578       orntNew[1] = ornt[1];
3579       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
3580       orntNew[2] = ornt[2];
3581       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3582       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3583 #if 1
3584       if ((newp+2 < fStartNew) || (newp+2 >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+2, fStartNew, fMaxNew);
3585       for (p = 0; p < 3; ++p) {
3586         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3587       }
3588 #endif
3589       /* D triangle */
3590       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
3591       orntNew[0] = 0;
3592       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
3593       orntNew[1] = 0;
3594       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
3595       orntNew[2] = 0;
3596       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3597       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3598 #if 1
3599       if ((newp+3 < fStartNew) || (newp+3 >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+3, fStartNew, fMaxNew);
3600       for (p = 0; p < 3; ++p) {
3601         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3602       }
3603 #endif
3604       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3605       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3606       for (r = 0; r < 4; ++r) {
3607         for (s = 0; s < supportSize; ++s) {
3608           PetscInt subf;
3609           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3610           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3611           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3612           for (c = 0; c < coneSize; ++c) {
3613             if (cone[c] == f) break;
3614           }
3615           subf = GetTriSubfaceInverse_Static(ornt[c], r);
3616           if (support[s] < cMax) {
3617             supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
3618           } else {
3619             supportRef[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (r==3 ? r : subf);
3620           }
3621         }
3622         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
3623 #if 1
3624         if ((newp+r < fStartNew) || (newp+r >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+r, fStartNew, fMaxNew);
3625         for (p = 0; p < supportSize; ++p) {
3626           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior or hybrid cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
3627         }
3628 #endif
3629       }
3630     }
3631     /* Interior cell faces have 3 edges and 2 cells */
3632     for (c = cStart; c < cMax; ++c) {
3633       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8;
3634       const PetscInt *cone, *ornt;
3635       PetscInt        coneNew[3], orntNew[3];
3636       PetscInt        supportNew[2];
3637 
3638       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3639       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3640       /* Face A: {c, a, d} */
3641       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3642       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3643       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3644       orntNew[1] = ornt[1] < 0 ? -2 : 0;
3645       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 2);
3646       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3647       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3648       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3649 #if 1
3650       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3651       for (p = 0; p < 3; ++p) {
3652         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3653       }
3654 #endif
3655       supportNew[0] = (c - cStart)*8 + 0;
3656       supportNew[1] = (c - cStart)*8 + 0+4;
3657       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3658 #if 1
3659       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3660       for (p = 0; p < 2; ++p) {
3661         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
3662       }
3663 #endif
3664       ++newp;
3665       /* Face B: {a, b, e} */
3666       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3667       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3668       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 0);
3669       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3670       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3671       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3672       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3673       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3674 #if 1
3675       if ((newp+1 < fStartNew) || (newp+1 >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+1, fStartNew, fMaxNew);
3676       for (p = 0; p < 3; ++p) {
3677         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3678       }
3679 #endif
3680       supportNew[0] = (c - cStart)*8 + 1;
3681       supportNew[1] = (c - cStart)*8 + 1+4;
3682       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3683 #if 1
3684       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3685       for (p = 0; p < 2; ++p) {
3686         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
3687       }
3688 #endif
3689       ++newp;
3690       /* Face C: {c, f, b} */
3691       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3692       orntNew[0] = ornt[2] < 0 ? -2 : 0;
3693       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3694       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3695       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 1);
3696       orntNew[2] = ornt[0] < 0 ? -2 : 0;
3697       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3698       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3699 #if 1
3700       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3701       for (p = 0; p < 3; ++p) {
3702         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3703       }
3704 #endif
3705       supportNew[0] = (c - cStart)*8 + 2;
3706       supportNew[1] = (c - cStart)*8 + 2+4;
3707       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3708 #if 1
3709       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3710       for (p = 0; p < 2; ++p) {
3711         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
3712       }
3713 #endif
3714       ++newp;
3715       /* Face D: {d, e, f} */
3716       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 0);
3717       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3718       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3719       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3720       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3721       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3722       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3723       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3724 #if 1
3725       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3726       for (p = 0; p < 3; ++p) {
3727         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3728       }
3729 #endif
3730       supportNew[0] = (c - cStart)*8 + 3;
3731       supportNew[1] = (c - cStart)*8 + 3+4;
3732       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3733 #if 1
3734       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3735       for (p = 0; p < 2; ++p) {
3736         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
3737       }
3738 #endif
3739       ++newp;
3740       /* Face E: {d, f, a} */
3741       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 1);
3742       orntNew[0] = ornt[2] < 0 ? 0 : -2;
3743       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3744       orntNew[1] = -2;
3745       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 2);
3746       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3747       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3748       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3749 #if 1
3750       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3751       for (p = 0; p < 3; ++p) {
3752         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3753       }
3754 #endif
3755       supportNew[0] = (c - cStart)*8 + 0+4;
3756       supportNew[1] = (c - cStart)*8 + 3+4;
3757       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3758 #if 1
3759       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3760       for (p = 0; p < 2; ++p) {
3761         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
3762       }
3763 #endif
3764       ++newp;
3765       /* Face F: {c, a, f} */
3766       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 2);
3767       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3768       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3769       orntNew[1] = 0;
3770       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTriMidEdge_Static(ornt[2], 0);
3771       orntNew[2] = ornt[2] < 0 ? 0 : -2;
3772       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3773       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3774 #if 1
3775       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3776       for (p = 0; p < 3; ++p) {
3777         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3778       }
3779 #endif
3780       supportNew[0] = (c - cStart)*8 + 0+4;
3781       supportNew[1] = (c - cStart)*8 + 2+4;
3782       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3783 #if 1
3784       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3785       for (p = 0; p < 2; ++p) {
3786         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
3787       }
3788 #endif
3789       ++newp;
3790       /* Face G: {e, a, f} */
3791       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTriMidEdge_Static(ornt[1], 1);
3792       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3793       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3794       orntNew[1] = 0;
3795       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 1);
3796       orntNew[2] = ornt[3] < 0 ? 0 : -2;
3797       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3798       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3799 #if 1
3800       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3801       for (p = 0; p < 3; ++p) {
3802         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3803       }
3804 #endif
3805       supportNew[0] = (c - cStart)*8 + 1+4;
3806       supportNew[1] = (c - cStart)*8 + 3+4;
3807       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3808 #if 1
3809       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3810       for (p = 0; p < 2; ++p) {
3811         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
3812       }
3813 #endif
3814       ++newp;
3815       /* Face H: {a, b, f} */
3816       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTriMidEdge_Static(ornt[0], 0);
3817       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3818       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTriMidEdge_Static(ornt[3], 2);
3819       orntNew[1] = ornt[3] < 0 ? 0 : -2;
3820       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3821       orntNew[2] = -2;
3822       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3823       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3824 #if 1
3825       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3826       for (p = 0; p < 3; ++p) {
3827         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3828       }
3829 #endif
3830       supportNew[0] = (c - cStart)*8 + 1+4;
3831       supportNew[1] = (c - cStart)*8 + 2+4;
3832       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3833 #if 1
3834       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3835       for (p = 0; p < 2; ++p) {
3836         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
3837       }
3838 #endif
3839       ++newp;
3840     }
3841     /* Hybrid split faces have 4 edges and same cells */
3842     for (f = fMax; f < fEnd; ++f) {
3843       const PetscInt *cone, *ornt, *support;
3844       PetscInt        coneNew[4], orntNew[4];
3845       PetscInt        supportNew[2], size, s, c;
3846 
3847       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3848       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3849       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3850       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3851       for (r = 0; r < 2; ++r) {
3852         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
3853 
3854         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
3855         orntNew[0]   = ornt[0];
3856         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
3857         orntNew[1]   = ornt[1];
3858         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (cone[2+r] - eMax);
3859         orntNew[2+r] = 0;
3860         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd      - eMax) + (f - fMax);
3861         orntNew[3-r] = 0;
3862         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3863         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3864 #if 1
3865         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
3866         for (p = 0; p < 2; ++p) {
3867           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3868         }
3869         for (p = 2; p < 4; ++p) {
3870           if ((coneNew[p] < eMaxNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", coneNew[p], eMaxNew, eEndNew);
3871         }
3872 #endif
3873         for (s = 0; s < size; ++s) {
3874           const PetscInt *coneCell, *orntCell, *fornt;
3875           PetscInt        o, of;
3876 
3877           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
3878           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
3879           o = orntCell[0] < 0 ? -1 : 1;
3880           for (c = 2; c < 5; ++c) if (coneCell[c] == f) break;
3881           if (c >= 5) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
3882           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
3883           of = fornt[c-2] < 0 ? -1 : 1;
3884           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetTriEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%3;
3885         }
3886         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3887 #if 1
3888         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
3889         for (p = 0; p < size; ++p) {
3890           if ((supportNew[p] < cMaxNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", supportNew[p], cMaxNew, cEndNew);
3891         }
3892 #endif
3893       }
3894     }
3895     /* Hybrid cell faces have 4 edges and 2 cells */
3896     for (c = cMax; c < cEnd; ++c) {
3897       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3;
3898       const PetscInt *cone, *ornt;
3899       PetscInt        coneNew[4], orntNew[4];
3900       PetscInt        supportNew[2];
3901 
3902       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3903       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3904       for (r = 0; r < 3; ++r) {
3905         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + (r+2)%3;
3906         orntNew[0] = 0;
3907         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + (r+2)%3;
3908         orntNew[1] = 0;
3909         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+(r+2)%3] - fMax);
3910         orntNew[2] = 0;
3911         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+r]       - fMax);
3912         orntNew[3] = 0;
3913         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
3914         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
3915 #if 1
3916         if ((newp+r < fMaxNew) || (newp+r >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp+r, fMaxNew, fEndNew);
3917         for (p = 0; p < 2; ++p) {
3918           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
3919         }
3920         for (p = 2; p < 4; ++p) {
3921           if ((coneNew[p] < eMaxNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", coneNew[p], eMaxNew, eEndNew);
3922         }
3923 #endif
3924         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetTriSubface_Static(ornt[0], r);
3925         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + 3;
3926         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
3927 #if 1
3928         if ((newp+r < fMaxNew) || (newp+r >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp+r, fMaxNew, fEndNew);
3929         for (p = 0; p < 2; ++p) {
3930           if ((supportNew[p] < cMaxNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", supportNew[p], cMaxNew, cEndNew);
3931         }
3932 #endif
3933       }
3934     }
3935     /* Interior split edges have 2 vertices and the same faces as the parent */
3936     for (e = eStart; e < eMax; ++e) {
3937       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
3938 
3939       for (r = 0; r < 2; ++r) {
3940         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
3941         const PetscInt *cone, *ornt, *support;
3942         PetscInt        coneNew[2], coneSize, c, supportSize, s;
3943 
3944         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3945         coneNew[0]       = vStartNew + (cone[0] - vStart);
3946         coneNew[1]       = vStartNew + (cone[1] - vStart);
3947         coneNew[(r+1)%2] = newv;
3948         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3949 #if 1
3950         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3951         for (p = 0; p < 2; ++p) {
3952           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
3953         }
3954 #endif
3955         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
3956         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3957         for (s = 0; s < supportSize; ++s) {
3958           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3959           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3960           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3961           for (c = 0; c < coneSize; ++c) if (cone[c] == e) break;
3962           if (support[s] < fMax) {
3963             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
3964           } else {
3965             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
3966           }
3967         }
3968         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3969 #if 1
3970         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3971         for (p = 0; p < supportSize; ++p) {
3972           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior or hybrid face [%d, %d)", supportRef[p], fStartNew, fEndNew);
3973         }
3974 #endif
3975       }
3976     }
3977     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
3978     for (f = fStart; f < fMax; ++f) {
3979       const PetscInt *cone, *ornt, *support;
3980       PetscInt        coneSize, supportSize, s;
3981 
3982       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3983       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3984       for (r = 0; r < 3; ++r) {
3985         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
3986         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
3987         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
3988                                     -1, -1,  1,  6,  0,  4,
3989                                      2,  5,  3,  4, -1, -1,
3990                                     -1, -1,  3,  6,  2,  7};
3991 
3992         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3993         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
3994         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
3995         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3996 #if 1
3997         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3998         for (p = 0; p < 2; ++p) {
3999           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4000         }
4001 #endif
4002         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
4003         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
4004         for (s = 0; s < supportSize; ++s) {
4005           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4006           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4007           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4008           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
4009           if (support[s] < cMax) {
4010             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
4011             er = GetTriMidEdgeInverse_Static(ornt[c], r);
4012             if (er == eint[c]) {
4013               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
4014             } else {
4015               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
4016               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
4017             }
4018           } else {
4019             supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (r + 1)%3;
4020           }
4021         }
4022         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4023 #if 1
4024         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4025         for (p = 0; p < intFaces; ++p) {
4026           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior or hybrid face [%d, %d)", supportRef[p], fStartNew, fEndNew);
4027         }
4028 #endif
4029       }
4030     }
4031     /* Interior cell edges have 2 vertices and 4 faces */
4032     for (c = cStart; c < cMax; ++c) {
4033       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
4034       const PetscInt *cone, *ornt, *fcone;
4035       PetscInt        coneNew[2], supportNew[4], find;
4036 
4037       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4038       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4039       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
4040       find = GetTriEdge_Static(ornt[0], 0);
4041       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4042       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
4043       find = GetTriEdge_Static(ornt[2], 1);
4044       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
4045       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4046 #if 1
4047       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4048       for (p = 0; p < 2; ++p) {
4049         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4050       }
4051 #endif
4052       supportNew[0] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 4;
4053       supportNew[1] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 5;
4054       supportNew[2] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 6;
4055       supportNew[3] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 7;
4056       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4057 #if 1
4058       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
4059       for (p = 0; p < 4; ++p) {
4060         if ((supportNew[p] < fStartNew) || (supportNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportNew[p], fStartNew, fMaxNew);
4061       }
4062 #endif
4063     }
4064     /* Hybrid edges have two vertices and the same faces */
4065     for (e = eMax; e < eEnd; ++e) {
4066       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
4067       const PetscInt *cone, *support, *fcone;
4068       PetscInt        coneNew[2], size, fsize, s;
4069 
4070       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4071       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4072       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4073       coneNew[0] = vStartNew + (cone[0] - vStart);
4074       coneNew[1] = vStartNew + (cone[1] - vStart);
4075       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4076 #if 1
4077       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4078       for (p = 0; p < 2; ++p) {
4079         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4080       }
4081 #endif
4082       for (s = 0; s < size; ++s) {
4083         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
4084         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
4085         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
4086         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
4087         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + c-2;
4088       }
4089       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4090 #if 1
4091       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4092       for (p = 0; p < size; ++p) {
4093         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", supportRef[p], fMaxNew, fEndNew);
4094       }
4095 #endif
4096     }
4097     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
4098     for (f = fMax; f < fEnd; ++f) {
4099       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
4100       const PetscInt *cone, *support, *ccone, *cornt;
4101       PetscInt        coneNew[2], size, csize, s;
4102 
4103       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4104       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4105       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4106       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
4107       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
4108       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4109 #if 1
4110       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4111       for (p = 0; p < 2; ++p) {
4112         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4113       }
4114 #endif
4115       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 0;
4116       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 1;
4117       for (s = 0; s < size; ++s) {
4118         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
4119         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
4120         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
4121         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
4122         if ((c < 2) || (c >= csize)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Hybrid face %d is not in cone of hybrid cell %d", f, support[s]);
4123         supportRef[2+s*2+0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + c-2;
4124         supportRef[2+s*2+1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (c-1)%3;
4125       }
4126       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4127 #if 1
4128       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
4129       for (p = 0; p < 2+size*2; ++p) {
4130         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", supportRef[p], fMaxNew, fEndNew);
4131       }
4132 #endif
4133     }
4134     /* Interior vertices have identical supports */
4135     for (v = vStart; v < vEnd; ++v) {
4136       const PetscInt  newp = vStartNew + (v - vStart);
4137       const PetscInt *support, *cone;
4138       PetscInt        size, s;
4139 
4140       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4141       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4142       for (s = 0; s < size; ++s) {
4143         PetscInt r = 0;
4144 
4145         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4146         if (cone[1] == v) r = 1;
4147         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4148         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (support[s] - eMax);
4149       }
4150       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4151 #if 1
4152       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4153       for (p = 0; p < size; ++p) {
4154         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior or hybrid edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
4155       }
4156 #endif
4157     }
4158     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
4159     for (e = eStart; e < eMax; ++e) {
4160       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4161       const PetscInt *cone, *support;
4162       PetscInt       *star = NULL, starSize, faceSize = 0, cellSize = 0, coneSize, size, s;
4163 
4164       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4165       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4166       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4167       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4168       for (s = 0; s < size; ++s) {
4169         PetscInt r = 0;
4170 
4171         if (support[s] < fMax) {
4172           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4173           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4174           for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
4175           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
4176           supportRef[2+faceSize+1] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
4177           faceSize += 2;
4178         } else {
4179           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (support[s] - fMax);
4180           ++faceSize;
4181         }
4182       }
4183       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4184       for (s = 0; s < starSize*2; s += 2) {
4185         const PetscInt *cone, *ornt;
4186         PetscInt        e01, e23;
4187 
4188         if ((star[s] >= cStart) && (star[s] < cMax)) {
4189           /* Check edge 0-1 */
4190           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
4191           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
4192           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
4193           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
4194           /* Check edge 2-3 */
4195           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
4196           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
4197           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
4198           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
4199           if ((e01 == e) || (e23 == e)) {supportRef[2+faceSize+cellSize++] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (star[s] - cStart);}
4200         }
4201       }
4202       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4203       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4204 #if 1
4205       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4206       for (p = 0; p < 2+faceSize+cellSize; ++p) {
4207         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an interior or hybrid edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
4208       }
4209 #endif
4210     }
4211     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4212     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
4213     break;
4214   case REFINER_SIMPLEX_TO_HEX_3D:
4215     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
4216     /* All cells have 6 faces */
4217     for (c = cStart; c < cEnd; ++c) {
4218       const PetscInt  newp = cStartNew + (c - cStart)*4;
4219       const PetscInt *cone, *ornt;
4220       PetscInt        coneNew[6];
4221       PetscInt        orntNew[6];
4222 
4223       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4224       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4225       /* A hex */
4226       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 0); /* B */
4227       orntNew[0] = ornt[0] < 0 ? -1 : 1;
4228       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 3;               /* T */
4229       orntNew[1] = -4;
4230       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 0); /* F */
4231       orntNew[2] = ornt[2] < 0 ? -1 : 1;
4232       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 0;               /* K */
4233       orntNew[3] = -1;
4234       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 2;               /* R */
4235       orntNew[4] = 0;
4236       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 0); /* L */
4237       orntNew[5] = ornt[1] < 0 ? -1 : 1;
4238       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4239       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4240 #if 1
4241       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
4242       for (p = 0; p < 6; ++p) {
4243         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4244       }
4245 #endif
4246       /* B hex */
4247       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 1); /* B */
4248       orntNew[0] = ornt[0] < 0 ? -2 : 0;
4249       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 4;               /* T */
4250       orntNew[1] = 0;
4251       coneNew[2] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 0;               /* F */
4252       orntNew[2] = 0;
4253       coneNew[3] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 1); /* K */
4254       orntNew[3] = ornt[3] < 0 ? -2 : 0;
4255       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 1;               /* R */
4256       orntNew[4] = 0;
4257       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 2); /* L */
4258       orntNew[5] = ornt[1] < 0 ? -4 : 2;
4259       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4260       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4261 #if 1
4262       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
4263       for (p = 0; p < 6; ++p) {
4264         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4265       }
4266 #endif
4267       /* C hex */
4268       coneNew[0] = fStartNew + (cone[0] - fStart)*3 + GetTriSubface_Static(ornt[0], 2); /* B */
4269       orntNew[0] = ornt[0] < 0 ? -4 : 2;
4270       coneNew[1] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 5;               /* T */
4271       orntNew[1] = -4;
4272       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 1); /* F */
4273       orntNew[2] = ornt[2] < 0 ? -2 : 0;
4274       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 1;               /* K */
4275       orntNew[3] = -1;
4276       coneNew[4] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 0); /* R */
4277       orntNew[4] = ornt[3] < 0 ? -1 : 1;
4278       coneNew[5] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 2;               /* L */
4279       orntNew[5] = -4;
4280       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4281       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4282 #if 1
4283       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
4284       for (p = 0; p < 6; ++p) {
4285         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4286       }
4287 #endif
4288       /* D hex */
4289       coneNew[0] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 3;               /* B */
4290       orntNew[0] = 0;
4291       coneNew[1] = fStartNew + (cone[3] - fStart)*3 + GetTriSubface_Static(ornt[3], 2); /* T */
4292       orntNew[1] = ornt[3] < 0 ? -1 : 1;
4293       coneNew[2] = fStartNew + (cone[2] - fStart)*3 + GetTriSubface_Static(ornt[2], 2); /* F */
4294       orntNew[2] = ornt[2] < 0 ? -4 : 2;
4295       coneNew[3] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 4;               /* K */
4296       orntNew[3] = -1;
4297       coneNew[4] = fStartNew + (fEnd    - fStart)*3 + (c - cStart)*6 + 5;               /* R */
4298       orntNew[4] = 0;
4299       coneNew[5] = fStartNew + (cone[1] - fStart)*3 + GetTriSubface_Static(ornt[1], 1); /* L */
4300       orntNew[5] = ornt[1] < 0 ? -2 : 0;
4301       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4302       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4303 #if 1
4304       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
4305       for (p = 0; p < 6; ++p) {
4306         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4307       }
4308 #endif
4309     }
4310     /* Split faces have 4 edges and the same cells as the parent */
4311     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4312     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
4313     for (f = fStart; f < fEnd; ++f) {
4314       const PetscInt  newp = fStartNew + (f - fStart)*3;
4315       const PetscInt *cone, *ornt, *support;
4316       PetscInt        coneNew[4], orntNew[4], coneSize, supportSize, s;
4317 
4318       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4319       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4320       /* A quad */
4321       coneNew[0] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
4322       orntNew[0] = ornt[2];
4323       coneNew[1] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
4324       orntNew[1] = ornt[0];
4325       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
4326       orntNew[2] = 0;
4327       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
4328       orntNew[3] = -2;
4329       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4330       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4331 #if 1
4332       if ((newp+0 < fStartNew) || (newp+0 >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+0, fStartNew, fEndNew);
4333       for (p = 0; p < 4; ++p) {
4334         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
4335       }
4336 #endif
4337       /* B quad */
4338       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
4339       orntNew[0] = ornt[0];
4340       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
4341       orntNew[1] = ornt[1];
4342       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
4343       orntNew[2] = 0;
4344       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
4345       orntNew[3] = -2;
4346       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4347       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4348 #if 1
4349       if ((newp+1 < fStartNew) || (newp+1 >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+1, fStartNew, fEndNew);
4350       for (p = 0; p < 4; ++p) {
4351         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
4352       }
4353 #endif
4354       /* C quad */
4355       coneNew[0] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
4356       orntNew[0] = ornt[1];
4357       coneNew[1] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
4358       orntNew[1] = ornt[2];
4359       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
4360       orntNew[2] = 0;
4361       coneNew[3] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
4362       orntNew[3] = -2;
4363       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4364       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4365 #if 1
4366       if ((newp+2 < fStartNew) || (newp+2 >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+2, fStartNew, fEndNew);
4367       for (p = 0; p < 4; ++p) {
4368         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
4369       }
4370 #endif
4371       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4372       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4373       for (r = 0; r < 3; ++r) {
4374         for (s = 0; s < supportSize; ++s) {
4375           PetscInt subf;
4376           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4377           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4378           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4379           for (c = 0; c < coneSize; ++c) {
4380             if (cone[c] == f) break;
4381           }
4382           subf = GetTriSubfaceInverse_Static(ornt[c], r);
4383           supportRef[s] = cStartNew + (support[s] - cStart)*4 + faces[c*3+subf];
4384         }
4385         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
4386 #if 1
4387         if ((newp+r < fStartNew) || (newp+r >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp+r, fStartNew, fEndNew);
4388         for (p = 0; p < supportSize; ++p) {
4389           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
4390         }
4391 #endif
4392       }
4393     }
4394     /* Interior faces have 4 edges and 2 cells */
4395     for (c = cStart; c < cEnd; ++c) {
4396       PetscInt        newp = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6;
4397       const PetscInt *cone, *ornt;
4398       PetscInt        coneNew[4], orntNew[4];
4399       PetscInt        supportNew[2];
4400 
4401       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4402       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4403       /* Face {a, g, m, h} */
4404       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],0);
4405       orntNew[0] = 0;
4406       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
4407       orntNew[1] = 0;
4408       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
4409       orntNew[2] = -2;
4410       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],2);
4411       orntNew[3] = -2;
4412       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4413       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4414 #if 1
4415       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4416       for (p = 0; p < 4; ++p) {
4417         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
4418       }
4419 #endif
4420       supportNew[0] = (c - cStart)*4 + 0;
4421       supportNew[1] = (c - cStart)*4 + 1;
4422       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4423 #if 1
4424       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4425       for (p = 0; p < 2; ++p) {
4426         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
4427       }
4428 #endif
4429       ++newp;
4430       /* Face {g, b, l , m} */
4431       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],1);
4432       orntNew[0] = -2;
4433       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],0);
4434       orntNew[1] = 0;
4435       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
4436       orntNew[2] = 0;
4437       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
4438       orntNew[3] = -2;
4439       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4440       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4441 #if 1
4442       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4443       for (p = 0; p < 4; ++p) {
4444         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
4445       }
4446 #endif
4447       supportNew[0] = (c - cStart)*4 + 1;
4448       supportNew[1] = (c - cStart)*4 + 2;
4449       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4450 #if 1
4451       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4452       for (p = 0; p < 2; ++p) {
4453         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
4454       }
4455 #endif
4456       ++newp;
4457       /* Face {c, g, m, i} */
4458       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTriInteriorEdge_Static(ornt[0],2);
4459       orntNew[0] = 0;
4460       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
4461       orntNew[1] = 0;
4462       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
4463       orntNew[2] = -2;
4464       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],0);
4465       orntNew[3] = -2;
4466       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4467       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4468 #if 1
4469       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4470       for (p = 0; p < 4; ++p) {
4471         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
4472       }
4473 #endif
4474       supportNew[0] = (c - cStart)*4 + 0;
4475       supportNew[1] = (c - cStart)*4 + 2;
4476       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4477 #if 1
4478       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4479       for (p = 0; p < 2; ++p) {
4480         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
4481       }
4482 #endif
4483       ++newp;
4484       /* Face {d, h, m, i} */
4485       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],0);
4486       orntNew[0] = 0;
4487       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
4488       orntNew[1] = 0;
4489       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
4490       orntNew[2] = -2;
4491       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],2);
4492       orntNew[3] = -2;
4493       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4494       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4495 #if 1
4496       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4497       for (p = 0; p < 4; ++p) {
4498         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
4499       }
4500 #endif
4501       supportNew[0] = (c - cStart)*4 + 0;
4502       supportNew[1] = (c - cStart)*4 + 3;
4503       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4504 #if 1
4505       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4506       for (p = 0; p < 2; ++p) {
4507         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
4508       }
4509 #endif
4510       ++newp;
4511       /* Face {h, m, l, e} */
4512       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
4513       orntNew[0] = 0;
4514       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
4515       orntNew[1] = -2;
4516       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],1);
4517       orntNew[2] = -2;
4518       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTriInteriorEdge_Static(ornt[1],1);
4519       orntNew[3] = 0;
4520       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4521       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4522 #if 1
4523       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4524       for (p = 0; p < 4; ++p) {
4525         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
4526       }
4527 #endif
4528       supportNew[0] = (c - cStart)*4 + 1;
4529       supportNew[1] = (c - cStart)*4 + 3;
4530       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4531 #if 1
4532       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4533       for (p = 0; p < 2; ++p) {
4534         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
4535       }
4536 #endif
4537       ++newp;
4538       /* Face {i, m, l, f} */
4539       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
4540       orntNew[0] = 0;
4541       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
4542       orntNew[1] = -2;
4543       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTriInteriorEdge_Static(ornt[3],2);
4544       orntNew[2] = -2;
4545       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTriInteriorEdge_Static(ornt[2],1);
4546       orntNew[3] = 0;
4547       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4548       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4549 #if 1
4550       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4551       for (p = 0; p < 4; ++p) {
4552         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
4553       }
4554 #endif
4555       supportNew[0] = (c - cStart)*4 + 2;
4556       supportNew[1] = (c - cStart)*4 + 3;
4557       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4558 #if 1
4559       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4560       for (p = 0; p < 2; ++p) {
4561         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
4562       }
4563 #endif
4564       ++newp;
4565     }
4566     /* Split Edges have 2 vertices and the same faces as the parent */
4567     for (e = eStart; e < eEnd; ++e) {
4568       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
4569 
4570       for (r = 0; r < 2; ++r) {
4571         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
4572         const PetscInt *cone, *ornt, *support;
4573         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4574 
4575         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4576         coneNew[0]       = vStartNew + (cone[0] - vStart);
4577         coneNew[1]       = vStartNew + (cone[1] - vStart);
4578         coneNew[(r+1)%2] = newv;
4579         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4580 #if 1
4581         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4582         for (p = 0; p < 2; ++p) {
4583           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4584         }
4585 #endif
4586         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
4587         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4588         for (s = 0; s < supportSize; ++s) {
4589           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4590           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4591           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4592           for (c = 0; c < coneSize; ++c) {
4593             if (cone[c] == e) break;
4594           }
4595           supportRef[s] = fStartNew + (support[s] - fStart)*3 + (c + (ornt[c] < 0 ? 1-r : r))%3;
4596         }
4597         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4598 #if 1
4599         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4600         for (p = 0; p < supportSize; ++p) {
4601           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
4602         }
4603 #endif
4604       }
4605     }
4606     /* Face edges have 2 vertices and 2 + cell faces supports */
4607     for (f = fStart; f < fEnd; ++f) {
4608       const PetscInt *cone, *ornt, *support;
4609       PetscInt        coneSize, supportSize, s;
4610 
4611       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4612       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4613       for (r = 0; r < 3; ++r) {
4614         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
4615         PetscInt        coneNew[2];
4616         PetscInt        fint[4][3] = { {0, 1, 2},
4617                                        {3, 4, 0},
4618                                        {2, 5, 3},
4619                                        {1, 4, 5} };
4620 
4621         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4622         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
4623         coneNew[1] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + f - fStart;
4624         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4625 #if 1
4626         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4627         for (p = 0; p < 2; ++p) {
4628           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4629         }
4630 #endif
4631         supportRef[0] = fStartNew + (f - fStart)*3 + (r+0)%3;
4632         supportRef[1] = fStartNew + (f - fStart)*3 + (r+1)%3;
4633         for (s = 0; s < supportSize; ++s) {
4634           PetscInt er;
4635           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4636           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4637           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4638           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
4639           er = GetTriInteriorEdgeInverse_Static(ornt[c], r);
4640           supportRef[2+s] = fStartNew + (fEnd - fStart)*3 + (support[s] - cStart)*6 + fint[c][er];
4641         }
4642         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4643 #if 1
4644         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4645         for (p = 0; p < supportSize + 2; ++p) {
4646           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
4647         }
4648 #endif
4649       }
4650     }
4651     /* Interior cell edges have 2 vertices and 3 faces */
4652     for (c = cStart; c < cEnd; ++c) {
4653       const PetscInt *cone;
4654       PetscInt       fint[4][3] = { {0,1,2},
4655                                     {0,3,4},
4656                                     {2,3,5},
4657                                     {1,4,5} } ;
4658 
4659       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4660       for (r = 0; r < 4; r++) {
4661         PetscInt       coneNew[2], supportNew[3];
4662         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + r;
4663 
4664         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
4665         coneNew[1] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd -fStart) + c - cStart;
4666         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4667 #if 1
4668         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4669         for (p = 0; p < 2; ++p) {
4670           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4671         }
4672 #endif
4673         supportNew[0] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][0];
4674         supportNew[1] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][1];
4675         supportNew[2] = fStartNew + (fEnd - fStart)*3 + (c - cStart)*6 + fint[r][2];
4676         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4677 #if 1
4678         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4679         for (p = 0; p < 3; ++p) {
4680           if ((supportNew[p] < fStartNew) || (supportNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportNew[p], fStartNew, fEndNew);
4681         }
4682 #endif
4683       }
4684     }
4685     /* Old vertices have identical supports */
4686     for (v = vStart; v < vEnd; ++v) {
4687       const PetscInt  newp = vStartNew + (v - vStart);
4688       const PetscInt *support, *cone;
4689       PetscInt        size, s;
4690 
4691       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4692       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4693       for (s = 0; s < size; ++s) {
4694         PetscInt r = 0;
4695 
4696         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4697         if (cone[1] == v) r = 1;
4698         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4699       }
4700       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4701 #if 1
4702       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4703       for (p = 0; p < size; ++p) {
4704         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
4705       }
4706 #endif
4707     }
4708     /* Edge vertices have 2 + faces supports */
4709     for (e = eStart; e < eEnd; ++e) {
4710       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4711       const PetscInt *cone, *support;
4712       PetscInt        size, s;
4713 
4714       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4715       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4716       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4717       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4718       for (s = 0; s < size; ++s) {
4719         PetscInt r = 0, coneSize;
4720 
4721         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4722         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4723         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
4724         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + r;
4725       }
4726       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4727 #if 1
4728       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4729       for (p = 0; p < 2+size; ++p) {
4730         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
4731       }
4732 #endif
4733     }
4734     /* Face vertices have 3 + cells supports */
4735     for (f = fStart; f < fEnd; ++f) {
4736       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
4737       const PetscInt *cone, *support;
4738       PetscInt        size, s;
4739 
4740       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4741       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4742       supportRef[0] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 0;
4743       supportRef[1] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 1;
4744       supportRef[2] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + 2;
4745       for (s = 0; s < size; ++s) {
4746         PetscInt r = 0, coneSize;
4747 
4748         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4749         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4750         for (r = 0; r < coneSize; ++r) {if (cone[r] == f) break;}
4751         supportRef[3+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (support[s] - cStart)*4 + r;
4752       }
4753       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4754 #if 1
4755       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4756       for (p = 0; p < 3+size; ++p) {
4757         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
4758       }
4759 #endif
4760     }
4761     /* Interior cell vertices have 4 supports */
4762     for (c = cStart; c < cEnd; ++c) {
4763       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + c - cStart;
4764       supportRef[0] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 0;
4765       supportRef[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 1;
4766       supportRef[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 2;
4767       supportRef[3] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart)*4 + 3;
4768       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4769 #if 1
4770       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4771       for (p = 0; p < 4; ++p) {
4772         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
4773       }
4774 #endif
4775     }
4776     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4777     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
4778     break;
4779   case REFINER_HEX_3D:
4780     /*
4781      Bottom (viewed from top)    Top
4782      1---------2---------2       7---------2---------6
4783      |         |         |       |         |         |
4784      |    B    2    C    |       |    H    2    G    |
4785      |         |         |       |         |         |
4786      3----3----0----1----1       3----3----0----1----1
4787      |         |         |       |         |         |
4788      |    A    0    D    |       |    E    0    F    |
4789      |         |         |       |         |         |
4790      0---------0---------3       4---------0---------5
4791      */
4792     /* All cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
4793     for (c = cStart; c < cEnd; ++c) {
4794       const PetscInt  newp = (c - cStart)*8;
4795       const PetscInt *cone, *ornt;
4796       PetscInt        coneNew[6], orntNew[6];
4797 
4798       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4799       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4800       /* A hex */
4801       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
4802       orntNew[0] = ornt[0];
4803       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
4804       orntNew[1] = 0;
4805       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
4806       orntNew[2] = ornt[2];
4807       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
4808       orntNew[3] = 0;
4809       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
4810       orntNew[4] = 0;
4811       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
4812       orntNew[5] = ornt[5];
4813       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4814       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4815 #if 1
4816       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
4817       for (p = 0; p < 6; ++p) {
4818         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4819       }
4820 #endif
4821       /* B hex */
4822       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
4823       orntNew[0] = ornt[0];
4824       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
4825       orntNew[1] = 0;
4826       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
4827       orntNew[2] = -1;
4828       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
4829       orntNew[3] = ornt[3];
4830       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
4831       orntNew[4] = 0;
4832       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
4833       orntNew[5] = ornt[5];
4834       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4835       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4836 #if 1
4837       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
4838       for (p = 0; p < 6; ++p) {
4839         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4840       }
4841 #endif
4842       /* C hex */
4843       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
4844       orntNew[0] = ornt[0];
4845       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
4846       orntNew[1] = 0;
4847       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
4848       orntNew[2] = -1;
4849       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
4850       orntNew[3] = ornt[3];
4851       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
4852       orntNew[4] = ornt[4];
4853       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
4854       orntNew[5] = -4;
4855       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4856       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4857 #if 1
4858       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
4859       for (p = 0; p < 6; ++p) {
4860         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4861       }
4862 #endif
4863       /* D hex */
4864       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
4865       orntNew[0] = ornt[0];
4866       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
4867       orntNew[1] = 0;
4868       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
4869       orntNew[2] = ornt[2];
4870       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
4871       orntNew[3] = 0;
4872       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
4873       orntNew[4] = ornt[4];
4874       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
4875       orntNew[5] = -4;
4876       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4877       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4878 #if 1
4879       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
4880       for (p = 0; p < 6; ++p) {
4881         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4882       }
4883 #endif
4884       /* E hex */
4885       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
4886       orntNew[0] = -4;
4887       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
4888       orntNew[1] = ornt[1];
4889       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
4890       orntNew[2] = ornt[2];
4891       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
4892       orntNew[3] = 0;
4893       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
4894       orntNew[4] = -1;
4895       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
4896       orntNew[5] = ornt[5];
4897       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
4898       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
4899 #if 1
4900       if ((newp+4 < cStartNew) || (newp+4 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+4, cStartNew, cEndNew);
4901       for (p = 0; p < 6; ++p) {
4902         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4903       }
4904 #endif
4905       /* F hex */
4906       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
4907       orntNew[0] = -4;
4908       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
4909       orntNew[1] = ornt[1];
4910       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
4911       orntNew[2] = ornt[2];
4912       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4913       orntNew[3] = -1;
4914       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
4915       orntNew[4] = ornt[4];
4916       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
4917       orntNew[5] = 1;
4918       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
4919       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
4920 #if 1
4921       if ((newp+5 < cStartNew) || (newp+5 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+5, cStartNew, cEndNew);
4922       for (p = 0; p < 6; ++p) {
4923         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4924       }
4925 #endif
4926       /* G hex */
4927       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
4928       orntNew[0] = -4;
4929       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
4930       orntNew[1] = ornt[1];
4931       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4932       orntNew[2] = 0;
4933       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
4934       orntNew[3] = ornt[3];
4935       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
4936       orntNew[4] = ornt[4];
4937       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
4938       orntNew[5] = -3;
4939       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
4940       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
4941 #if 1
4942       if ((newp+6 < cStartNew) || (newp+6 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+6, cStartNew, cEndNew);
4943       for (p = 0; p < 6; ++p) {
4944         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4945       }
4946 #endif
4947       /* H hex */
4948       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
4949       orntNew[0] = -4;
4950       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
4951       orntNew[1] = ornt[1];
4952       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
4953       orntNew[2] = -1;
4954       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
4955       orntNew[3] = ornt[3];
4956       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
4957       orntNew[4] = 3;
4958       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
4959       orntNew[5] = ornt[5];
4960       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
4961       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
4962 #if 1
4963       if ((newp+7 < cStartNew) || (newp+7 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+7, cStartNew, cEndNew);
4964       for (p = 0; p < 6; ++p) {
4965         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4966       }
4967 #endif
4968     }
4969     /* Split faces have 4 edges and the same cells as the parent */
4970     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4971     ierr = PetscMalloc1(4 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
4972     for (f = fStart; f < fEnd; ++f) {
4973       for (r = 0; r < 4; ++r) {
4974         /* TODO: This can come from GetFaces_Internal() */
4975         const PetscInt  newCells[24] = {0, 1, 2, 3,  4, 5, 6, 7,  0, 3, 5, 4,  2, 1, 7, 6,  3, 2, 6, 5,  0, 4, 7, 1};
4976         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
4977         const PetscInt *cone, *ornt, *support;
4978         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
4979 
4980         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4981         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4982         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
4983         orntNew[(r+3)%4] = ornt[(r+3)%4];
4984         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
4985         orntNew[(r+0)%4] = ornt[r];
4986         coneNew[(r+1)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
4987         orntNew[(r+1)%4] = 0;
4988         coneNew[(r+2)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + (r+3)%4;
4989         orntNew[(r+2)%4] = -2;
4990         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4991         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4992 #if 1
4993         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4994         for (p = 0; p < 4; ++p) {
4995           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
4996         }
4997 #endif
4998         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4999         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5000         for (s = 0; s < supportSize; ++s) {
5001           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5002           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5003           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5004           for (c = 0; c < coneSize; ++c) {
5005             if (cone[c] == f) break;
5006           }
5007           supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+GetQuadSubfaceInverse_Static(ornt[c], r)];
5008         }
5009         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5010 #if 1
5011         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5012         for (p = 0; p < supportSize; ++p) {
5013           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
5014         }
5015 #endif
5016       }
5017     }
5018     /* Interior faces have 4 edges and 2 cells */
5019     for (c = cStart; c < cEnd; ++c) {
5020       const PetscInt  newCells[24] = {0, 3,  2, 3,  1, 2,  0, 1,  4, 5,  5, 6,  6, 7,  4, 7,  0, 4,  3, 5,  2, 6,  1, 7};
5021       const PetscInt *cone, *ornt;
5022       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
5023 
5024       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5025       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5026       /* A-D face */
5027       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 0;
5028       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
5029       orntNew[0] = 0;
5030       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
5031       orntNew[1] = 0;
5032       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
5033       orntNew[2] = -2;
5034       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
5035       orntNew[3] = -2;
5036       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5037       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5038 #if 1
5039       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5040       for (p = 0; p < 4; ++p) {
5041         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5042       }
5043 #endif
5044       /* C-D face */
5045       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 1;
5046       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
5047       orntNew[0] = 0;
5048       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
5049       orntNew[1] = 0;
5050       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
5051       orntNew[2] = -2;
5052       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
5053       orntNew[3] = -2;
5054       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5055       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5056 #if 1
5057       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5058       for (p = 0; p < 4; ++p) {
5059         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5060       }
5061 #endif
5062       /* B-C face */
5063       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 2;
5064       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
5065       orntNew[0] = -2;
5066       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
5067       orntNew[1] = 0;
5068       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
5069       orntNew[2] = 0;
5070       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
5071       orntNew[3] = -2;
5072       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5073       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5074 #if 1
5075       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5076       for (p = 0; p < 4; ++p) {
5077         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5078       }
5079 #endif
5080       /* A-B face */
5081       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 3;
5082       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
5083       orntNew[0] = -2;
5084       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
5085       orntNew[1] = 0;
5086       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
5087       orntNew[2] = 0;
5088       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
5089       orntNew[3] = -2;
5090       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5091       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5092 #if 1
5093       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5094       for (p = 0; p < 4; ++p) {
5095         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5096       }
5097 #endif
5098       /* E-F face */
5099       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 4;
5100       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
5101       orntNew[0] = -2;
5102       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
5103       orntNew[1] = -2;
5104       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
5105       orntNew[2] = 0;
5106       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
5107       orntNew[3] = 0;
5108       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5109       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5110 #if 1
5111       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5112       for (p = 0; p < 4; ++p) {
5113         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5114       }
5115 #endif
5116       /* F-G face */
5117       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 5;
5118       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
5119       orntNew[0] = -2;
5120       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
5121       orntNew[1] = -2;
5122       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
5123       orntNew[2] = 0;
5124       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
5125       orntNew[3] = 0;
5126       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5127       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5128 #if 1
5129       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5130       for (p = 0; p < 4; ++p) {
5131         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5132       }
5133 #endif
5134       /* G-H face */
5135       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 6;
5136       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
5137       orntNew[0] = -2;
5138       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
5139       orntNew[1] = 0;
5140       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
5141       orntNew[2] = 0;
5142       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
5143       orntNew[3] = -2;
5144       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5145       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5146 #if 1
5147       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5148       for (p = 0; p < 4; ++p) {
5149         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5150       }
5151 #endif
5152       /* E-H face */
5153       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 7;
5154       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
5155       orntNew[0] = -2;
5156       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
5157       orntNew[1] = -2;
5158       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
5159       orntNew[2] = 0;
5160       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
5161       orntNew[3] = 0;
5162       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5163       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5164 #if 1
5165       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5166       for (p = 0; p < 4; ++p) {
5167         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5168       }
5169 #endif
5170       /* A-E face */
5171       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 8;
5172       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
5173       orntNew[0] = 0;
5174       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
5175       orntNew[1] = 0;
5176       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
5177       orntNew[2] = -2;
5178       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
5179       orntNew[3] = -2;
5180       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5181       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5182 #if 1
5183       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5184       for (p = 0; p < 4; ++p) {
5185         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5186       }
5187 #endif
5188       /* D-F face */
5189       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 9;
5190       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
5191       orntNew[0] = -2;
5192       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
5193       orntNew[1] = 0;
5194       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
5195       orntNew[2] = 0;
5196       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
5197       orntNew[3] = -2;
5198       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5199       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5200 #if 1
5201       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5202       for (p = 0; p < 4; ++p) {
5203         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5204       }
5205 #endif
5206       /* C-G face */
5207       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 10;
5208       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
5209       orntNew[0] = -2;
5210       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
5211       orntNew[1] = -2;
5212       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
5213       orntNew[2] = 0;
5214       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
5215       orntNew[3] = 0;
5216       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5217       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5218 #if 1
5219       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5220       for (p = 0; p < 4; ++p) {
5221         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5222       }
5223 #endif
5224       /* B-H face */
5225       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 11;
5226       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
5227       orntNew[0] = 0;
5228       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
5229       orntNew[1] = -2;
5230       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
5231       orntNew[2] = -2;
5232       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
5233       orntNew[3] = 0;
5234       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5235       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5236 #if 1
5237       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5238       for (p = 0; p < 4; ++p) {
5239         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eEndNew);
5240       }
5241 #endif
5242       for (r = 0; r < 12; ++r) {
5243         newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
5244         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
5245         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
5246         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5247 #if 1
5248         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5249         for (p = 0; p < 2; ++p) {
5250           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
5251         }
5252 #endif
5253       }
5254     }
5255     /* Split edges have 2 vertices and the same faces as the parent */
5256     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5257     for (e = eStart; e < eEnd; ++e) {
5258       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
5259 
5260       for (r = 0; r < 2; ++r) {
5261         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
5262         const PetscInt *cone, *ornt, *support;
5263         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5264 
5265         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
5266         coneNew[0]       = vStartNew + (cone[0] - vStart);
5267         coneNew[1]       = vStartNew + (cone[1] - vStart);
5268         coneNew[(r+1)%2] = newv;
5269         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5270 #if 1
5271         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5272         for (p = 0; p < 2; ++p) {
5273           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
5274         }
5275 #endif
5276         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
5277         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5278         for (s = 0; s < supportSize; ++s) {
5279           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5280           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5281           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5282           for (c = 0; c < coneSize; ++c) {
5283             if (cone[c] == e) break;
5284           }
5285           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
5286         }
5287         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5288 #if 1
5289         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5290         for (p = 0; p < supportSize; ++p) {
5291           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
5292         }
5293 #endif
5294       }
5295     }
5296     /* Face edges have 2 vertices and 2+cells faces */
5297     for (f = fStart; f < fEnd; ++f) {
5298       const PetscInt  newFaces[24] = {3, 2, 1, 0,  4, 5, 6, 7,  0, 9, 4, 8,  2, 11, 6, 10,  1, 10, 5, 9,  8, 7, 11, 3};
5299       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
5300       const PetscInt *cone, *coneCell, *orntCell, *support;
5301       PetscInt        coneNew[2], coneSize, c, supportSize, s;
5302 
5303       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5304       for (r = 0; r < 4; ++r) {
5305         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
5306 
5307         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
5308         coneNew[1] = newv;
5309         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5310 #if 1
5311         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5312         for (p = 0; p < 2; ++p) {
5313           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
5314         }
5315 #endif
5316         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5317         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5318         supportRef[0] = fStartNew + (f - fStart)*4 + r;
5319         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
5320         for (s = 0; s < supportSize; ++s) {
5321           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5322           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
5323           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
5324           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
5325           supportRef[2+s] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
5326         }
5327         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5328 #if 1
5329         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5330         for (p = 0; p < 2+supportSize; ++p) {
5331           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
5332         }
5333 #endif
5334       }
5335     }
5336     /* Cell edges have 2 vertices and 4 faces */
5337     for (c = cStart; c < cEnd; ++c) {
5338       const PetscInt  newFaces[24] = {0, 1, 2, 3,  4, 5, 6, 7,  0, 9, 4, 8,  2, 11, 6, 10,  1, 10, 5, 9,  3, 8, 7, 11};
5339       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
5340       const PetscInt *cone;
5341       PetscInt        coneNew[2], supportNew[4];
5342 
5343       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5344       for (r = 0; r < 6; ++r) {
5345         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
5346 
5347         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
5348         coneNew[1] = newv;
5349         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5350 #if 1
5351         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5352         for (p = 0; p < 2; ++p) {
5353           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
5354         }
5355 #endif
5356         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
5357         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5358 #if 1
5359         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
5360         for (p = 0; p < 4; ++p) {
5361           if ((supportNew[p] < fStartNew) || (supportNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportNew[p], fStartNew, fEndNew);
5362         }
5363 #endif
5364       }
5365     }
5366     /* Old vertices have identical supports */
5367     for (v = vStart; v < vEnd; ++v) {
5368       const PetscInt  newp = vStartNew + (v - vStart);
5369       const PetscInt *support, *cone;
5370       PetscInt        size, s;
5371 
5372       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5373       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5374       for (s = 0; s < size; ++s) {
5375         PetscInt r = 0;
5376 
5377         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5378         if (cone[1] == v) r = 1;
5379         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
5380       }
5381       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5382 #if 1
5383       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5384       for (p = 0; p < size; ++p) {
5385         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
5386       }
5387 #endif
5388     }
5389     /* Edge vertices have 2 + faces supports */
5390     for (e = eStart; e < eEnd; ++e) {
5391       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
5392       const PetscInt *cone, *support;
5393       PetscInt        size, s;
5394 
5395       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
5396       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5397       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
5398       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
5399       for (s = 0; s < size; ++s) {
5400         PetscInt r;
5401 
5402         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5403         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
5404         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*4 + r;
5405       }
5406       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5407 #if 1
5408       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5409       for (p = 0; p < 2+size; ++p) {
5410         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
5411       }
5412 #endif
5413     }
5414     /* Face vertices have 4 + cells supports */
5415     for (f = fStart; f < fEnd; ++f) {
5416       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
5417       const PetscInt *cone, *support;
5418       PetscInt        size, s;
5419 
5420       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5421       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5422       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eEnd - eStart)*2 +  (f - fStart)*4 + r;
5423       for (s = 0; s < size; ++s) {
5424         PetscInt r;
5425 
5426         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5427         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
5428         supportRef[4+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (support[s] - cStart)*6 + r;
5429       }
5430       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5431 #if 1
5432       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5433       for (p = 0; p < 4+size; ++p) {
5434         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
5435       }
5436 #endif
5437     }
5438     /* Cell vertices have 6 supports */
5439     for (c = cStart; c < cEnd; ++c) {
5440       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
5441       PetscInt       supportNew[6];
5442 
5443       for (r = 0; r < 6; ++r) {
5444         supportNew[r] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
5445       }
5446       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5447     }
5448     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5449     break;
5450   case REFINER_HYBRID_HEX_3D:
5451     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
5452     /*
5453      Bottom (viewed from top)    Top
5454      1---------2---------2       7---------2---------6
5455      |         |         |       |         |         |
5456      |    B    2    C    |       |    H    2    G    |
5457      |         |         |       |         |         |
5458      3----3----0----1----1       3----3----0----1----1
5459      |         |         |       |         |         |
5460      |    A    0    D    |       |    E    0    F    |
5461      |         |         |       |         |         |
5462      0---------0---------3       4---------0---------5
5463      */
5464     /* Interior cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
5465     for (c = cStart; c < cMax; ++c) {
5466       const PetscInt  newp = (c - cStart)*8;
5467       const PetscInt *cone, *ornt;
5468       PetscInt        coneNew[6], orntNew[6];
5469 
5470       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5471       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5472       /* A hex */
5473       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
5474       orntNew[0] = ornt[0];
5475       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
5476       orntNew[1] = 0;
5477       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
5478       orntNew[2] = ornt[2];
5479       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
5480       orntNew[3] = 0;
5481       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
5482       orntNew[4] = 0;
5483       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
5484       orntNew[5] = ornt[5];
5485       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5486       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5487 #if 1
5488       if ((newp+0 < cStartNew) || (newp+0 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cMaxNew);
5489       for (p = 0; p < 6; ++p) {
5490         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
5491       }
5492 #endif
5493       /* B hex */
5494       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
5495       orntNew[0] = ornt[0];
5496       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
5497       orntNew[1] = 0;
5498       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
5499       orntNew[2] = -1;
5500       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
5501       orntNew[3] = ornt[3];
5502       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
5503       orntNew[4] = 0;
5504       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
5505       orntNew[5] = ornt[5];
5506       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5507       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5508 #if 1
5509       if ((newp+1 < cStartNew) || (newp+1 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cMaxNew);
5510       for (p = 0; p < 6; ++p) {
5511         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
5512       }
5513 #endif
5514       /* C hex */
5515       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
5516       orntNew[0] = ornt[0];
5517       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
5518       orntNew[1] = 0;
5519       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
5520       orntNew[2] = -1;
5521       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
5522       orntNew[3] = ornt[3];
5523       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
5524       orntNew[4] = ornt[4];
5525       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
5526       orntNew[5] = -4;
5527       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5528       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5529 #if 1
5530       if ((newp+2 < cStartNew) || (newp+2 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cMaxNew);
5531       for (p = 0; p < 6; ++p) {
5532         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
5533       }
5534 #endif
5535       /* D hex */
5536       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
5537       orntNew[0] = ornt[0];
5538       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
5539       orntNew[1] = 0;
5540       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
5541       orntNew[2] = ornt[2];
5542       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
5543       orntNew[3] = 0;
5544       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
5545       orntNew[4] = ornt[4];
5546       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
5547       orntNew[5] = -4;
5548       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5549       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5550 #if 1
5551       if ((newp+3 < cStartNew) || (newp+3 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cMaxNew);
5552       for (p = 0; p < 6; ++p) {
5553         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
5554       }
5555 #endif
5556       /* E hex */
5557       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
5558       orntNew[0] = -4;
5559       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
5560       orntNew[1] = ornt[1];
5561       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
5562       orntNew[2] = ornt[2];
5563       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
5564       orntNew[3] = 0;
5565       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
5566       orntNew[4] = -1;
5567       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
5568       orntNew[5] = ornt[5];
5569       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
5570       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
5571 #if 1
5572       if ((newp+4 < cStartNew) || (newp+4 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+4, cStartNew, cMaxNew);
5573       for (p = 0; p < 6; ++p) {
5574         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
5575       }
5576 #endif
5577       /* F hex */
5578       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
5579       orntNew[0] = -4;
5580       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
5581       orntNew[1] = ornt[1];
5582       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
5583       orntNew[2] = ornt[2];
5584       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
5585       orntNew[3] = -1;
5586       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
5587       orntNew[4] = ornt[4];
5588       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
5589       orntNew[5] = 1;
5590       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
5591       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
5592 #if 1
5593       if ((newp+5 < cStartNew) || (newp+5 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+5, cStartNew, cMaxNew);
5594       for (p = 0; p < 6; ++p) {
5595         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
5596       }
5597 #endif
5598       /* G hex */
5599       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
5600       orntNew[0] = -4;
5601       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
5602       orntNew[1] = ornt[1];
5603       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
5604       orntNew[2] = 0;
5605       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
5606       orntNew[3] = ornt[3];
5607       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
5608       orntNew[4] = ornt[4];
5609       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
5610       orntNew[5] = -3;
5611       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
5612       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
5613 #if 1
5614       if ((newp+6 < cStartNew) || (newp+6 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+6, cStartNew, cMaxNew);
5615       for (p = 0; p < 6; ++p) {
5616         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
5617       }
5618 #endif
5619       /* H hex */
5620       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
5621       orntNew[0] = -4;
5622       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
5623       orntNew[1] = ornt[1];
5624       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
5625       orntNew[2] = -1;
5626       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
5627       orntNew[3] = ornt[3];
5628       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
5629       orntNew[4] = 3;
5630       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
5631       orntNew[5] = ornt[5];
5632       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
5633       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
5634 #if 1
5635       if ((newp+7 < cStartNew) || (newp+7 >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+7, cStartNew, cMaxNew);
5636       for (p = 0; p < 6; ++p) {
5637         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
5638       }
5639 #endif
5640     }
5641     /* Hybrid cells have 6 faces: Front, Back, Sides */
5642     /*
5643      3---------2---------2
5644      |         |         |
5645      |    D    2    C    |
5646      |         |         |
5647      3----3----0----1----1
5648      |         |         |
5649      |    A    0    B    |
5650      |         |         |
5651      0---------0---------1
5652      */
5653     for (c = cMax; c < cEnd; ++c) {
5654       const PetscInt  newp = (cMax - cStart)*8 + (c - cMax)*4;
5655       const PetscInt *cone, *ornt, *fornt;
5656       PetscInt        coneNew[6], orntNew[6], o, of, i;
5657 
5658       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5659       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5660       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
5661       o = ornt[0] < 0 ? -1 : 1;
5662       for (r = 0; r < 4; ++r) {
5663         PetscInt subfA = GetQuadSubface_Static(ornt[0], r);
5664         PetscInt edgeA = GetQuadEdge_Static(ornt[0], r);
5665         PetscInt edgeB = GetQuadEdge_Static(ornt[0], (r+3)%4);
5666         if (ornt[0] != ornt[1]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent ordering for matching ends of hybrid cell %d: %d != %d", c, ornt[0], ornt[1]);
5667         coneNew[0]         = fStartNew + (cone[0] - fStart)*4 + subfA;
5668         orntNew[0]         = ornt[0];
5669         coneNew[1]         = fStartNew + (cone[1] - fStart)*4 + subfA;
5670         orntNew[1]         = ornt[0];
5671         of = fornt[edgeA] < 0 ? -1 : 1;
5672         i  = GetQuadEdgeInverse_Static(ornt[0], r) + 2;
5673         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeA] - fMax)*2 + (o*of < 0 ? 1 : 0);
5674         orntNew[i] = ornt[edgeA];
5675         i  = GetQuadEdgeInverse_Static(ornt[0], (r+1)%4) + 2;
5676         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeA;
5677         orntNew[i] = 0;
5678         i  = GetQuadEdgeInverse_Static(ornt[0], (r+2)%4) + 2;
5679         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeB;
5680         orntNew[i] = -2;
5681         of = fornt[edgeB] < 0 ? -1 : 1;
5682         i  = GetQuadEdgeInverse_Static(ornt[0], (r+3)%4) + 2;
5683         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeB] - fMax)*2 + (o*of < 0 ? 0 : 1);
5684         orntNew[i] = ornt[edgeB];
5685         ierr       = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
5686         ierr       = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
5687 #if 1
5688         if ((newp+r < cMaxNew) || (newp+r >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", newp+r, cMaxNew, cEndNew);
5689         for (p = 0; p < 2; ++p) {
5690           if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
5691         }
5692         for (p = 2; p < 6; ++p) {
5693           if ((coneNew[p] < fMaxNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", coneNew[p], fMaxNew, fEndNew);
5694         }
5695 #endif
5696       }
5697     }
5698     /* Interior split faces have 4 edges and the same cells as the parent */
5699     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5700     ierr = PetscMalloc1(4 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
5701     for (f = fStart; f < fMax; ++f) {
5702       for (r = 0; r < 4; ++r) {
5703         /* TODO: This can come from GetFaces_Internal() */
5704         const PetscInt  newCells[24] = {0, 1, 2, 3,  4, 5, 6, 7,  0, 3, 5, 4,  2, 1, 7, 6,  3, 2, 6, 5,  0, 4, 7, 1};
5705         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
5706         const PetscInt *cone, *ornt, *support;
5707         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
5708 
5709         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5710         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
5711         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
5712         orntNew[(r+3)%4] = ornt[(r+3)%4];
5713         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
5714         orntNew[(r+0)%4] = ornt[r];
5715         coneNew[(r+1)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
5716         orntNew[(r+1)%4] = 0;
5717         coneNew[(r+2)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + (r+3)%4;
5718         orntNew[(r+2)%4] = -2;
5719         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5720         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5721 #if 1
5722         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5723         for (p = 0; p < 4; ++p) {
5724           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5725         }
5726 #endif
5727         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5728         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5729         for (s = 0; s < supportSize; ++s) {
5730           PetscInt subf;
5731           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5732           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5733           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5734           for (c = 0; c < coneSize; ++c) {
5735             if (cone[c] == f) break;
5736           }
5737           subf = GetQuadSubfaceInverse_Static(ornt[c], r);
5738           if (support[s] < cMax) {
5739             supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+subf];
5740           } else {
5741             supportRef[s] = cStartNew + (cMax       - cStart)*8 + (support[s] - cMax)*4 + subf;
5742           }
5743         }
5744         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5745 #if 1
5746         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5747         for (p = 0; p < supportSize; ++p) {
5748           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
5749         }
5750 #endif
5751       }
5752     }
5753     /* Interior cell faces have 4 edges and 2 cells */
5754     for (c = cStart; c < cMax; ++c) {
5755       const PetscInt  newCells[24] = {0, 3,  2, 3,  1, 2,  0, 1,  4, 5,  5, 6,  6, 7,  4, 7,  0, 4,  3, 5,  2, 6,  1, 7};
5756       const PetscInt *cone, *ornt;
5757       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
5758 
5759       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5760       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5761       /* A-D face */
5762       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 0;
5763       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
5764       orntNew[0] = 0;
5765       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
5766       orntNew[1] = 0;
5767       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
5768       orntNew[2] = -2;
5769       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
5770       orntNew[3] = -2;
5771       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5772       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5773 #if 1
5774       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5775       for (p = 0; p < 4; ++p) {
5776         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5777       }
5778 #endif
5779       /* C-D face */
5780       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 1;
5781       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
5782       orntNew[0] = 0;
5783       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
5784       orntNew[1] = 0;
5785       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
5786       orntNew[2] = -2;
5787       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
5788       orntNew[3] = -2;
5789       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5790       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5791 #if 1
5792       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5793       for (p = 0; p < 4; ++p) {
5794         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5795       }
5796 #endif
5797       /* B-C face */
5798       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 2;
5799       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
5800       orntNew[0] = -2;
5801       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
5802       orntNew[1] = 0;
5803       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
5804       orntNew[2] = 0;
5805       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
5806       orntNew[3] = -2;
5807       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5808       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5809 #if 1
5810       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5811       for (p = 0; p < 4; ++p) {
5812         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5813       }
5814 #endif
5815       /* A-B face */
5816       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 3;
5817       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
5818       orntNew[0] = -2;
5819       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
5820       orntNew[1] = 0;
5821       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
5822       orntNew[2] = 0;
5823       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
5824       orntNew[3] = -2;
5825       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5826       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5827 #if 1
5828       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5829       for (p = 0; p < 4; ++p) {
5830         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5831       }
5832 #endif
5833       /* E-F face */
5834       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 4;
5835       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
5836       orntNew[0] = -2;
5837       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
5838       orntNew[1] = -2;
5839       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
5840       orntNew[2] = 0;
5841       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
5842       orntNew[3] = 0;
5843       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5844       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5845 #if 1
5846       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5847       for (p = 0; p < 4; ++p) {
5848         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5849       }
5850 #endif
5851       /* F-G face */
5852       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 5;
5853       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
5854       orntNew[0] = -2;
5855       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
5856       orntNew[1] = -2;
5857       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
5858       orntNew[2] = 0;
5859       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
5860       orntNew[3] = 0;
5861       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5862       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5863 #if 1
5864       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5865       for (p = 0; p < 4; ++p) {
5866         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5867       }
5868 #endif
5869       /* G-H face */
5870       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 6;
5871       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
5872       orntNew[0] = -2;
5873       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
5874       orntNew[1] = 0;
5875       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
5876       orntNew[2] = 0;
5877       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
5878       orntNew[3] = -2;
5879       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5880       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5881 #if 1
5882       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5883       for (p = 0; p < 4; ++p) {
5884         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5885       }
5886 #endif
5887       /* E-H face */
5888       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 7;
5889       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
5890       orntNew[0] = -2;
5891       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
5892       orntNew[1] = -2;
5893       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
5894       orntNew[2] = 0;
5895       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
5896       orntNew[3] = 0;
5897       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5898       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5899 #if 1
5900       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5901       for (p = 0; p < 4; ++p) {
5902         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5903       }
5904 #endif
5905       /* A-E face */
5906       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 8;
5907       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
5908       orntNew[0] = 0;
5909       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
5910       orntNew[1] = 0;
5911       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
5912       orntNew[2] = -2;
5913       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
5914       orntNew[3] = -2;
5915       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5916       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5917 #if 1
5918       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5919       for (p = 0; p < 4; ++p) {
5920         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5921       }
5922 #endif
5923       /* D-F face */
5924       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 9;
5925       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
5926       orntNew[0] = -2;
5927       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
5928       orntNew[1] = 0;
5929       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
5930       orntNew[2] = 0;
5931       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
5932       orntNew[3] = -2;
5933       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5934       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5935 #if 1
5936       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5937       for (p = 0; p < 4; ++p) {
5938         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5939       }
5940 #endif
5941       /* C-G face */
5942       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 10;
5943       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
5944       orntNew[0] = -2;
5945       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
5946       orntNew[1] = -2;
5947       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
5948       orntNew[2] = 0;
5949       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
5950       orntNew[3] = 0;
5951       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5952       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5953 #if 1
5954       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5955       for (p = 0; p < 4; ++p) {
5956         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5957       }
5958 #endif
5959       /* B-H face */
5960       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 11;
5961       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
5962       orntNew[0] = 0;
5963       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
5964       orntNew[1] = -2;
5965       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
5966       orntNew[2] = -2;
5967       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
5968       orntNew[3] = 0;
5969       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5970       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5971 #if 1
5972       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5973       for (p = 0; p < 4; ++p) {
5974         if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
5975       }
5976 #endif
5977       for (r = 0; r < 12; ++r) {
5978         newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
5979         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
5980         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
5981         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5982 #if 1
5983         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5984         for (p = 0; p < 2; ++p) {
5985           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cMaxNew);
5986         }
5987 #endif
5988       }
5989     }
5990     /* Hybrid split faces have 4 edges and same cells */
5991     for (f = fMax; f < fEnd; ++f) {
5992       const PetscInt *cone, *ornt, *support;
5993       PetscInt        coneNew[4], orntNew[4];
5994       PetscInt        supportNew[2], size, s, c;
5995 
5996       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5997       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
5998       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5999       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6000       for (r = 0; r < 2; ++r) {
6001         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
6002 
6003         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
6004         orntNew[0]   = ornt[0];
6005         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
6006         orntNew[1]   = ornt[1];
6007         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (cone[2+r] - eMax);
6008         orntNew[2+r] = 0;
6009         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd      - eMax) + (f - fMax);
6010         orntNew[3-r] = 0;
6011         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6012         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
6013 #if 1
6014         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
6015         for (p = 0; p < 2; ++p) {
6016           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
6017         }
6018         for (p = 2; p < 4; ++p) {
6019           if ((coneNew[p] < eMaxNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", coneNew[p], eMaxNew, eEndNew);
6020         }
6021 #endif
6022         for (s = 0; s < size; ++s) {
6023           const PetscInt *coneCell, *orntCell, *fornt;
6024           PetscInt        o, of;
6025 
6026           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
6027           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
6028           o = orntCell[0] < 0 ? -1 : 1;
6029           for (c = 2; c < 6; ++c) if (coneCell[c] == f) break;
6030           if (c >= 6) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
6031           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
6032           of = fornt[c-2] < 0 ? -1 : 1;
6033           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetQuadEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%4;
6034         }
6035         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6036 #if 1
6037         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
6038         for (p = 0; p < size; ++p) {
6039           if ((supportNew[p] < cMaxNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", supportNew[p], cMaxNew, cEndNew);
6040         }
6041 #endif
6042       }
6043     }
6044     /* Hybrid cell faces have 4 edges and 2 cells */
6045     for (c = cMax; c < cEnd; ++c) {
6046       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4;
6047       const PetscInt *cone, *ornt;
6048       PetscInt        coneNew[4], orntNew[4];
6049       PetscInt        supportNew[2];
6050 
6051       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6052       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6053       for (r = 0; r < 4; ++r) {
6054 #if 0
6055         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], r);
6056         orntNew[0] = 0;
6057         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], r);
6058         orntNew[1] = 0;
6059         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+GetQuadEdge_Static(ornt[0], r)] - fMax);
6060         orntNew[2] = 0;
6061         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd                                   - fMax) + (c - cMax);
6062         orntNew[3] = 0;
6063 #else
6064         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + r;
6065         orntNew[0] = 0;
6066         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + r;
6067         orntNew[1] = 0;
6068         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+r] - fMax);
6069         orntNew[2] = 0;
6070         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd      - fMax) + (c - cMax);
6071         orntNew[3] = 0;
6072 #endif
6073         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
6074         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
6075 #if 1
6076         if ((newp+r < fMaxNew) || (newp+r >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp+r, fMaxNew, fEndNew);
6077         for (p = 0; p < 2; ++p) {
6078           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
6079         }
6080         for (p = 2; p < 4; ++p) {
6081           if ((coneNew[p] < eMaxNew) || (coneNew[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", coneNew[p], eMaxNew, eEndNew);
6082         }
6083 #endif
6084         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], r);
6085         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], (r+1)%4);
6086         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
6087 #if 1
6088         if ((newp+r < fMaxNew) || (newp+r >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp+r, fMaxNew, fEndNew);
6089         for (p = 0; p < 2; ++p) {
6090           if ((supportNew[p] < cMaxNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid cell [%d, %d)", supportNew[p], cMaxNew, cEndNew);
6091         }
6092 #endif
6093       }
6094     }
6095     /* Interior split edges have 2 vertices and the same faces as the parent */
6096     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6097     for (e = eStart; e < eMax; ++e) {
6098       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
6099 
6100       for (r = 0; r < 2; ++r) {
6101         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
6102         const PetscInt *cone, *ornt, *support;
6103         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6104 
6105         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6106         coneNew[0]       = vStartNew + (cone[0] - vStart);
6107         coneNew[1]       = vStartNew + (cone[1] - vStart);
6108         coneNew[(r+1)%2] = newv;
6109         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6110 #if 1
6111         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6112         for (p = 0; p < 2; ++p) {
6113           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6114         }
6115 #endif
6116         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
6117         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
6118         for (s = 0; s < supportSize; ++s) {
6119           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6120           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6121           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
6122           for (c = 0; c < coneSize; ++c) {
6123             if (cone[c] == e) break;
6124           }
6125           if (support[s] < fMax) {
6126             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%4;
6127           } else {
6128             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
6129           }
6130         }
6131         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6132 #if 1
6133         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6134         for (p = 0; p < supportSize; ++p) {
6135           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6136         }
6137 #endif
6138       }
6139     }
6140     /* Interior face edges have 2 vertices and 2+cells faces */
6141     for (f = fStart; f < fMax; ++f) {
6142       const PetscInt  newFaces[24] = {3, 2, 1, 0,  4, 5, 6, 7,  0, 9, 4, 8,  2, 11, 6, 10,  1, 10, 5, 9,  8, 7, 11, 3};
6143       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
6144       const PetscInt *cone, *coneCell, *orntCell, *support;
6145       PetscInt        coneNew[2], coneSize, c, supportSize, s;
6146 
6147       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6148       for (r = 0; r < 4; ++r) {
6149         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
6150 
6151         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
6152         coneNew[1] = newv;
6153         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6154 #if 1
6155         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6156         for (p = 0; p < 2; ++p) {
6157           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6158         }
6159 #endif
6160         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6161         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6162         supportRef[0] = fStartNew + (f - fStart)*4 + r;
6163         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
6164         for (s = 0; s < supportSize; ++s) {
6165           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6166           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
6167           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
6168           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
6169           if (support[s] < cMax) {
6170             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
6171           } else {
6172             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + r;
6173           }
6174         }
6175         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6176 #if 1
6177         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6178         for (p = 0; p < 2+supportSize; ++p) {
6179           if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6180         }
6181 #endif
6182       }
6183     }
6184     /* Interior cell edges have 2 vertices and 4 faces */
6185     for (c = cStart; c < cMax; ++c) {
6186       const PetscInt  newFaces[24] = {0, 1, 2, 3,  4, 5, 6, 7,  0, 9, 4, 8,  2, 11, 6, 10,  1, 10, 5, 9,  3, 8, 7, 11};
6187       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
6188       const PetscInt *cone;
6189       PetscInt        coneNew[2], supportNew[4];
6190 
6191       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6192       for (r = 0; r < 6; ++r) {
6193         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
6194 
6195         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
6196         coneNew[1] = newv;
6197         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6198 #if 1
6199         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6200         for (p = 0; p < 2; ++p) {
6201           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6202         }
6203 #endif
6204         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
6205         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6206 #if 1
6207         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
6208         for (p = 0; p < 4; ++p) {
6209           if ((supportNew[p] < fStartNew) || (supportNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportNew[p], fStartNew, fMaxNew);
6210         }
6211 #endif
6212       }
6213     }
6214     /* Hybrid edges have two vertices and the same faces */
6215     for (e = eMax; e < eEnd; ++e) {
6216       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
6217       const PetscInt *cone, *support, *fcone;
6218       PetscInt        coneNew[2], size, fsize, s;
6219 
6220       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6221       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
6222       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
6223       coneNew[0] = vStartNew + (cone[0] - vStart);
6224       coneNew[1] = vStartNew + (cone[1] - vStart);
6225       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6226 #if 1
6227       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6228       for (p = 0; p < 2; ++p) {
6229         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6230       }
6231 #endif
6232       for (s = 0; s < size; ++s) {
6233         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
6234         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
6235         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
6236         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
6237         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + c-2;
6238       }
6239       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6240 #if 1
6241       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6242       for (p = 0; p < size; ++p) {
6243         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", supportRef[p], fMaxNew, fEndNew);
6244       }
6245 #endif
6246     }
6247     /* Hybrid face edges have 2 vertices and 2+cells faces */
6248     for (f = fMax; f < fEnd; ++f) {
6249       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
6250       const PetscInt *cone, *support, *ccone, *cornt;
6251       PetscInt        coneNew[2], size, csize, s;
6252 
6253       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6254       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6255       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6256       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
6257       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
6258       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6259 #if 1
6260       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6261       for (p = 0; p < 2; ++p) {
6262         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6263       }
6264 #endif
6265       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 0;
6266       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 1;
6267       for (s = 0; s < size; ++s) {
6268         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
6269         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
6270         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
6271         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
6272         if ((c < 2) || (c >= csize)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Hybrid face %d is not in cone of hybrid cell %d", f, support[s]);
6273         supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + c-2;
6274       }
6275       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6276 #if 1
6277       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6278       for (p = 0; p < 2+size; ++p) {
6279         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", supportRef[p], fMaxNew, fEndNew);
6280       }
6281 #endif
6282     }
6283     /* Hybrid cell edges have 2 vertices and 4 faces */
6284     for (c = cMax; c < cEnd; ++c) {
6285       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
6286       const PetscInt *cone, *support;
6287       PetscInt        coneNew[2], size;
6288 
6289       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6290       ierr = DMPlexGetSupportSize(dm, c, &size);CHKERRQ(ierr);
6291       ierr = DMPlexGetSupport(dm, c, &support);CHKERRQ(ierr);
6292       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
6293       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
6294       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6295 #if 1
6296       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6297       for (p = 0; p < 2; ++p) {
6298         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6299       }
6300 #endif
6301       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 0;
6302       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 1;
6303       supportRef[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 2;
6304       supportRef[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 3;
6305       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6306 #if 1
6307       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
6308       for (p = 0; p < 4; ++p) {
6309         if ((supportRef[p] < fMaxNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", supportRef[p], fMaxNew, fEndNew);
6310       }
6311 #endif
6312     }
6313     /* Interior vertices have identical supports */
6314     for (v = vStart; v < vEnd; ++v) {
6315       const PetscInt  newp = vStartNew + (v - vStart);
6316       const PetscInt *support, *cone;
6317       PetscInt        size, s;
6318 
6319       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6320       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6321       for (s = 0; s < size; ++s) {
6322         PetscInt r = 0;
6323 
6324         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6325         if (cone[1] == v) r = 1;
6326         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
6327         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (support[s] - eMax);
6328       }
6329       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6330 #if 1
6331       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6332       for (p = 0; p < size; ++p) {
6333         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
6334       }
6335 #endif
6336     }
6337     /* Interior edge vertices have 2 + faces supports */
6338     for (e = eStart; e < eMax; ++e) {
6339       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
6340       const PetscInt *cone, *support;
6341       PetscInt        size, s;
6342 
6343       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
6344       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
6345       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
6346       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
6347       for (s = 0; s < size; ++s) {
6348         PetscInt r;
6349 
6350         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6351         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
6352         if (support[s] < fMax) {
6353           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*4 + r;
6354         } else {
6355           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (support[s] - fMax);
6356         }
6357       }
6358       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6359 #if 1
6360       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6361       for (p = 0; p < 2+size; ++p) {
6362         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
6363       }
6364 #endif
6365     }
6366     /* Interior face vertices have 4 + cells supports */
6367     for (f = fStart; f < fMax; ++f) {
6368       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
6369       const PetscInt *cone, *support;
6370       PetscInt        size, s;
6371 
6372       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6373       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6374       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eMax - eStart)*2 +  (f - fStart)*4 + r;
6375       for (s = 0; s < size; ++s) {
6376         PetscInt r;
6377 
6378         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6379         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
6380         if (support[s] < cMax) {
6381           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (support[s] - cStart)*6 + r;
6382         } else {
6383           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax       - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (support[s] - cMax);
6384         }
6385       }
6386       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6387 #if 1
6388       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6389       for (p = 0; p < 4+size; ++p) {
6390         if ((supportRef[p] < eStartNew) || (supportRef[p] >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", supportRef[p], eStartNew, eEndNew);
6391       }
6392 #endif
6393     }
6394     /* Cell vertices have 6 supports */
6395     for (c = cStart; c < cMax; ++c) {
6396       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
6397       PetscInt       supportNew[6];
6398 
6399       for (r = 0; r < 6; ++r) {
6400         supportNew[r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
6401       }
6402       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6403     }
6404     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6405     break;
6406   default:
6407     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6408   }
6409   PetscFunctionReturn(0);
6410 }
6411 
6412 static PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6413 {
6414   PetscSection          coordSection, coordSectionNew;
6415   Vec                   coordinates, coordinatesNew;
6416   PetscScalar          *coords, *coordsNew;
6417   const PetscInt        numVertices = depthSize ? depthSize[0] : 0;
6418   PetscInt              dim, spaceDim, depth, bs, coordSizeNew, cStart, cEnd, cMax;
6419   PetscInt              c, vStart, vStartNew, vEnd, v, eStart, eEnd, eMax, e, fStart, fEnd, fMax, f;
6420   PetscInt              cStartNew, cEndNew, vEndNew, *parentId = NULL;
6421   VecType               vtype;
6422   PetscBool             isperiodic, localize = PETSC_FALSE, needcoords = PETSC_FALSE;
6423   const PetscReal      *maxCell, *L;
6424   const DMBoundaryType *bd;
6425   PetscErrorCode        ierr;
6426 
6427   PetscFunctionBegin;
6428   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6429   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6430   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6431   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6432   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6433   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6434   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, NULL);CHKERRQ(ierr);
6435   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, NULL, NULL, &vStartNew);CHKERRQ(ierr);
6436   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, NULL, NULL, &vEndNew);CHKERRQ(ierr);
6437   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6438   ierr = PetscSectionGetFieldComponents(coordSection, 0, &spaceDim);CHKERRQ(ierr);
6439   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
6440   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
6441   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, spaceDim);CHKERRQ(ierr);
6442   ierr = DMGetPeriodicity(dm, &isperiodic, &maxCell, &L, &bd);CHKERRQ(ierr);
6443   ierr = DMSetPeriodicity(rdm, isperiodic,  maxCell,  L,  bd);CHKERRQ(ierr);
6444   /* Determine if we need to localize coordinates when generating them */
6445   if (isperiodic && !maxCell) {
6446     ierr = DMGetCoordinatesLocalized(dm, &localize);CHKERRQ(ierr);
6447     if (!localize) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Cannot refine if coordinates have not been localized");
6448   }
6449   if (localize) {
6450     PetscInt p, r, newp, *pi;
6451 
6452     /* New coordinates will be already localized on the cell */
6453     ierr = PetscSectionSetChart(coordSectionNew, 0, vStartNew+numVertices);CHKERRQ(ierr);
6454 
6455     /* We need the parentId to properly localize coordinates */
6456     ierr = PetscMalloc1(cEndNew-cStartNew,&pi);CHKERRQ(ierr);
6457     switch (refiner) {
6458     case REFINER_NOOP:
6459       break;
6460     case REFINER_SIMPLEX_1D:
6461       for (p = cStart; p < cEnd; ++p) {
6462         for (r = 0; r < 2; ++r) {
6463           newp     = (p - cStart)*2 + r;
6464           pi[newp] = p;
6465         }
6466       }
6467       break;
6468     case REFINER_SIMPLEX_2D:
6469       for (p = cStart; p < cEnd; ++p) {
6470         for (r = 0; r < 4; ++r) {
6471           newp     = (p - cStart)*4 + r;
6472           pi[newp] = p;
6473         }
6474       }
6475       break;
6476     case REFINER_HEX_2D:
6477       for (p = cStart; p < cEnd; ++p) {
6478         for (r = 0; r < 4; ++r) {
6479           newp     = (p - cStart)*4 + r;
6480           pi[newp] = p;
6481         }
6482       }
6483       break;
6484     case REFINER_HYBRID_SIMPLEX_2D:
6485       for (p = cStart; p < cMax; ++p) {
6486         for (r = 0; r < 4; ++r) {
6487           newp     = (p - cStart)*4 + r;
6488           pi[newp] = p;
6489         }
6490       }
6491       for (p = cMax; p < cEnd; ++p) {
6492         for (r = 0; r < 2; ++r) {
6493           newp     = (cMax - cStart)*4 + (p - cMax)*2 + r;
6494           pi[newp] = p;
6495         }
6496       }
6497       break;
6498     case REFINER_HYBRID_HEX_2D:
6499       for (p = cStart; p < cMax; ++p) {
6500         for (r = 0; r < 4; ++r) {
6501           newp     = (p - cStart)*4 + r;
6502           pi[newp] = p;
6503         }
6504       }
6505       for (p = cMax; p < cEnd; ++p) {
6506         for (r = 0; r < 2; ++r) {
6507           newp     = (cMax - cStart)*4 + (p - cMax)*2 + r;
6508           pi[newp] = p;
6509         }
6510       }
6511       break;
6512     case REFINER_SIMPLEX_3D:
6513       for (p = cStart; p < cEnd; ++p) {
6514         for (r = 0; r < 8; ++r) {
6515           newp     = (p - cStart)*8 + r;
6516           pi[newp] = p;
6517         }
6518       }
6519       break;
6520     case REFINER_HYBRID_SIMPLEX_3D:
6521       for (p = cStart; p < cMax; ++p) {
6522         for (r = 0; r < 8; ++r) {
6523           newp     = (p - cStart)*8 + r;
6524           pi[newp] = p;
6525         }
6526       }
6527       for (p = cMax; p < cEnd; ++p) {
6528         for (r = 0; r < 4; ++r) {
6529           newp     = (cMax - cStart)*8 + (p - cMax)*4 + r;
6530           pi[newp] = p;
6531         }
6532       }
6533       break;
6534     case REFINER_HEX_3D:
6535       for (p = cStart; p < cEnd; ++p) {
6536         for (r = 0; r < 8; ++r) {
6537           newp = (p - cStart)*8 + r;
6538           pi[newp] = p;
6539         }
6540       }
6541       break;
6542     case REFINER_HYBRID_HEX_3D:
6543       for (p = cStart; p < cMax; ++p) {
6544         for (r = 0; r < 8; ++r) {
6545           newp = (p - cStart)*8 + r;
6546           pi[newp] = p;
6547         }
6548       }
6549       for (p = cMax; p < cEnd; ++p) {
6550         for (r = 0; r < 4; ++r) {
6551           newp = (cMax - cStart)*8 + (p - cMax)*4 + r;
6552           pi[newp] = p;
6553         }
6554       }
6555       break;
6556     default:
6557       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6558     }
6559     parentId = pi;
6560   } else {
6561     ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+numVertices);CHKERRQ(ierr);
6562   }
6563   if (cMax < 0) cMax = cEnd;
6564   if (fMax < 0) fMax = fEnd;
6565   if (eMax < 0) eMax = eEnd;
6566 
6567   /* All vertices have the spaceDim coordinates */
6568   if (localize) {
6569     PetscInt c;
6570 
6571     for (c = cStartNew; c < cEndNew; ++c) {
6572       PetscInt *cone = NULL;
6573       PetscInt  closureSize, coneSize = 0, p, pdof;
6574 
6575       ierr = PetscSectionGetDof(coordSection, parentId[c], &pdof); CHKERRQ(ierr);
6576       if (pdof) { /* localize on all cells that are refinement of a localized parent cell */
6577         ierr = DMPlexGetTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6578         for (p = 0; p < closureSize*2; p += 2) {
6579           const PetscInt point = cone[p];
6580           if ((point >= vStartNew) && (point < vEndNew)) coneSize++;
6581         }
6582         ierr = DMPlexRestoreTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6583         ierr = PetscSectionSetDof(coordSectionNew, c, coneSize*spaceDim);CHKERRQ(ierr);
6584         ierr = PetscSectionSetFieldDof(coordSectionNew, c, 0, coneSize*spaceDim);CHKERRQ(ierr);
6585       }
6586     }
6587   }
6588   for (v = vStartNew; v < vStartNew+numVertices; ++v) {
6589     ierr = PetscSectionSetDof(coordSectionNew, v, spaceDim);CHKERRQ(ierr);
6590     ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, spaceDim);CHKERRQ(ierr);
6591   }
6592   ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
6593   ierr = DMSetCoordinateSection(rdm, PETSC_DETERMINE, coordSectionNew);CHKERRQ(ierr);
6594   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6595   ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
6596   ierr = VecCreate(PETSC_COMM_SELF, &coordinatesNew);CHKERRQ(ierr);
6597   ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
6598   ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
6599   ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr);
6600   ierr = VecSetBlockSize(coordinatesNew, bs);CHKERRQ(ierr);
6601   ierr = VecGetType(coordinates, &vtype);CHKERRQ(ierr);
6602   ierr = VecSetType(coordinatesNew, vtype);CHKERRQ(ierr);
6603   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
6604   ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6605 
6606   switch (refiner) {
6607   case REFINER_NOOP: break;
6608   case REFINER_SIMPLEX_TO_HEX_3D:
6609   case REFINER_HEX_3D:
6610   case REFINER_HYBRID_HEX_3D:
6611     /* Face vertices have the average of corner coordinates */
6612     for (f = fStart; f < fMax; ++f) {
6613       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
6614       PetscInt      *cone = NULL;
6615       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
6616 
6617       ierr = DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6618       for (p = 0; p < closureSize*2; p += 2) {
6619         const PetscInt point = cone[p];
6620         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
6621       }
6622       if (localize) {
6623         const PetscInt *support = NULL;
6624         PetscInt       *rStar = NULL;
6625         PetscInt        supportSize, rStarSize, coff, s, ccoff[8];
6626         PetscBool       cellfound = PETSC_FALSE;
6627 
6628         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
6629         ierr = DMPlexGetSupportSize(dm,f,&supportSize);CHKERRQ(ierr);
6630         ierr = DMPlexGetSupport(dm,f,&support);CHKERRQ(ierr);
6631         /* Compute average of coordinates for each cell sharing the face */
6632         for (s = 0; s < supportSize; ++s) {
6633           PetscScalar     coordsNewAux[3] = { 0.0, 0.0, 0.0 };
6634           PetscInt       *cellCone = NULL;
6635           PetscInt        cellClosureSize, cellConeSize = 0, cdof;
6636           const PetscInt  cell = support[s];
6637           PetscBool       copyoff = PETSC_FALSE;
6638 
6639           ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
6640           for (p = 0; p < cellClosureSize*2; p += 2) {
6641             const PetscInt point = cellCone[p];
6642             if ((point >= vStart) && (point < vEnd)) cellCone[cellConeSize++] = point;
6643           }
6644           ierr = PetscSectionGetDof(coordSection, cell, &cdof);CHKERRQ(ierr);
6645           if (!cdof) { /* the parent cell does not have localized coordinates */
6646             cellfound = PETSC_TRUE;
6647             for (v = 0; v < coneSize; ++v) {
6648               ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
6649               for (d = 0; d < spaceDim; ++d) coordsNewAux[d] += coords[off[v]+d];
6650             }
6651             for (d = 0; d < spaceDim; ++d) coordsNewAux[d] /= coneSize;
6652           } else {
6653             ierr = PetscSectionGetOffset(coordSection, cell, &coff);CHKERRQ(ierr);
6654             for (p = 0; p < coneSize; ++p) {
6655               const PetscInt tv = cone[p];
6656               PetscInt       cv, voff;
6657               PetscBool      locv = PETSC_TRUE;
6658 
6659               for (cv = 0; cv < cellConeSize; ++cv) {
6660                 if (cellCone[cv] == tv) {
6661                   ccoff[p] = spaceDim*cv + coff;
6662                   break;
6663                 }
6664               }
6665               if (cv == cellConeSize) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map vertex %D\n",tv);
6666 
6667               ierr = PetscSectionGetOffset(coordSection, cone[p], &voff);CHKERRQ(ierr);
6668               for (d = 0; d < spaceDim; ++d) {
6669                 coordsNewAux[d] += coords[ccoff[p]+d];
6670                 if (!cellfound && coords[voff+d] != coords[ccoff[p]+d]) locv = PETSC_FALSE;
6671               }
6672               if (locv && !cellfound) {
6673                 cellfound = PETSC_TRUE;
6674                 copyoff   = PETSC_TRUE;
6675               }
6676             }
6677             for (d = 0; d < spaceDim; ++d) coordsNewAux[d] /= coneSize;
6678 
6679             /* Found a valid face for the "vertex" part of the Section (physical space)
6680                i.e., a face that has at least one corner in the physical space */
6681             if (copyoff) for (p = 0; p < coneSize; ++p) off[p] = ccoff[p];
6682           }
6683 
6684           /* Localize new coordinates on each refined cell */
6685           for (v = 0; v < rStarSize*2; v += 2) {
6686             if ((rStar[v] >= cStartNew) && (rStar[v] < cEndNew) && parentId[rStar[v]-cStartNew] == cell) {
6687               PetscInt       *rcone = NULL, rclosureSize, lid, rcdof, rcoff;
6688               const PetscInt  rcell = rStar[v];
6689 
6690               ierr = PetscSectionGetDof(coordSectionNew, rcell, &rcdof);CHKERRQ(ierr);
6691               if (!rcdof) continue;
6692               ierr = PetscSectionGetOffset(coordSectionNew, rcell, &rcoff);CHKERRQ(ierr);
6693               ierr = DMPlexGetTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
6694               for (p = 0, lid = 0; p < rclosureSize*2; p += 2) {
6695                 if (rcone[p] == newv) {
6696                   for (d = 0; d < spaceDim; d++) coordsNew[rcoff + lid*spaceDim + d] = coordsNewAux[d];
6697                   break;
6698                 }
6699                 if (rcone[p] >= vStartNew && rcone[p] < vEndNew) lid++;
6700               }
6701               ierr = DMPlexRestoreTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
6702               if (p == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
6703             }
6704           }
6705           ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
6706         }
6707         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
6708         if (!cellfound) {
6709           /* Could not find a valid face for the vertex part, we will get this vertex later (final reduction) */
6710           needcoords = PETSC_TRUE;
6711           coneSize   = 0;
6712         }
6713       } else {
6714         for (v = 0; v < coneSize; ++v) {
6715           ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
6716         }
6717       }
6718       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6719       if (coneSize) {
6720         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
6721         for (v = 0; v < coneSize; ++v) {ierr = DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);CHKERRQ(ierr);}
6722         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
6723       } else {
6724         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = PETSC_MIN_REAL;
6725       }
6726       ierr = DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6727     }
6728   case REFINER_SIMPLEX_TO_HEX_2D:
6729   case REFINER_HEX_2D:
6730   case REFINER_HYBRID_HEX_2D:
6731   case REFINER_SIMPLEX_1D:
6732     /* Cell vertices have the average of corner coordinates */
6733     for (c = cStart; c < cMax; ++c) {
6734       const PetscInt newv = vStartNew + (vEnd - vStart) + (dim > 1 ? (eMax - eStart) : 0) + (c - cStart) + (dim > 2 ? (fMax - fStart) : 0);
6735       PetscInt      *cone = NULL;
6736       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d, cdof = 0;
6737 
6738       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6739       for (p = 0; p < closureSize*2; p += 2) {
6740         const PetscInt point = cone[p];
6741         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
6742       }
6743       if (localize) {
6744         ierr = PetscSectionGetDof(coordSection, c, &cdof);CHKERRQ(ierr);
6745       }
6746       if (cdof) {
6747         PetscInt coff;
6748 
6749         ierr = PetscSectionGetOffset(coordSection, c, &coff);CHKERRQ(ierr);
6750         for (v = 0; v < coneSize; ++v) off[v] = spaceDim*v + coff;
6751       } else {
6752         for (v = 0; v < coneSize; ++v) {
6753           ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
6754         }
6755       }
6756       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6757       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
6758       for (v = 0; v < coneSize; ++v) {ierr = DMLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);CHKERRQ(ierr);}
6759       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
6760       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6761 
6762       /* Localize new coordinates on each refined cell */
6763       if (cdof) {
6764         PetscInt *rStar = NULL, rStarSize;
6765 
6766         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
6767         for (v = 0; v < rStarSize*2; v += 2) {
6768           if ((rStar[v] >= cStartNew) && (rStar[v] < cEndNew)) {
6769             PetscInt *cone = NULL, closureSize, lid, coff, rc, rcdof;
6770 
6771             rc   = rStar[v];
6772             ierr = PetscSectionGetDof(coordSectionNew, rc, &rcdof);CHKERRQ(ierr);
6773             if (!rcdof) continue;
6774             ierr = PetscSectionGetOffset(coordSectionNew, rc, &coff);CHKERRQ(ierr);
6775             ierr = DMPlexGetTransitiveClosure(rdm, rc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6776             for (p = 0, lid = 0; p < closureSize*2; p += 2) {
6777               if (cone[p] == newv) {
6778                 for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = coordsNew[offnew + d];
6779                 break;
6780               }
6781               if (cone[p] >= vStartNew && cone[p] < vEndNew) lid++;
6782             }
6783             if (p == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
6784             ierr = DMPlexRestoreTransitiveClosure(rdm, rc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6785           }
6786         }
6787         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
6788       }
6789     }
6790   case REFINER_SIMPLEX_2D:
6791   case REFINER_HYBRID_SIMPLEX_2D:
6792   case REFINER_SIMPLEX_3D:
6793   case REFINER_HYBRID_SIMPLEX_3D:
6794     /* Edge vertices have the average of endpoint coordinates */
6795     for (e = eStart; e < eMax; ++e) {
6796       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
6797       const PetscInt *cone;
6798       PetscInt        coneSize, offA, offB, offnew, d;
6799 
6800       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
6801       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
6802       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
6803       if (localize) {
6804         PetscInt   coff, toffA = -1, toffB = -1, voffA, voffB;
6805         PetscInt  *eStar = NULL, eStarSize;
6806         PetscInt  *rStar = NULL, rStarSize;
6807         PetscBool  cellfound = PETSC_FALSE;
6808 
6809         offA = offB = -1;
6810         ierr = PetscSectionGetOffset(coordSection, cone[0], &voffA);CHKERRQ(ierr);
6811         ierr = PetscSectionGetOffset(coordSection, cone[1], &voffB);CHKERRQ(ierr);
6812         ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &eStarSize, &eStar);CHKERRQ(ierr);
6813         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
6814         for (v = 0; v < eStarSize*2; v += 2) {
6815           if ((eStar[v] >= cStart) && (eStar[v] < cEnd)) {
6816             PetscScalar     coordsNewAux[3];
6817             PetscInt       *cellCone = NULL;
6818             PetscInt        cellClosureSize, s, cv, cdof;
6819             PetscBool       locvA = PETSC_TRUE, locvB = PETSC_TRUE;
6820             const PetscInt  cell = eStar[v];
6821 
6822             ierr = PetscSectionGetDof(coordSection, cell, &cdof);CHKERRQ(ierr);
6823             if (!cdof) {
6824               /* Found a valid edge for the "vertex" part of the Section */
6825               offA = voffA;
6826               offB = voffB;
6827               cellfound = PETSC_TRUE;
6828             } else {
6829               ierr = PetscSectionGetOffset(coordSection, cell, &coff);CHKERRQ(ierr);
6830               ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
6831               for (s = 0, cv = 0; s < cellClosureSize*2; s += 2) {
6832                 const PetscInt point = cellCone[s];
6833                 if ((point >= vStart) && (point < vEnd)) {
6834                   if (point == cone[0]) toffA = spaceDim*cv + coff;
6835                   else if (point == cone[1]) toffB = spaceDim*cv + coff;
6836                   cv++;
6837                 }
6838               }
6839               ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &cellClosureSize, &cellCone);CHKERRQ(ierr);
6840               for (d = 0; d < spaceDim; ++d) {
6841                 coordsNewAux[d] = 0.5*(coords[toffA+d] + coords[toffB+d]);
6842                 if (coords[toffA+d] != coords[voffA+d]) locvA = PETSC_FALSE;
6843                 if (coords[toffB+d] != coords[voffB+d]) locvB = PETSC_FALSE;
6844               }
6845               /* Found a valid edge for the "vertex" part of the Section */
6846               if (!cellfound && (locvA || locvB)) {
6847                 cellfound = PETSC_TRUE;
6848                 offA = toffA;
6849                 offB = toffB;
6850               }
6851             }
6852 
6853             /* Localize new coordinates on each refined cell */
6854             for (s = 0; s < rStarSize*2; s += 2) {
6855               if ((rStar[s] >= cStartNew) && (rStar[s] < cEndNew) && parentId[rStar[s]-cStartNew] == cell) {
6856                 PetscInt       *rcone = NULL, rclosureSize, lid, p, rcdof;
6857                 const PetscInt  rcell = rStar[s];
6858 
6859                 ierr = PetscSectionGetDof(coordSectionNew, rcell, &rcdof);CHKERRQ(ierr);
6860                 if (!rcdof) continue;
6861                 ierr = PetscSectionGetOffset(coordSectionNew, rcell, &coff);CHKERRQ(ierr);
6862                 ierr = DMPlexGetTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
6863                 for (p = 0, lid = 0; p < rclosureSize*2; p += 2) {
6864                   if (rcone[p] == newv) {
6865                     for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = coordsNewAux[d];
6866                     break;
6867                   }
6868                   if (rcone[p] >= vStartNew && rcone[p] < vEndNew) lid++;
6869                 }
6870                 ierr = DMPlexRestoreTransitiveClosure(rdm, rcell, PETSC_TRUE, &rclosureSize, &rcone);CHKERRQ(ierr);
6871                 if (p == rclosureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
6872               }
6873             }
6874           }
6875         }
6876         ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &eStarSize, &eStar);CHKERRQ(ierr);
6877         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
6878         if (!cellfound) {
6879           /* Could not find a valid edge for the vertex part, we will get this vertex later (final reduction) */
6880           needcoords = PETSC_TRUE;
6881         }
6882       } else {
6883         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6884         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6885       }
6886       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6887       if (offA != -1 && offB != -1) {
6888         ierr = DMLocalizeCoordinate_Internal(dm, spaceDim, &coords[offA], &coords[offB], &coordsNew[offnew]);CHKERRQ(ierr);
6889         for (d = 0; d < spaceDim; ++d) {
6890           coordsNew[offnew+d] = 0.5*(coords[offA+d] + coordsNew[offnew+d]);
6891         }
6892       } else {
6893         for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = PETSC_MIN_REAL;
6894       }
6895     }
6896     /* Old vertices have the same coordinates */
6897     for (v = vStart; v < vEnd; ++v) {
6898       const PetscInt newv = vStartNew + (v - vStart);
6899       PetscInt       off, offnew, d;
6900 
6901       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6902       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6903       for (d = 0; d < spaceDim; ++d) {
6904         coordsNew[offnew+d] = coords[off+d];
6905       }
6906 
6907       /* Localize new coordinates on each refined cell */
6908       if (localize) {
6909         PetscInt  p;
6910         PetscInt *rStar = NULL, rStarSize;
6911 
6912         ierr = DMPlexGetTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
6913         for (p = 0; p < rStarSize*2; p += 2) {
6914           if ((rStar[p] >= cStartNew) && (rStar[p] < cEndNew)) {
6915             PetscScalar  ocoords[3];
6916             PetscInt    *cone = NULL, closureSize, lid, coff, s, oc, cdof;
6917 
6918             c    = rStar[p];
6919             oc   = parentId[c-cStartNew];
6920             ierr = PetscSectionGetDof(coordSectionNew, c, &cdof);CHKERRQ(ierr);
6921             if (!cdof) continue;
6922             ierr = PetscSectionGetDof(coordSection, oc, &cdof);CHKERRQ(ierr);
6923             if (!cdof) continue;
6924             ierr = PetscSectionGetOffset(coordSection, oc, &coff);CHKERRQ(ierr);
6925             ierr = DMPlexGetTransitiveClosure(dm, oc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6926             for (s = 0, lid = 0; s < closureSize*2; s += 2) {
6927               if (cone[s] == v) {
6928                 for (d = 0; d < spaceDim; d++) ocoords[d] = coords[coff + lid*spaceDim + d];
6929                 break;
6930               }
6931               if (cone[s] >= vStart && cone[s] < vEnd) lid++;
6932             }
6933             if (s == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map old vertex %D\n",v);
6934             ierr = DMPlexRestoreTransitiveClosure(dm, oc, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6935 
6936             ierr = PetscSectionGetOffset(coordSectionNew, c, &coff);CHKERRQ(ierr);
6937             ierr = DMPlexGetTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6938             for (s = 0, lid = 0; s < closureSize*2; s += 2) {
6939               if (cone[s] == newv) {
6940                 for (d = 0; d < spaceDim; d++) coordsNew[coff + lid*spaceDim + d] = ocoords[d];
6941                 break;
6942               }
6943               if (cone[s] >= vStartNew && cone[s] < vEndNew) lid++;
6944             }
6945             if (s == closureSize*2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unable to map new vertex %D\n",newv);
6946             ierr = DMPlexRestoreTransitiveClosure(rdm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6947           }
6948         }
6949         ierr = DMPlexRestoreTransitiveClosure(rdm, newv, PETSC_FALSE, &rStarSize, &rStar);CHKERRQ(ierr);
6950       }
6951     }
6952     break;
6953   default:
6954     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6955   }
6956   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
6957   ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6958   ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
6959 
6960   /* Final reduction (if needed) if we are localizing */
6961   if (localize) {
6962     PetscBool gred;
6963 
6964     ierr = MPIU_Allreduce(&needcoords, &gred, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)rdm));CHKERRQ(ierr);
6965     if (gred) {
6966       DM                 cdm;
6967       Vec                aux;
6968       PetscSF            sf;
6969       const PetscScalar *lArray;
6970       PetscScalar       *gArray;
6971 
6972       ierr = DMGetCoordinateDM(rdm, &cdm);CHKERRQ(ierr);
6973       ierr = DMCreateGlobalVector(cdm, &aux);CHKERRQ(ierr);
6974       ierr = DMGetDefaultSF(cdm, &sf);CHKERRQ(ierr);
6975       ierr = VecGetArrayRead(coordinatesNew, &lArray);CHKERRQ(ierr);
6976       ierr = VecSet(aux, PETSC_MIN_REAL);CHKERRQ(ierr);
6977       ierr = VecGetArray(aux, &gArray);CHKERRQ(ierr);
6978       ierr = PetscSFReduceBegin(sf, MPIU_SCALAR, lArray, gArray, MPIU_MAX);CHKERRQ(ierr);
6979       ierr = PetscSFReduceEnd(sf, MPIU_SCALAR, lArray, gArray, MPIU_MAX);CHKERRQ(ierr);
6980       ierr = VecRestoreArrayRead(coordinatesNew, &lArray);CHKERRQ(ierr);
6981       ierr = VecRestoreArray(aux, &gArray);CHKERRQ(ierr);
6982       ierr = DMGlobalToLocalBegin(cdm, aux, INSERT_VALUES, coordinatesNew);CHKERRQ(ierr);
6983       ierr = DMGlobalToLocalEnd(cdm, aux, INSERT_VALUES, coordinatesNew);CHKERRQ(ierr);
6984       ierr = VecDestroy(&aux);CHKERRQ(ierr);
6985     }
6986   }
6987   ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
6988   ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
6989   ierr = PetscFree(parentId);CHKERRQ(ierr);
6990   PetscFunctionReturn(0);
6991 }
6992 
6993 /*@
6994   DMPlexCreateProcessSF - Create an SF which just has process connectivity
6995 
6996   Collective on DM
6997 
6998   Input Parameters:
6999 + dm      - The DM
7000 - sfPoint - The PetscSF which encodes point connectivity
7001 
7002   Output Parameters:
7003 + processRanks - A list of process neighbors, or NULL
7004 - sfProcess    - An SF encoding the process connectivity, or NULL
7005 
7006   Level: developer
7007 
7008 .seealso: PetscSFCreate(), DMPlexCreateTwoSidedProcessSF()
7009 @*/
7010 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
7011 {
7012   PetscInt           numRoots, numLeaves, l;
7013   const PetscInt    *localPoints;
7014   const PetscSFNode *remotePoints;
7015   PetscInt          *localPointsNew;
7016   PetscSFNode       *remotePointsNew;
7017   PetscInt          *ranks, *ranksNew;
7018   PetscMPIInt        size;
7019   PetscErrorCode     ierr;
7020 
7021   PetscFunctionBegin;
7022   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7023   PetscValidHeaderSpecific(sfPoint, PETSCSF_CLASSID, 2);
7024   if (processRanks) {PetscValidPointer(processRanks, 3);}
7025   if (sfProcess)    {PetscValidPointer(sfProcess, 4);}
7026   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) dm), &size);CHKERRQ(ierr);
7027   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
7028   ierr = PetscMalloc1(numLeaves, &ranks);CHKERRQ(ierr);
7029   for (l = 0; l < numLeaves; ++l) {
7030     ranks[l] = remotePoints[l].rank;
7031   }
7032   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
7033   ierr = PetscMalloc1(numLeaves, &ranksNew);CHKERRQ(ierr);
7034   ierr = PetscMalloc1(numLeaves, &localPointsNew);CHKERRQ(ierr);
7035   ierr = PetscMalloc1(numLeaves, &remotePointsNew);CHKERRQ(ierr);
7036   for (l = 0; l < numLeaves; ++l) {
7037     ranksNew[l]              = ranks[l];
7038     localPointsNew[l]        = l;
7039     remotePointsNew[l].index = 0;
7040     remotePointsNew[l].rank  = ranksNew[l];
7041   }
7042   ierr = PetscFree(ranks);CHKERRQ(ierr);
7043   if (processRanks) {ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);}
7044   else              {ierr = PetscFree(ranksNew);CHKERRQ(ierr);}
7045   if (sfProcess) {
7046     ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
7047     ierr = PetscObjectSetName((PetscObject) *sfProcess, "Process SF");CHKERRQ(ierr);
7048     ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
7049     ierr = PetscSFSetGraph(*sfProcess, size, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7050   }
7051   PetscFunctionReturn(0);
7052 }
7053 
7054 static PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7055 {
7056   PetscSF            sf, sfNew, sfProcess;
7057   IS                 processRanks;
7058   MPI_Datatype       depthType;
7059   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
7060   const PetscInt    *localPoints, *neighbors;
7061   const PetscSFNode *remotePoints;
7062   PetscInt          *localPointsNew;
7063   PetscSFNode       *remotePointsNew;
7064   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
7065   PetscInt           ldepth, depth, numNeighbors, pStartNew, pEndNew, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r, n;
7066   PetscInt           cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
7067   PetscErrorCode     ierr;
7068 
7069   PetscFunctionBegin;
7070   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
7071   ierr = DMPlexGetDepth(dm, &ldepth);CHKERRQ(ierr);
7072   ierr = MPIU_Allreduce(&ldepth, &depth, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
7073   if ((ldepth >= 0) && (depth != ldepth)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Inconsistent Plex depth %d != %d", ldepth, depth);
7074   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7075   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7076   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7077   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7078   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7079   cMax = cMax < 0 ? cEnd : cMax;
7080   fMax = fMax < 0 ? fEnd : fMax;
7081   eMax = eMax < 0 ? eEnd : eMax;
7082   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
7083   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
7084   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
7085   /* Calculate size of new SF */
7086   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
7087   if (numRoots < 0) PetscFunctionReturn(0);
7088   for (l = 0; l < numLeaves; ++l) {
7089     const PetscInt p = localPoints[l];
7090 
7091     switch (refiner) {
7092     case REFINER_SIMPLEX_1D:
7093       if ((p >= vStart) && (p < vEnd)) {
7094         /* Interior vertices stay the same */
7095         ++numLeavesNew;
7096       } else if ((p >= cStart && p < cMax)) {
7097         /* Interior cells add new cells and interior vertices */
7098         numLeavesNew += 2 + 1;
7099       }
7100       break;
7101     case REFINER_SIMPLEX_2D:
7102     case REFINER_HYBRID_SIMPLEX_2D:
7103       if ((p >= vStart) && (p < vEnd)) {
7104         /* Interior vertices stay the same */
7105         ++numLeavesNew;
7106       } else if ((p >= fStart) && (p < fMax)) {
7107         /* Interior faces add new faces and vertex */
7108         numLeavesNew += 2 + 1;
7109       } else if ((p >= fMax) && (p < fEnd)) {
7110         /* Hybrid faces stay the same */
7111         ++numLeavesNew;
7112       } else if ((p >= cStart) && (p < cMax)) {
7113         /* Interior cells add new cells and interior faces */
7114         numLeavesNew += 4 + 3;
7115       } else if ((p >= cMax) && (p < cEnd)) {
7116         /* Hybrid cells add new cells and hybrid face */
7117         numLeavesNew += 2 + 1;
7118       }
7119       break;
7120     case REFINER_SIMPLEX_TO_HEX_2D:
7121       if ((p >= vStart) && (p < vEnd)) {
7122         /* Interior vertices stay the same */
7123         ++numLeavesNew;
7124       } else if ((p >= fStart) && (p < fEnd)) {
7125         /* Interior faces add new faces and vertex */
7126         numLeavesNew += 2 + 1;
7127       } else if ((p >= cStart) && (p < cEnd)) {
7128         /* Interior cells add new cells, interior faces, and vertex */
7129         numLeavesNew += 3 + 3 + 1;
7130       }
7131       break;
7132     case REFINER_HEX_2D:
7133     case REFINER_HYBRID_HEX_2D:
7134       if ((p >= vStart) && (p < vEnd)) {
7135         /* Interior vertices stay the same */
7136         ++numLeavesNew;
7137       } else if ((p >= fStart) && (p < fMax)) {
7138         /* Interior faces add new faces and vertex */
7139         numLeavesNew += 2 + 1;
7140       } else if ((p >= fMax) && (p < fEnd)) {
7141         /* Hybrid faces stay the same */
7142         ++numLeavesNew;
7143       } else if ((p >= cStart) && (p < cMax)) {
7144         /* Interior cells add new cells, interior faces, and vertex */
7145         numLeavesNew += 4 + 4 + 1;
7146       } else if ((p >= cMax) && (p < cEnd)) {
7147         /* Hybrid cells add new cells and hybrid face */
7148         numLeavesNew += 2 + 1;
7149       }
7150       break;
7151     case REFINER_SIMPLEX_3D:
7152     case REFINER_HYBRID_SIMPLEX_3D:
7153       if ((p >= vStart) && (p < vEnd)) {
7154         /* Interior vertices stay the same */
7155         ++numLeavesNew;
7156       } else if ((p >= eStart) && (p < eMax)) {
7157         /* Interior edges add new edges and vertex */
7158         numLeavesNew += 2 + 1;
7159       } else if ((p >= eMax) && (p < eEnd)) {
7160         /* Hybrid edges stay the same */
7161         ++numLeavesNew;
7162       } else if ((p >= fStart) && (p < fMax)) {
7163         /* Interior faces add new faces and edges */
7164         numLeavesNew += 4 + 3;
7165       } else if ((p >= fMax) && (p < fEnd)) {
7166         /* Hybrid faces add new faces and edges */
7167         numLeavesNew += 2 + 1;
7168       } else if ((p >= cStart) && (p < cMax)) {
7169         /* Interior cells add new cells, faces, and edges */
7170         numLeavesNew += 8 + 8 + 1;
7171       } else if ((p >= cMax) && (p < cEnd)) {
7172         /* Hybrid cells add new cells and faces */
7173         numLeavesNew += 4 + 3;
7174       }
7175       break;
7176     case REFINER_SIMPLEX_TO_HEX_3D:
7177       if ((p >= vStart) && (p < vEnd)) {
7178         /* Interior vertices stay the same */
7179         ++numLeavesNew;
7180       } else if ((p >= eStart) && (p < eEnd)) {
7181         /* Interior edges add new edges and vertex */
7182         numLeavesNew += 2 + 1;
7183       } else if ((p >= fStart) && (p < fEnd)) {
7184         /* Interior faces add new faces, edges and a vertex */
7185         numLeavesNew += 3 + 3 + 1;
7186       } else if ((p >= cStart) && (p < cEnd)) {
7187         /* Interior cells add new cells, faces, edges and a vertex */
7188         numLeavesNew += 4 + 6 + 4 + 1;
7189       }
7190       break;
7191     case REFINER_HEX_3D:
7192     case REFINER_HYBRID_HEX_3D:
7193       if ((p >= vStart) && (p < vEnd)) {
7194         /* Old vertices stay the same */
7195         ++numLeavesNew;
7196       } else if ((p >= eStart) && (p < eMax)) {
7197         /* Interior edges add new edges, and vertex */
7198         numLeavesNew += 2 + 1;
7199       } else if ((p >= eMax) && (p < eEnd)) {
7200         /* Hybrid edges stay the same */
7201         ++numLeavesNew;
7202       } else if ((p >= fStart) && (p < fMax)) {
7203         /* Interior faces add new faces, edges, and vertex */
7204         numLeavesNew += 4 + 4 + 1;
7205       } else if ((p >= fMax) && (p < fEnd)) {
7206         /* Hybrid faces add new faces and edges */
7207         numLeavesNew += 2 + 1;
7208       } else if ((p >= cStart) && (p < cMax)) {
7209         /* Interior cells add new cells, faces, edges, and vertex */
7210         numLeavesNew += 8 + 12 + 6 + 1;
7211       } else if ((p >= cStart) && (p < cEnd)) {
7212         /* Hybrid cells add new cells, faces, and edges */
7213         numLeavesNew += 4 + 4 + 1;
7214       }
7215       break;
7216     default:
7217       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7218     }
7219   }
7220   /* Communicate depthSizes for each remote rank */
7221   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
7222   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
7223   ierr = PetscMalloc5((depth+1)*numNeighbors,&rdepthSize,numNeighbors,&rvStartNew,numNeighbors,&reStartNew,numNeighbors,&rfStartNew,numNeighbors,&rcStartNew);CHKERRQ(ierr);
7224   ierr = PetscMalloc7(depth+1,&depthSizeOld,(depth+1)*numNeighbors,&rdepthSizeOld,(depth+1)*numNeighbors,&rdepthMaxOld,numNeighbors,&rvStart,numNeighbors,&reStart,numNeighbors,&rfStart,numNeighbors,&rcStart);CHKERRQ(ierr);
7225   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
7226   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
7227   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7228   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7229   for (n = 0; n < numNeighbors; ++n) {
7230     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
7231   }
7232   depthSizeOld[depth]   = cMax;
7233   depthSizeOld[0]       = vMax;
7234   depthSizeOld[depth-1] = fMax;
7235   depthSizeOld[1]       = eMax;
7236 
7237   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7238   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7239 
7240   depthSizeOld[depth]   = cEnd - cStart;
7241   depthSizeOld[0]       = vEnd - vStart;
7242   depthSizeOld[depth-1] = fEnd - fStart;
7243   depthSizeOld[1]       = eEnd - eStart;
7244 
7245   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7246   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7247   for (n = 0; n < numNeighbors; ++n) {
7248     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
7249     rdepthMaxOld[n*(depth+1)+depth]   = rdepthMaxOld[n*(depth+1)+depth]   < 0 ? rdepthSizeOld[n*(depth+1)+depth]  +rcStart[n]: rdepthMaxOld[n*(depth+1)+depth];
7250     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];
7251     rdepthMaxOld[n*(depth+1)+1]       = rdepthMaxOld[n*(depth+1)+1]       < 0 ? rdepthSizeOld[n*(depth+1)+1]      +reStart[n]: rdepthMaxOld[n*(depth+1)+1];
7252   }
7253   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
7254   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
7255   /* Calculate new point SF */
7256   ierr = PetscMalloc1(numLeavesNew, &localPointsNew);CHKERRQ(ierr);
7257   ierr = PetscMalloc1(numLeavesNew, &remotePointsNew);CHKERRQ(ierr);
7258   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
7259   for (l = 0, m = 0; l < numLeaves; ++l) {
7260     PetscInt    p     = localPoints[l];
7261     PetscInt    rp    = remotePoints[l].index, n;
7262     PetscMPIInt rrank = remotePoints[l].rank;
7263 
7264     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
7265     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
7266     switch (refiner) {
7267     case REFINER_SIMPLEX_1D:
7268       if ((p >= vStart) && (p < vEnd)) {
7269         /* Old vertices stay the same */
7270         localPointsNew[m]        = vStartNew     + (p  - vStart);
7271         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7272         remotePointsNew[m].rank  = rrank;
7273         ++m;
7274       } else if ((p >= cStart) && (p < cMax)) {
7275         /* Old interior cells add new cells and vertex */
7276         for (r = 0; r < 2; ++r, ++m) {
7277           localPointsNew[m]        = cStartNew     + (p  - cStart)*2     + r;
7278           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*2 + r;
7279           remotePointsNew[m].rank  = rrank;
7280         }
7281         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - cStart);
7282         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rcStart[n]);
7283         remotePointsNew[m].rank  = rrank;
7284         ++m;
7285       }
7286       break;
7287     case REFINER_SIMPLEX_2D:
7288     case REFINER_HYBRID_SIMPLEX_2D:
7289       if ((p >= vStart) && (p < vEnd)) {
7290         /* Old vertices stay the same */
7291         localPointsNew[m]        = vStartNew     + (p  - vStart);
7292         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7293         remotePointsNew[m].rank  = rrank;
7294         ++m;
7295       } else if ((p >= fStart) && (p < fMax)) {
7296         /* Old interior faces add new faces and vertex */
7297         for (r = 0; r < 2; ++r, ++m) {
7298           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7299           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7300           remotePointsNew[m].rank  = rrank;
7301         }
7302         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7303         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7304         remotePointsNew[m].rank  = rrank;
7305         ++m;
7306       } else if ((p >= fMax) && (p < fEnd)) {
7307         /* Old hybrid faces stay the same */
7308         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
7309         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
7310         remotePointsNew[m].rank  = rrank;
7311         ++m;
7312       } else if ((p >= cStart) && (p < cMax)) {
7313         /* Old interior cells add new cells and interior faces */
7314         for (r = 0; r < 4; ++r, ++m) {
7315           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7316           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7317           remotePointsNew[m].rank  = rrank;
7318         }
7319         for (r = 0; r < 3; ++r, ++m) {
7320           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
7321           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
7322           remotePointsNew[m].rank  = rrank;
7323         }
7324       } else if ((p >= cMax) && (p < cEnd)) {
7325         /* Old hybrid cells add new cells and hybrid face */
7326         for (r = 0; r < 2; ++r, ++m) {
7327           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7328           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7329           remotePointsNew[m].rank  = rrank;
7330         }
7331         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
7332         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]);
7333         remotePointsNew[m].rank  = rrank;
7334         ++m;
7335       }
7336       break;
7337     case REFINER_SIMPLEX_TO_HEX_2D:
7338       if ((p >= vStart) && (p < vEnd)) {
7339         /* Old vertices stay the same */
7340         localPointsNew[m]        = vStartNew     + (p  - vStart);
7341         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7342         remotePointsNew[m].rank  = rrank;
7343         ++m;
7344       } else if ((p >= fStart) && (p < fEnd)) {
7345         /* Old interior faces add new faces and vertex */
7346         for (r = 0; r < 2; ++r, ++m) {
7347           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7348           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7349           remotePointsNew[m].rank  = rrank;
7350         }
7351         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7352         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7353         remotePointsNew[m].rank  = rrank;
7354         ++m;
7355       } else if ((p >= cStart) && (p < cEnd)) {
7356         /* Old interior cells add new cells, interior faces, and a vertex */
7357         for (r = 0; r < 3; ++r, ++m) {
7358           localPointsNew[m]        = cStartNew     + (p  - cStart)*3     + r;
7359           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*3 + r;
7360           remotePointsNew[m].rank  = rrank;
7361         }
7362         for (r = 0; r < 3; ++r, ++m) {
7363           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
7364           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
7365           remotePointsNew[m].rank  = rrank;
7366         }
7367         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (fEnd - fStart)                    + (p  - cStart);
7368         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
7369         remotePointsNew[m].rank  = rrank;
7370         ++m;
7371       }
7372       break;
7373     case REFINER_HEX_2D:
7374     case REFINER_HYBRID_HEX_2D:
7375       if ((p >= vStart) && (p < vEnd)) {
7376         /* Old vertices stay the same */
7377         localPointsNew[m]        = vStartNew     + (p  - vStart);
7378         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7379         remotePointsNew[m].rank  = rrank;
7380         ++m;
7381       } else if ((p >= fStart) && (p < fMax)) {
7382         /* Old interior faces add new faces and vertex */
7383         for (r = 0; r < 2; ++r, ++m) {
7384           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7385           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7386           remotePointsNew[m].rank  = rrank;
7387         }
7388         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7389         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7390         remotePointsNew[m].rank  = rrank;
7391         ++m;
7392       } else if ((p >= fMax) && (p < fEnd)) {
7393         /* Old hybrid faces stay the same */
7394         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
7395         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
7396         remotePointsNew[m].rank  = rrank;
7397         ++m;
7398       } else if ((p >= cStart) && (p < cMax)) {
7399         /* Old interior cells add new cells, interior faces, and vertex */
7400         for (r = 0; r < 4; ++r, ++m) {
7401           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7402           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7403           remotePointsNew[m].rank  = rrank;
7404         }
7405         for (r = 0; r < 4; ++r, ++m) {
7406           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*4     + r;
7407           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*4 + r;
7408           remotePointsNew[m].rank  = rrank;
7409         }
7410         localPointsNew[m]        = vStartNew     + (vEnd - vStart)               + (fMax                              - fStart)     + (p  - cStart);
7411         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0]  + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]);
7412         remotePointsNew[m].rank  = rrank;
7413         ++m;
7414       } else if ((p >= cStart) && (p < cMax)) {
7415         /* Old hybrid cells add new cells and hybrid face */
7416         for (r = 0; r < 2; ++r, ++m) {
7417           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7418           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7419           remotePointsNew[m].rank  = rrank;
7420         }
7421         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*4     + (p  - cMax);
7422         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]);
7423         remotePointsNew[m].rank  = rrank;
7424         ++m;
7425       }
7426       break;
7427     case REFINER_SIMPLEX_3D:
7428     case REFINER_HYBRID_SIMPLEX_3D:
7429       if ((p >= vStart) && (p < vEnd)) {
7430         /* Interior vertices stay the same */
7431         localPointsNew[m]        = vStartNew     + (p  - vStart);
7432         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7433         remotePointsNew[m].rank  = rrank;
7434         ++m;
7435       } else if ((p >= eStart) && (p < eMax)) {
7436         /* Interior edges add new edges and vertex */
7437         for (r = 0; r < 2; ++r, ++m) {
7438           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
7439           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
7440           remotePointsNew[m].rank  = rrank;
7441         }
7442         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
7443         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
7444         remotePointsNew[m].rank  = rrank;
7445         ++m;
7446       } else if ((p >= eMax) && (p < eEnd)) {
7447         /* Hybrid edges stay the same */
7448         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - eMax);
7449         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]);
7450         remotePointsNew[m].rank  = rrank;
7451         ++m;
7452       } else if ((p >= fStart) && (p < fMax)) {
7453         /* Interior faces add new faces and edges */
7454         for (r = 0; r < 4; ++r, ++m) {
7455           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
7456           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
7457           remotePointsNew[m].rank  = rrank;
7458         }
7459         for (r = 0; r < 3; ++r, ++m) {
7460           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*3     + r;
7461           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
7462           remotePointsNew[m].rank  = rrank;
7463         }
7464       } else if ((p >= fMax) && (p < fEnd)) {
7465         /* Hybrid faces add new faces and edges */
7466         for (r = 0; r < 2; ++r, ++m) {
7467           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fMax)*2                              + r;
7468           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;
7469           remotePointsNew[m].rank  = rrank;
7470         }
7471         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (eEnd                                    - eMax)                        + (p  - fMax);
7472         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]);
7473         remotePointsNew[m].rank  = rrank;
7474         ++m;
7475       } else if ((p >= cStart) && (p < cMax)) {
7476         /* Interior cells add new cells, faces, and edges */
7477         for (r = 0; r < 8; ++r, ++m) {
7478           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
7479           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
7480           remotePointsNew[m].rank  = rrank;
7481         }
7482         for (r = 0; r < 8; ++r, ++m) {
7483           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*8     + r;
7484           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*8 + r;
7485           remotePointsNew[m].rank  = rrank;
7486         }
7487         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (p  - cStart)*1     + 0;
7488         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;
7489         remotePointsNew[m].rank  = rrank;
7490         ++m;
7491       } else if ((p >= cMax) && (p < cEnd)) {
7492         /* Hybrid cells add new cells and faces */
7493         for (r = 0; r < 4; ++r, ++m) {
7494           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
7495           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
7496           remotePointsNew[m].rank  = rrank;
7497         }
7498         for (r = 0; r < 3; ++r, ++m) {
7499           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*2                              + (p  - cMax)*3                            + r;
7500           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;
7501           remotePointsNew[m].rank  = rrank;
7502         }
7503       }
7504       break;
7505     case REFINER_SIMPLEX_TO_HEX_3D:
7506       if ((p >= vStart) && (p < vEnd)) {
7507         /* Interior vertices stay the same */
7508         localPointsNew[m]        = vStartNew     + (p  - vStart);
7509         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7510         remotePointsNew[m].rank  = rrank;
7511         ++m;
7512       } else if ((p >= eStart) && (p < eEnd)) {
7513         /* Interior edges add new edges and vertex */
7514         for (r = 0; r < 2; ++r, ++m) {
7515           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
7516           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
7517           remotePointsNew[m].rank  = rrank;
7518         }
7519         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
7520         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
7521         remotePointsNew[m].rank  = rrank;
7522         ++m;
7523       } else if ((p >= fStart) && (p < fEnd)) {
7524         /* Interior faces add new faces, edges and a vertex */
7525         for (r = 0; r < 3; ++r, ++m) {
7526           localPointsNew[m]        = fStartNew     + (p  - fStart)*3     + r;
7527           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*3 + r;
7528           remotePointsNew[m].rank  = rrank;
7529         }
7530         for (r = 0; r < 3; ++r, ++m) {
7531           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2                + (p  - fStart)*3     + r;
7532           remotePointsNew[m].index = reStartNew[n] + (rdepthSizeOld[n*(depth+1)+1])*2 + (rp - rfStart[n])*3 + r;
7533           remotePointsNew[m].rank  = rrank;
7534         }
7535         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eEnd - eStart)              + (p - fStart);
7536         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+1] + (rp - rfStart[n]);
7537         remotePointsNew[m].rank  = rrank;
7538         ++m;
7539       } else if ((p >= cStart) && (p < cEnd)) {
7540         /* Interior cells add new cells, faces, edges, and a vertex */
7541         for (r = 0; r < 4; ++r, ++m) {
7542           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7543           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7544           remotePointsNew[m].rank  = rrank;
7545         }
7546         for (r = 0; r < 6; ++r, ++m) {
7547           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*3                    + (p  - cStart)*6     + r;
7548           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*3 + (rp - rcStart[n])*6 + r;
7549           remotePointsNew[m].rank  = rrank;
7550         }
7551         for (r = 0; r < 4; ++r, ++m) {
7552           localPointsNew[m]        = eStartNew     + (eEnd - eStart)*2              + (fEnd - fStart)*3                    + (p  - cStart)*4 + r;
7553           remotePointsNew[m].index = reStartNew[n] + rdepthSizeOld[n*(depth+1)+1]*2 + rdepthSizeOld[n*(depth+1)+depth-1]*3 + (rp - rcStart[n])*4 + r;
7554           remotePointsNew[m].rank  = rrank;
7555         }
7556         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eEnd - eStart)              + (fEnd - fStart)                    + (p - cStart);
7557         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + rdepthSizeOld[n*(depth+1)+1] + rdepthSizeOld[n*(depth+1)+depth-1] + (rp - rcStart[n]);
7558         remotePointsNew[m].rank  = rrank;
7559         ++m;
7560       }
7561       break;
7562     case REFINER_HEX_3D:
7563     case REFINER_HYBRID_HEX_3D:
7564       if ((p >= vStart) && (p < vEnd)) {
7565         /* Interior vertices stay the same */
7566         localPointsNew[m]        = vStartNew     + (p  - vStart);
7567         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7568         remotePointsNew[m].rank  = rrank;
7569         ++m;
7570       } else if ((p >= eStart) && (p < eMax)) {
7571         /* Interior edges add new edges and vertex */
7572         for (r = 0; r < 2; ++r, ++m) {
7573           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
7574           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
7575           remotePointsNew[m].rank  = rrank;
7576         }
7577         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
7578         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
7579         remotePointsNew[m].rank  = rrank;
7580         ++m;
7581       } else if ((p >= eMax) && (p < eEnd)) {
7582         /* Hybrid edges stay the same */
7583         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (p  - eMax);
7584         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]);
7585         remotePointsNew[m].rank  = rrank;
7586         ++m;
7587       } else if ((p >= fStart) && (p < fMax)) {
7588         /* Interior faces add new faces, edges, and vertex */
7589         for (r = 0; r < 4; ++r, ++m) {
7590           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
7591           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
7592           remotePointsNew[m].rank  = rrank;
7593         }
7594         for (r = 0; r < 4; ++r, ++m) {
7595           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*4     + r;
7596           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*4 + r;
7597           remotePointsNew[m].rank  = rrank;
7598         }
7599         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax                        - eStart)     + (p  - fStart);
7600         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
7601         remotePointsNew[m].rank  = rrank;
7602         ++m;
7603       } else if ((p >= fMax) && (p < fEnd)) {
7604         /* Hybrid faces add new faces and edges */
7605         for (r = 0; r < 2; ++r, ++m) {
7606           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (p  - fMax)*2                              + r;
7607           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;
7608           remotePointsNew[m].rank  = rrank;
7609         }
7610         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (p  - fMax);
7611         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]);
7612         remotePointsNew[m].rank  = rrank;
7613         ++m;
7614       } else if ((p >= cStart) && (p < cMax)) {
7615         /* Interior cells add new cells, faces, edges, and vertex */
7616         for (r = 0; r < 8; ++r, ++m) {
7617           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
7618           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
7619           remotePointsNew[m].rank  = rrank;
7620         }
7621         for (r = 0; r < 12; ++r, ++m) {
7622           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*12     + r;
7623           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*12 + r;
7624           remotePointsNew[m].rank  = rrank;
7625         }
7626         for (r = 0; r < 6; ++r, ++m) {
7627           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (p  - cStart)*6     + r;
7628           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;
7629           remotePointsNew[m].rank  = rrank;
7630         }
7631         for (r = 0; r < 1; ++r, ++m) {
7632           localPointsNew[m]        = vStartNew     + (eMax                        - eStart)     + (fMax                              - fStart)     + (p  - cStart)     + r;
7633           remotePointsNew[m].index = rvStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]) + r;
7634           remotePointsNew[m].rank  = rrank;
7635         }
7636       } else if ((p >= cMax) && (p < cEnd)) {
7637         /* Hybrid cells add new cells, faces, and edges */
7638         for (r = 0; r < 4; ++r, ++m) {
7639           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
7640           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
7641           remotePointsNew[m].rank  = rrank;
7642         }
7643         for (r = 0; r < 4; ++r, ++m) {
7644           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (fEnd                                          - fMax)*2                              + (p  - cMax)*4                            + r;
7645           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;
7646           remotePointsNew[m].rank  = rrank;
7647         }
7648         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (fEnd                                          - fMax)                              + (p  - cMax);
7649         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]);
7650         remotePointsNew[m].rank  = rrank;
7651         ++m;
7652       }
7653       break;
7654     default:
7655       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7656     }
7657   }
7658   if (m != numLeavesNew) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of leaf point %d should be %d", m, numLeavesNew);
7659   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
7660   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
7661   {
7662     PetscSFNode *rp, *rtmp;
7663     PetscInt    *lp, *idx, *ltmp, i;
7664 
7665     /* SF needs sorted leaves to correct calculate Gather */
7666     ierr = PetscMalloc1(numLeavesNew,&idx);CHKERRQ(ierr);
7667     ierr = PetscMalloc1(numLeavesNew, &lp);CHKERRQ(ierr);
7668     ierr = PetscMalloc1(numLeavesNew, &rp);CHKERRQ(ierr);
7669     for (i = 0; i < numLeavesNew; ++i) {
7670       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);
7671       idx[i] = i;
7672     }
7673     ierr = PetscSortIntWithPermutation(numLeavesNew, localPointsNew, idx);CHKERRQ(ierr);
7674     for (i = 0; i < numLeavesNew; ++i) {
7675       lp[i] = localPointsNew[idx[i]];
7676       rp[i] = remotePointsNew[idx[i]];
7677     }
7678     ltmp            = localPointsNew;
7679     localPointsNew  = lp;
7680     rtmp            = remotePointsNew;
7681     remotePointsNew = rp;
7682     ierr = PetscFree(idx);CHKERRQ(ierr);
7683     ierr = PetscFree(ltmp);CHKERRQ(ierr);
7684     ierr = PetscFree(rtmp);CHKERRQ(ierr);
7685   }
7686   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7687   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
7688   ierr = PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
7689   PetscFunctionReturn(0);
7690 }
7691 
7692 static PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7693 {
7694   PetscInt       numLabels, l;
7695   PetscInt       depth, newp, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r;
7696   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
7697   PetscErrorCode ierr;
7698 
7699   PetscFunctionBegin;
7700   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7701   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7702   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7703   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7704   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7705   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
7706   ierr = DMGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
7707   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7708   switch (refiner) {
7709   case REFINER_NOOP:
7710   case REFINER_SIMPLEX_1D:
7711   case REFINER_SIMPLEX_2D:
7712   case REFINER_SIMPLEX_TO_HEX_2D:
7713   case REFINER_HEX_2D:
7714   case REFINER_SIMPLEX_3D:
7715   case REFINER_HEX_3D:
7716   case REFINER_SIMPLEX_TO_HEX_3D:
7717     break;
7718   case REFINER_HYBRID_SIMPLEX_3D:
7719   case REFINER_HYBRID_HEX_3D:
7720     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
7721   case REFINER_HYBRID_SIMPLEX_2D:
7722   case REFINER_HYBRID_HEX_2D:
7723     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7724     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7725     break;
7726   default:
7727     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7728   }
7729   for (l = 0; l < numLabels; ++l) {
7730     DMLabel         label, labelNew;
7731     const char     *lname;
7732     PetscBool       isDepth;
7733     IS              valueIS;
7734     const PetscInt *values;
7735     PetscInt        defVal;
7736     PetscInt        numValues, val;
7737 
7738     ierr = DMGetLabelName(dm, l, &lname);CHKERRQ(ierr);
7739     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
7740     if (isDepth) continue;
7741     ierr = DMCreateLabel(rdm, lname);CHKERRQ(ierr);
7742     ierr = DMGetLabel(dm, lname, &label);CHKERRQ(ierr);
7743     ierr = DMGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
7744     ierr = DMLabelGetDefaultValue(label,&defVal);CHKERRQ(ierr);
7745     ierr = DMLabelSetDefaultValue(labelNew,defVal);CHKERRQ(ierr);
7746     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
7747     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
7748     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
7749     for (val = 0; val < numValues; ++val) {
7750       IS              pointIS;
7751       const PetscInt *points;
7752       PetscInt        numPoints, n;
7753 
7754       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
7755       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
7756       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
7757       /* Ensure refined label is created with same number of strata as
7758        * original (even if no entries here). */
7759       ierr = DMLabelAddStratum(labelNew, values[val]);CHKERRQ(ierr);
7760       for (n = 0; n < numPoints; ++n) {
7761         const PetscInt p = points[n];
7762         switch (refiner) {
7763         case REFINER_SIMPLEX_1D:
7764           if ((p >= vStart) && (p < vEnd)) {
7765             /* Old vertices stay the same */
7766             newp = vStartNew + (p - vStart);
7767             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7768           } else if ((p >= cStart) && (p < cEnd)) {
7769             /* Old cells add new cells and vertex */
7770             newp = vStartNew + (vEnd - vStart) + (p - cStart);
7771             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7772             for (r = 0; r < 2; ++r) {
7773               newp = cStartNew + (p - cStart)*2 + r;
7774               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7775             }
7776           }
7777           break;
7778         case REFINER_SIMPLEX_2D:
7779           if ((p >= vStart) && (p < vEnd)) {
7780             /* Old vertices stay the same */
7781             newp = vStartNew + (p - vStart);
7782             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7783           } else if ((p >= fStart) && (p < fEnd)) {
7784             /* Old faces add new faces and vertex */
7785             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7786             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7787             for (r = 0; r < 2; ++r) {
7788               newp = fStartNew + (p - fStart)*2 + r;
7789               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7790             }
7791           } else if ((p >= cStart) && (p < cEnd)) {
7792             /* Old cells add new cells and interior faces */
7793             for (r = 0; r < 4; ++r) {
7794               newp = cStartNew + (p - cStart)*4 + r;
7795               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7796             }
7797             for (r = 0; r < 3; ++r) {
7798               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7799               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7800             }
7801           }
7802           break;
7803         case REFINER_SIMPLEX_TO_HEX_2D:
7804           if ((p >= vStart) && (p < vEnd)) {
7805             /* Old vertices stay the same */
7806             newp = vStartNew + (p - vStart);
7807             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7808           } else if ((p >= fStart) && (p < fEnd)) {
7809             /* Old faces add new faces and vertex */
7810             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7811             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7812             for (r = 0; r < 2; ++r) {
7813               newp = fStartNew + (p - fStart)*2 + r;
7814               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7815             }
7816           } else if ((p >= cStart) && (p < cEnd)) {
7817             /* Old cells add new cells, interior faces, and a vertex */
7818             for (r = 0; r < 3; ++r) {
7819               newp = cStartNew + (p - cStart)*3 + r;
7820               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7821             }
7822             for (r = 0; r < 3; ++r) {
7823               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7824               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7825             }
7826             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + p;
7827             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7828           }
7829           break;
7830         case REFINER_HEX_2D:
7831           if ((p >= vStart) && (p < vEnd)) {
7832             /* Old vertices stay the same */
7833             newp = vStartNew + (p - vStart);
7834             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7835           } else if ((p >= fStart) && (p < fEnd)) {
7836             /* Old faces add new faces and vertex */
7837             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7838             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7839             for (r = 0; r < 2; ++r) {
7840               newp = fStartNew + (p - fStart)*2 + r;
7841               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7842             }
7843           } else if ((p >= cStart) && (p < cEnd)) {
7844             /* Old cells add new cells and interior faces and vertex */
7845             for (r = 0; r < 4; ++r) {
7846               newp = cStartNew + (p - cStart)*4 + r;
7847               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7848             }
7849             for (r = 0; r < 4; ++r) {
7850               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
7851               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7852             }
7853             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
7854             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7855           }
7856           break;
7857         case REFINER_HYBRID_SIMPLEX_2D:
7858           if ((p >= vStart) && (p < vEnd)) {
7859             /* Old vertices stay the same */
7860             newp = vStartNew + (p - vStart);
7861             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7862           } else if ((p >= fStart) && (p < fMax)) {
7863             /* Old interior faces add new faces and vertex */
7864             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7865             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7866             for (r = 0; r < 2; ++r) {
7867               newp = fStartNew + (p - fStart)*2 + r;
7868               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7869             }
7870           } else if ((p >= fMax) && (p < fEnd)) {
7871             /* Old hybrid faces stay the same */
7872             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7873             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7874           } else if ((p >= cStart) && (p < cMax)) {
7875             /* Old interior cells add new cells and interior faces */
7876             for (r = 0; r < 4; ++r) {
7877               newp = cStartNew + (p - cStart)*4 + r;
7878               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7879             }
7880             for (r = 0; r < 3; ++r) {
7881               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7882               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7883             }
7884           } else if ((p >= cMax) && (p < cEnd)) {
7885             /* Old hybrid cells add new cells and hybrid face */
7886             for (r = 0; r < 2; ++r) {
7887               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
7888               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7889             }
7890             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
7891             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7892           }
7893           break;
7894         case REFINER_HYBRID_HEX_2D:
7895           if ((p >= vStart) && (p < vEnd)) {
7896             /* Old vertices stay the same */
7897             newp = vStartNew + (p - vStart);
7898             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7899           } else if ((p >= fStart) && (p < fMax)) {
7900             /* Old interior faces add new faces and vertex */
7901             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7902             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7903             for (r = 0; r < 2; ++r) {
7904               newp = fStartNew + (p - fStart)*2 + r;
7905               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7906             }
7907           } else if ((p >= fMax) && (p < fEnd)) {
7908             /* Old hybrid faces stay the same */
7909             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7910             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7911           } else if ((p >= cStart) && (p < cMax)) {
7912             /* Old interior cells add new cells, interior faces, and vertex */
7913             for (r = 0; r < 4; ++r) {
7914               newp = cStartNew + (p - cStart)*4 + r;
7915               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7916             }
7917             for (r = 0; r < 4; ++r) {
7918               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
7919               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7920             }
7921             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
7922             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7923           } else if ((p >= cMax) && (p < cEnd)) {
7924             /* Old hybrid cells add new cells and hybrid face */
7925             for (r = 0; r < 2; ++r) {
7926               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
7927               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7928             }
7929             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (p - cMax);
7930             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7931           }
7932           break;
7933         case REFINER_SIMPLEX_3D:
7934           if ((p >= vStart) && (p < vEnd)) {
7935             /* Old vertices stay the same */
7936             newp = vStartNew + (p - vStart);
7937             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7938           } else if ((p >= eStart) && (p < eEnd)) {
7939             /* Old edges add new edges and vertex */
7940             for (r = 0; r < 2; ++r) {
7941               newp = eStartNew + (p - eStart)*2 + r;
7942               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7943             }
7944             newp = vStartNew + (vEnd - vStart) + (p - eStart);
7945             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7946           } else if ((p >= fStart) && (p < fEnd)) {
7947             /* Old faces add new faces and edges */
7948             for (r = 0; r < 4; ++r) {
7949               newp = fStartNew + (p - fStart)*4 + r;
7950               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7951             }
7952             for (r = 0; r < 3; ++r) {
7953               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
7954               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7955             }
7956           } else if ((p >= cStart) && (p < cEnd)) {
7957             /* Old cells add new cells and interior faces and edges */
7958             for (r = 0; r < 8; ++r) {
7959               newp = cStartNew + (p - cStart)*8 + r;
7960               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7961             }
7962             for (r = 0; r < 8; ++r) {
7963               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*8 + r;
7964               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7965             }
7966             for (r = 0; r < 1; ++r) {
7967               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*1 + r;
7968               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7969             }
7970           }
7971           break;
7972         case REFINER_SIMPLEX_TO_HEX_3D:
7973           if ((p >= vStart) && (p < vEnd)) {
7974             /* Old vertices stay the same */
7975             newp = vStartNew + (p - vStart);
7976             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7977           } else if ((p >= eStart) && (p < eEnd)) {
7978             /* Old edges add new edges and vertex */
7979             for (r = 0; r < 2; ++r) {
7980               newp = eStartNew + (p - eStart)*2 + r;
7981               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7982             }
7983             newp = vStartNew + (vEnd - vStart) + (p - eStart);
7984             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7985           } else if ((p >= fStart) && (p < fEnd)) {
7986             /* Old faces add new faces, edges and a vertex */
7987             for (r = 0; r < 3; ++r) {
7988               newp = fStartNew + (p - fStart)*3 + r;
7989               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7990             }
7991             for (r = 0; r < 3; ++r) {
7992               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
7993               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7994             }
7995           } else if ((p >= cStart) && (p < cEnd)) {
7996             /* Old cells add new cells and interior faces and edges and a vertex */
7997             for (r = 0; r < 4; ++r) {
7998               newp = cStartNew + (p - cStart)*4 + r;
7999               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8000             }
8001             for (r = 0; r < 6; ++r) {
8002               newp = fStartNew + (fEnd - fStart)*3 + (p - cStart)*6 + r;
8003               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8004             }
8005             for (r = 0; r < 4; ++r) {
8006               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*4 + r;
8007               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8008             }
8009             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + p - cStart;
8010             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8011           }
8012           break;
8013         case REFINER_HYBRID_SIMPLEX_3D:
8014           if ((p >= vStart) && (p < vEnd)) {
8015             /* Interior vertices stay the same */
8016             newp = vStartNew + (p - vStart);
8017             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8018           } else if ((p >= eStart) && (p < eMax)) {
8019             /* Interior edges add new edges and vertex */
8020             for (r = 0; r < 2; ++r) {
8021               newp = eStartNew + (p - eStart)*2 + r;
8022               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8023             }
8024             newp = vStartNew + (vEnd - vStart) + (p - eStart);
8025             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8026           } else if ((p >= eMax) && (p < eEnd)) {
8027             /* Hybrid edges stay the same */
8028             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - eMax);
8029             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8030           } else if ((p >= fStart) && (p < fMax)) {
8031             /* Interior faces add new faces and edges */
8032             for (r = 0; r < 4; ++r) {
8033               newp = fStartNew + (p - fStart)*4 + r;
8034               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8035             }
8036             for (r = 0; r < 3; ++r) {
8037               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
8038               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8039             }
8040           } else if ((p >= fMax) && (p < fEnd)) {
8041             /* Hybrid faces add new faces and edges */
8042             for (r = 0; r < 2; ++r) {
8043               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (p - fMax)*2 + r;
8044               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8045             }
8046             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - fMax);
8047             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8048           } else if ((p >= cStart) && (p < cMax)) {
8049             /* Interior cells add new cells, faces, and edges */
8050             for (r = 0; r < 8; ++r) {
8051               newp = cStartNew + (p - cStart)*8 + r;
8052               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8053             }
8054             for (r = 0; r < 8; ++r) {
8055               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*8 + r;
8056               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8057             }
8058             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart);
8059             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8060           } else if ((p >= cMax) && (p < cEnd)) {
8061             /* Hybrid cells add new cells and faces */
8062             for (r = 0; r < 4; ++r) {
8063               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
8064               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8065             }
8066             for (r = 0; r < 3; ++r) {
8067               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
8068               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8069             }
8070           }
8071           break;
8072         case REFINER_HEX_3D:
8073           if ((p >= vStart) && (p < vEnd)) {
8074             /* Old vertices stay the same */
8075             newp = vStartNew + (p - vStart);
8076             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8077           } else if ((p >= eStart) && (p < eEnd)) {
8078             /* Old edges add new edges and vertex */
8079             for (r = 0; r < 2; ++r) {
8080               newp = eStartNew + (p - eStart)*2 + r;
8081               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8082             }
8083             newp = vStartNew + (vEnd - vStart) + (p - eStart);
8084             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8085           } else if ((p >= fStart) && (p < fEnd)) {
8086             /* Old faces add new faces, edges, and vertex */
8087             for (r = 0; r < 4; ++r) {
8088               newp = fStartNew + (p - fStart)*4 + r;
8089               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8090             }
8091             for (r = 0; r < 4; ++r) {
8092               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*4 + r;
8093               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8094             }
8095             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (p - fStart);
8096             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8097           } else if ((p >= cStart) && (p < cEnd)) {
8098             /* Old cells add new cells, faces, edges, and vertex */
8099             for (r = 0; r < 8; ++r) {
8100               newp = cStartNew + (p - cStart)*8 + r;
8101               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8102             }
8103             for (r = 0; r < 12; ++r) {
8104               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*12 + r;
8105               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8106             }
8107             for (r = 0; r < 6; ++r) {
8108               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (p - cStart)*6 + r;
8109               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8110             }
8111             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (p - cStart);
8112             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8113           }
8114           break;
8115         case REFINER_HYBRID_HEX_3D:
8116           if ((p >= vStart) && (p < vEnd)) {
8117             /* Interior vertices stay the same */
8118             newp = vStartNew + (p - vStart);
8119             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8120           } else if ((p >= eStart) && (p < eMax)) {
8121             /* Interior edges add new edges and vertex */
8122             for (r = 0; r < 2; ++r) {
8123               newp = eStartNew + (p - eStart)*2 + r;
8124               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8125             }
8126             newp = vStartNew + (vEnd - vStart) + (p - eStart);
8127             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8128           } else if ((p >= eMax) && (p < eEnd)) {
8129             /* Hybrid edges stay the same */
8130             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - eMax);
8131             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8132           } else if ((p >= fStart) && (p < fMax)) {
8133             /* Interior faces add new faces, edges, and vertex */
8134             for (r = 0; r < 4; ++r) {
8135               newp = fStartNew + (p - fStart)*4 + r;
8136               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8137             }
8138             for (r = 0; r < 4; ++r) {
8139               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*4 + r;
8140               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8141             }
8142             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (p - fStart);
8143             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8144           } else if ((p >= fMax) && (p < fEnd)) {
8145             /* Hybrid faces add new faces and edges */
8146             for (r = 0; r < 2; ++r) {
8147               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (p - fMax)*2 + r;
8148               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8149             }
8150             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - fMax);
8151             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8152           } else if ((p >= cStart) && (p < cMax)) {
8153             /* Interior cells add new cells, faces, edges, and vertex */
8154             for (r = 0; r < 8; ++r) {
8155               newp = cStartNew + (p - cStart)*8 + r;
8156               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8157             }
8158             for (r = 0; r < 12; ++r) {
8159               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*12 + r;
8160               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8161             }
8162             for (r = 0; r < 6; ++r) {
8163               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (p - cStart)*6 + r;
8164               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8165             }
8166             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (p - cStart);
8167             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8168           } else if ((p >= cMax) && (p < cEnd)) {
8169             /* Hybrid cells add new cells, faces, and edges */
8170             for (r = 0; r < 4; ++r) {
8171               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
8172               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8173             }
8174             for (r = 0; r < 4; ++r) {
8175               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (p - cMax)*4 + r;
8176               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8177             }
8178             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (fEnd - fMax) + (p - cMax);
8179             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
8180           }
8181           break;
8182         default:
8183           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
8184         }
8185       }
8186       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
8187       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
8188     }
8189     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
8190     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
8191     if (0) {
8192       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
8193     }
8194   }
8195   PetscFunctionReturn(0);
8196 }
8197 
8198 /* This will only work for interpolated meshes */
8199 PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
8200 {
8201   DM             rdm;
8202   PetscInt      *depthSize;
8203   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
8204   PetscErrorCode ierr;
8205 
8206   PetscFunctionBegin;
8207   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
8208   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
8209   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
8210   ierr = DMSetDimension(rdm, dim);CHKERRQ(ierr);
8211   /* Calculate number of new points of each depth */
8212   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
8213   if (depth >= 0 && dim != depth) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Mesh must be interpolated for regular refinement");
8214   ierr = PetscMalloc1(depth+1, &depthSize);CHKERRQ(ierr);
8215   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
8216   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
8217   /* Step 1: Set chart */
8218   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
8219   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
8220   /* Step 2: Set cone/support sizes */
8221   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
8222   /* Step 3: Setup refined DM */
8223   ierr = DMSetUp(rdm);CHKERRQ(ierr);
8224   /* Step 4: Set cones and supports */
8225   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
8226   /* Step 5: Stratify */
8227   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
8228   /* Step 6: Create pointSF */
8229   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
8230   /* Step 7: Create labels */
8231   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
8232   /* Step 8: Set coordinates */
8233   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
8234   ierr = PetscFree(depthSize);CHKERRQ(ierr);
8235 
8236   *dmRefined = rdm;
8237   PetscFunctionReturn(0);
8238 }
8239 
8240 /*@
8241   DMPlexCreateCoarsePointIS - Creates an IS covering the coarse DM chart with the fine points as data
8242 
8243   Input Parameter:
8244 . dm - The coarse DM
8245 
8246   Output Parameter:
8247 . fpointIS - The IS of all the fine points which exist in the original coarse mesh
8248 
8249   Level: developer
8250 
8251 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexCreateSubpointIS()
8252 @*/
8253 PetscErrorCode DMPlexCreateCoarsePointIS(DM dm, IS *fpointIS)
8254 {
8255   CellRefiner    cellRefiner;
8256   PetscInt      *depthSize, *fpoints;
8257   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
8258   PetscInt       depth, pStart, pEnd, p, vStart, vEnd, v;
8259   PetscErrorCode ierr;
8260 
8261   PetscFunctionBegin;
8262   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
8263   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
8264   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8265   ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr);
8266   ierr = PetscMalloc1(depth+1, &depthSize);CHKERRQ(ierr);
8267   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
8268   if (cellRefiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
8269   ierr = PetscMalloc1(pEnd-pStart,&fpoints);CHKERRQ(ierr);
8270   for (p = 0; p < pEnd-pStart; ++p) fpoints[p] = -1;
8271   switch (cellRefiner) {
8272   case REFINER_SIMPLEX_1D:
8273   case REFINER_SIMPLEX_2D:
8274   case REFINER_HYBRID_SIMPLEX_2D:
8275   case REFINER_HEX_2D:
8276   case REFINER_HYBRID_HEX_2D:
8277   case REFINER_SIMPLEX_3D:
8278   case REFINER_HYBRID_SIMPLEX_3D:
8279   case REFINER_HEX_3D:
8280   case REFINER_HYBRID_HEX_3D:
8281     for (v = vStart; v < vEnd; ++v) fpoints[v-pStart] = vStartNew + (v - vStart);
8282     break;
8283   default:
8284     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", cellRefiner);
8285   }
8286   ierr = ISCreateGeneral(PETSC_COMM_SELF, pEnd-pStart, fpoints, PETSC_OWN_POINTER, fpointIS);CHKERRQ(ierr);
8287   ierr = PetscFree(depthSize);CHKERRQ(ierr);
8288   PetscFunctionReturn(0);
8289 }
8290 
8291 /*@
8292   DMPlexSetRefinementUniform - Set the flag for uniform refinement
8293 
8294   Input Parameters:
8295 + dm - The DM
8296 - refinementUniform - The flag for uniform refinement
8297 
8298   Level: developer
8299 
8300 .seealso: DMRefine(), DMPlexGetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
8301 @*/
8302 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
8303 {
8304   DM_Plex *mesh = (DM_Plex*) dm->data;
8305 
8306   PetscFunctionBegin;
8307   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8308   mesh->refinementUniform = refinementUniform;
8309   PetscFunctionReturn(0);
8310 }
8311 
8312 /*@
8313   DMPlexGetRefinementUniform - Retrieve the flag for uniform refinement
8314 
8315   Input Parameter:
8316 . dm - The DM
8317 
8318   Output Parameter:
8319 . refinementUniform - The flag for uniform refinement
8320 
8321   Level: developer
8322 
8323 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
8324 @*/
8325 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
8326 {
8327   DM_Plex *mesh = (DM_Plex*) dm->data;
8328 
8329   PetscFunctionBegin;
8330   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8331   PetscValidPointer(refinementUniform,  2);
8332   *refinementUniform = mesh->refinementUniform;
8333   PetscFunctionReturn(0);
8334 }
8335 
8336 /*@
8337   DMPlexSetRefinementLimit - Set the maximum cell volume for refinement
8338 
8339   Input Parameters:
8340 + dm - The DM
8341 - refinementLimit - The maximum cell volume in the refined mesh
8342 
8343   Level: developer
8344 
8345 .seealso: DMRefine(), DMPlexGetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
8346 @*/
8347 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
8348 {
8349   DM_Plex *mesh = (DM_Plex*) dm->data;
8350 
8351   PetscFunctionBegin;
8352   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8353   mesh->refinementLimit = refinementLimit;
8354   PetscFunctionReturn(0);
8355 }
8356 
8357 /*@
8358   DMPlexGetRefinementLimit - Retrieve the maximum cell volume for refinement
8359 
8360   Input Parameter:
8361 . dm - The DM
8362 
8363   Output Parameter:
8364 . refinementLimit - The maximum cell volume in the refined mesh
8365 
8366   Level: developer
8367 
8368 .seealso: DMRefine(), DMPlexSetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
8369 @*/
8370 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
8371 {
8372   DM_Plex *mesh = (DM_Plex*) dm->data;
8373 
8374   PetscFunctionBegin;
8375   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8376   PetscValidPointer(refinementLimit,  2);
8377   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
8378   *refinementLimit = mesh->refinementLimit;
8379   PetscFunctionReturn(0);
8380 }
8381 
8382 /*@
8383   DMPlexSetRefinementFunction - Set the function giving the maximum cell volume for refinement
8384 
8385   Input Parameters:
8386 + dm - The DM
8387 - refinementFunc - Function giving the maximum cell volume in the refined mesh
8388 
8389   Note: The calling sequence is refinementFunc(coords, limit)
8390 $ coords - Coordinates of the current point, usually a cell centroid
8391 $ limit  - The maximum cell volume for a cell containing this point
8392 
8393   Level: developer
8394 
8395 .seealso: DMRefine(), DMPlexGetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
8396 @*/
8397 PetscErrorCode DMPlexSetRefinementFunction(DM dm, PetscErrorCode (*refinementFunc)(const PetscReal [], PetscReal *))
8398 {
8399   DM_Plex *mesh = (DM_Plex*) dm->data;
8400 
8401   PetscFunctionBegin;
8402   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8403   mesh->refinementFunc = refinementFunc;
8404   PetscFunctionReturn(0);
8405 }
8406 
8407 /*@
8408   DMPlexGetRefinementFunction - Get the function giving the maximum cell volume for refinement
8409 
8410   Input Parameter:
8411 . dm - The DM
8412 
8413   Output Parameter:
8414 . refinementFunc - Function giving the maximum cell volume in the refined mesh
8415 
8416   Note: The calling sequence is refinementFunc(coords, limit)
8417 $ coords - Coordinates of the current point, usually a cell centroid
8418 $ limit  - The maximum cell volume for a cell containing this point
8419 
8420   Level: developer
8421 
8422 .seealso: DMRefine(), DMPlexSetRefinementFunction(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
8423 @*/
8424 PetscErrorCode DMPlexGetRefinementFunction(DM dm, PetscErrorCode (**refinementFunc)(const PetscReal [], PetscReal *))
8425 {
8426   DM_Plex *mesh = (DM_Plex*) dm->data;
8427 
8428   PetscFunctionBegin;
8429   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8430   PetscValidPointer(refinementFunc,  2);
8431   *refinementFunc = mesh->refinementFunc;
8432   PetscFunctionReturn(0);
8433 }
8434 
8435 PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
8436 {
8437   PetscInt       dim, cStart, cEnd, coneSize, cMax, fMax;
8438   PetscErrorCode ierr;
8439 
8440   PetscFunctionBegin;
8441   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
8442   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8443   if (cEnd <= cStart) {*cellRefiner = REFINER_NOOP; PetscFunctionReturn(0);}
8444   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
8445   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, NULL, NULL);CHKERRQ(ierr);
8446   switch (dim) {
8447   case 1:
8448     switch (coneSize) {
8449     case 2:
8450       *cellRefiner = REFINER_SIMPLEX_1D;
8451       break;
8452     default:
8453       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
8454     }
8455     break;
8456   case 2:
8457     switch (coneSize) {
8458     case 3:
8459       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_2D;
8460       else *cellRefiner = REFINER_SIMPLEX_2D;
8461       break;
8462     case 4:
8463       if (cMax >= 0 && fMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_2D;
8464       else *cellRefiner = REFINER_HEX_2D;
8465       break;
8466     default:
8467       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
8468     }
8469     break;
8470   case 3:
8471     switch (coneSize) {
8472     case 4:
8473       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_3D;
8474       else *cellRefiner = REFINER_SIMPLEX_3D;
8475       break;
8476     case 6:
8477       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_3D;
8478       else *cellRefiner = REFINER_HEX_3D;
8479       break;
8480     default:
8481       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
8482     }
8483     break;
8484   default:
8485     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
8486   }
8487   PetscFunctionReturn(0);
8488 }
8489 
8490 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
8491 {
8492   PetscBool      isUniform;
8493   PetscErrorCode ierr;
8494 
8495   PetscFunctionBegin;
8496   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
8497   if (isUniform) {
8498     CellRefiner cellRefiner;
8499     PetscBool   localized;
8500 
8501     ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
8502     ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr);
8503     ierr = DMPlexRefineUniform_Internal(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
8504     ierr = DMCopyBoundary(dm, *dmRefined);CHKERRQ(ierr);
8505     if (localized) {ierr = DMLocalizeCoordinates(*dmRefined);CHKERRQ(ierr);}
8506   } else {
8507     ierr = DMPlexRefine_Internal(dm, NULL, dmRefined);CHKERRQ(ierr);
8508   }
8509   PetscFunctionReturn(0);
8510 }
8511 
8512 PetscErrorCode DMRefineHierarchy_Plex(DM dm, PetscInt nlevels, DM dmRefined[])
8513 {
8514   DM             cdm = dm;
8515   PetscInt       r;
8516   PetscBool      isUniform, localized;
8517   PetscErrorCode ierr;
8518 
8519   PetscFunctionBegin;
8520   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
8521   ierr = DMGetCoordinatesLocalized(dm, &localized);CHKERRQ(ierr);
8522   if (isUniform) {
8523     for (r = 0; r < nlevels; ++r) {
8524       CellRefiner cellRefiner;
8525 
8526       ierr = DMPlexGetCellRefiner_Internal(cdm, &cellRefiner);CHKERRQ(ierr);
8527       ierr = DMPlexRefineUniform_Internal(cdm, cellRefiner, &dmRefined[r]);CHKERRQ(ierr);
8528       ierr = DMCopyBoundary(cdm, dmRefined[r]);CHKERRQ(ierr);
8529       if (localized) {ierr = DMLocalizeCoordinates(dmRefined[r]);CHKERRQ(ierr);}
8530       ierr = DMSetCoarseDM(dmRefined[r], cdm);CHKERRQ(ierr);
8531       ierr = DMPlexSetRegularRefinement(dmRefined[r], PETSC_TRUE);CHKERRQ(ierr);
8532       cdm  = dmRefined[r];
8533     }
8534   } else {
8535     for (r = 0; r < nlevels; ++r) {
8536       ierr = DMRefine(cdm, PetscObjectComm((PetscObject) dm), &dmRefined[r]);CHKERRQ(ierr);
8537       ierr = DMCopyBoundary(cdm, dmRefined[r]);CHKERRQ(ierr);
8538       if (localized) {ierr = DMLocalizeCoordinates(dmRefined[r]);CHKERRQ(ierr);}
8539       ierr = DMSetCoarseDM(dmRefined[r], cdm);CHKERRQ(ierr);
8540       cdm  = dmRefined[r];
8541     }
8542   }
8543   PetscFunctionReturn(0);
8544 }
8545