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