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