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