xref: /petsc/src/dm/impls/plex/plexrefine.c (revision 3fe31fa29bf1bd75ee57c8d4c344699ef3f6a635)
1 #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <petscsf.h>
3 
4 #undef __FUNCT__
5 #define __FUNCT__ "GetDepthStart_Private"
6 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
7 {
8   PetscFunctionBegin;
9   if (cStart) *cStart = 0;
10   if (vStart) *vStart = depth < 0 ? 0 : depthSize[depth];
11   if (fStart) *fStart = depth < 0 ? 0 : depthSize[depth] + depthSize[0];
12   if (eStart) *eStart = depth < 0 ? 0 : depthSize[depth] + depthSize[0] + depthSize[depth-1];
13   PetscFunctionReturn(0);
14 }
15 
16 #undef __FUNCT__
17 #define __FUNCT__ "GetDepthEnd_Private"
18 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
19 {
20   PetscFunctionBegin;
21   if (cEnd) *cEnd = depth < 0 ? 0 : depthSize[depth];
22   if (vEnd) *vEnd = depth < 0 ? 0 : depthSize[depth] + depthSize[0];
23   if (fEnd) *fEnd = depth < 0 ? 0 : depthSize[depth] + depthSize[0] + depthSize[depth-1];
24   if (eEnd) *eEnd = depth < 0 ? 0 : depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
25   PetscFunctionReturn(0);
26 }
27 
28 #undef __FUNCT__
29 #define __FUNCT__ "CellRefinerGetAffineTransforms_Internal"
30 /* Gets the affine map from the original cell to each subcell */
31 PetscErrorCode CellRefinerGetAffineTransforms_Internal(CellRefiner refiner, PetscInt *numSubcells, PetscReal *v0[], PetscReal *jac[], PetscReal *invjac[])
32 {
33   PetscReal     *v = NULL, *j = NULL, *invj = NULL, detJ;
34   PetscInt       dim, s;
35   PetscErrorCode ierr;
36 
37   PetscFunctionBegin;
38   switch (refiner) {
39   case REFINER_NOOP: break;
40   case REFINER_SIMPLEX_2D:
41     /*
42      2
43      |\
44      | \
45      |  \
46      |   \
47      | C  \
48      |     \
49      |      \
50      2---1---1
51      |\  D  / \
52      | 2   0   \
53      |A \ /  B  \
54      0---0-------1
55      */
56     dim = 2;
57     if (numSubcells) *numSubcells = 4;
58     if (v0) {
59       ierr = PetscMalloc3(4*dim,&v,4*dim*dim,&j,4*dim*dim,&invj);CHKERRQ(ierr);
60       /* A */
61       v[0+0] = -1.0; v[0+1] = -1.0;
62       j[0+0] =  0.5; j[0+1] =  0.0;
63       j[0+2] =  0.0; j[0+3] =  0.5;
64       /* B */
65       v[2+0] =  0.0; v[2+1] = -1.0;
66       j[4+0] =  0.5; j[4+1] =  0.0;
67       j[4+2] =  0.0; j[4+3] =  0.5;
68       /* C */
69       v[4+0] = -1.0; v[4+1] =  0.0;
70       j[8+0] =  0.5; j[8+1] =  0.0;
71       j[8+2] =  0.0; j[8+3] =  0.5;
72       /* D */
73       v[6+0]  =  0.0; v[6+1]  = -1.0;
74       j[12+0] =  0.0; j[12+1] = -0.5;
75       j[12+2] =  0.5; j[12+3] =  0.5;
76       for (s = 0; s < 4; ++s) {
77         DMPlex_Det2D_Internal(&detJ, &j[s*dim*dim]);
78         DMPlex_Invert2D_Internal(&invj[s*dim*dim], &j[s*dim*dim], detJ);
79       }
80     }
81     break;
82   case REFINER_HEX_2D:
83     /*
84      3---------2---------2
85      |         |         |
86      |    D    2    C    |
87      |         |         |
88      3----3----0----1----1
89      |         |         |
90      |    A    0    B    |
91      |         |         |
92      0---------0---------1
93      */
94     dim = 2;
95     if (numSubcells) *numSubcells = 4;
96     if (v0) {
97       ierr = PetscMalloc3(4*dim,&v,4*dim*dim,&j,4*dim*dim,&invj);CHKERRQ(ierr);
98       /* A */
99       v[0+0] = -1.0; v[0+1] = -1.0;
100       j[0+0] =  0.5; j[0+1] =  0.0;
101       j[0+2] =  0.0; j[0+3] =  0.5;
102       /* B */
103       v[2+0] =  0.0; v[2+1] = -1.0;
104       j[4+0] =  0.5; j[4+1] =  0.0;
105       j[4+2] =  0.0; j[4+3] =  0.5;
106       /* C */
107       v[4+0] =  0.0; v[4+1] =  0.0;
108       j[8+0] =  0.5; j[8+1] =  0.0;
109       j[8+2] =  0.0; j[8+3] =  0.5;
110       /* D */
111       v[6+0]  = -1.0; v[6+1]  =  0.0;
112       j[12+0] =  0.5; j[12+1] =  0.0;
113       j[12+2] =  0.0; j[12+3] =  0.5;
114       for (s = 0; s < 4; ++s) {
115         DMPlex_Det2D_Internal(&detJ, &j[s*dim*dim]);
116         DMPlex_Invert2D_Internal(&invj[s*dim*dim], &j[s*dim*dim], detJ);
117       }
118     }
119     break;
120   default:
121     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
122   }
123   if (v0) {*v0 = v; *jac = j; *invjac = invj;}
124   PetscFunctionReturn(0);
125 }
126 
127 #undef __FUNCT__
128 #define __FUNCT__ "CellRefinerRestoreAffineTransforms_Internal"
129 PetscErrorCode CellRefinerRestoreAffineTransforms_Internal(CellRefiner refiner, PetscInt *numSubcells, PetscReal *v0[], PetscReal *jac[], PetscReal *invjac[])
130 {
131   PetscErrorCode ierr;
132 
133   PetscFunctionBegin;
134   ierr = PetscFree3(*v0,*jac,*invjac);CHKERRQ(ierr);
135   PetscFunctionReturn(0);
136 }
137 
138 #undef __FUNCT__
139 #define __FUNCT__ "CellRefinerInCellTest_Internal"
140 /* Should this be here or in the DualSpace somehow? */
141 PetscErrorCode CellRefinerInCellTest_Internal(CellRefiner refiner, const PetscReal point[], PetscBool *inside)
142 {
143   PetscReal sum = 0.0;
144   PetscInt  d;
145 
146   PetscFunctionBegin;
147   *inside = PETSC_TRUE;
148   switch (refiner) {
149   case REFINER_NOOP: break;
150   case REFINER_SIMPLEX_2D:
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 REFINER_HEX_2D:
158     for (d = 0; d < 2; ++d) if ((point[d] < -1.0) || (point[d] > 1.0)) {*inside = PETSC_FALSE; break;}
159     break;
160   default:
161     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
162   }
163   PetscFunctionReturn(0);
164 }
165 
166 #undef __FUNCT__
167 #define __FUNCT__ "CellRefinerGetSizes"
168 static PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
169 {
170   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
171   PetscErrorCode ierr;
172 
173   PetscFunctionBegin;
174   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
175   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
176   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
177   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
178   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
179   switch (refiner) {
180   case REFINER_NOOP:
181     break;
182   case REFINER_SIMPLEX_1D:
183     depthSize[0] = vEnd - vStart + cEnd - cStart;         /* Add a vertex on every cell. */
184     depthSize[1] = 2*(cEnd - cStart);                     /* Split every cell in 2. */
185     break;
186   case REFINER_SIMPLEX_2D:
187     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
188     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
189     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
190     break;
191   case REFINER_HYBRID_SIMPLEX_2D:
192     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
193     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
194     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
195     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 */
196     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
197     break;
198   case REFINER_HEX_2D:
199     depthSize[0] = vEnd - vStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every face and cell */
200     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
201     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
202     break;
203   case REFINER_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 REFINER_SIMPLEX_3D:
216     depthSize[0] =    vEnd - vStart  +    eEnd - eStart;                    /* Add a vertex on every edge */
217     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 */
218     depthSize[2] = 4*(fEnd - fStart) + 8*(cEnd - cStart);                   /* Every face split into 4 faces and 8 faces are added for each cell */
219     depthSize[3] = 8*(cEnd - cStart);                                       /* Every cell split into 8 cells */
220     break;
221   case REFINER_HYBRID_SIMPLEX_3D:
222     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
223     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
224     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
225     /* Tetrahedra */
226     depthSize[0]  =    vEnd - vStart  +    eMax - eStart;                    /* Add a vertex on every interior edge */
227     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 */
228     depthSize[2]  = 4*(fMax - fStart) + 8*(cMax - cStart);                   /* Every interior face split into 4 faces, 8 faces added for each interior cell */
229     depthSize[3]  = 8*(cMax - cStart);                                       /* Every interior cell split into 8 cells */
230     /* Triangular Prisms */
231     depthSize[0] += 0;                                                       /* No hybrid vertices */
232     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax);                     /* Every hybrid edge remains, 1 edge for every hybrid face */
233     depthSize[2] += 2*(fEnd - fMax)   + 3*(cEnd - cMax);                     /* Every hybrid face split into 2 faces and 3 faces are added for each hybrid cell */
234     depthSize[3] += 4*(cEnd - cMax);                                         /* Every hybrid cell split into 4 cells */
235     break;
236   case REFINER_HEX_3D:
237     depthSize[0] = vEnd - vStart + eEnd - eStart + fEnd - fStart + cEnd - cStart; /* Add a vertex on every edge, face and cell */
238     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 */
239     depthSize[2] = 4*(fEnd - fStart) + 12*(cEnd - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
240     depthSize[3] = 8*(cEnd - cStart);                                             /* Every cell split into 8 cells */
241     break;
242   case REFINER_HYBRID_HEX_3D:
243     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
244     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
245     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
246     /* Hexahedra */
247     depthSize[0] = vEnd - vStart + eMax - eStart + fMax - fStart + cMax - cStart; /* Add a vertex on every edge, face and cell */
248     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 */
249     depthSize[2] = 4*(fMax - fStart) + 12*(cMax - cStart);                        /* Every face is split into 4 faces, and 12 faces are added for each cell */
250     depthSize[3] = 8*(cMax - cStart);                                             /* Every cell split into 8 cells */
251     /* Quadrilateral Prisms */
252     depthSize[0] += 0;                                                            /* No hybrid vertices */
253     depthSize[1] +=   (eEnd - eMax)   +   (fEnd - fMax)   +   (cEnd - cMax);      /* Every hybrid edge remains, 1 edge for every hybrid face and hybrid cell */
254     depthSize[2] += 2*(fEnd - fMax)   + 4*(cEnd - cMax);                          /* Every hybrid face split into 2 faces and 4 faces are added for each hybrid cell */
255     depthSize[3] += 4*(cEnd - cMax);                                              /* Every hybrid cell split into 4 cells */
256     break;
257   default:
258     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
259   }
260   PetscFunctionReturn(0);
261 }
262 
263 /* Return triangle edge for orientation o, if it is r for o == 0 */
264 PETSC_STATIC_INLINE PetscInt GetTriEdge_Static(PetscInt o, PetscInt r) {
265   return (o < 0 ? 2-(o+r) : o+r)%3;
266 }
267 PETSC_STATIC_INLINE PetscInt GetTriEdgeInverse_Static(PetscInt o, PetscInt s) {
268   return (o < 0 ? 2-(o+s) : 3+s-o)%3;
269 }
270 
271 /* Return triangle subface for orientation o, if it is r for o == 0 */
272 PETSC_STATIC_INLINE PetscInt GetTriSubface_Static(PetscInt o, PetscInt r) {
273   return (o < 0 ? 3-(o+r) : o+r)%3;
274 }
275 PETSC_STATIC_INLINE PetscInt GetTriSubfaceInverse_Static(PetscInt o, PetscInt s) {
276   return (o < 0 ? 3-(o+s) : 3+s-o)%3;
277 }
278 
279 /* I HAVE NO IDEA: Return ??? for orientation o, if it is r for o == 0 */
280 PETSC_STATIC_INLINE PetscInt GetTetSomething_Static(PetscInt o, PetscInt r) {
281   return (o < 0 ? 1-(o+r) : o+r)%3;
282 }
283 PETSC_STATIC_INLINE PetscInt GetTetSomethingInverse_Static(PetscInt o, PetscInt s) {
284   return (o < 0 ? 1-(o+s) : 3+s-o)%3;
285 }
286 
287 
288 /* Return quad edge for orientation o, if it is r for o == 0 */
289 PETSC_STATIC_INLINE PetscInt GetQuadEdge_Static(PetscInt o, PetscInt r) {
290   return (o < 0 ? 3-(o+r) : o+r)%4;
291 }
292 PETSC_STATIC_INLINE PetscInt GetQuadEdgeInverse_Static(PetscInt o, PetscInt s) {
293   return (o < 0 ? 3-(o+s) : 4+s-o)%4;
294 }
295 
296 /* Return quad subface for orientation o, if it is r for o == 0 */
297 PETSC_STATIC_INLINE PetscInt GetQuadSubface_Static(PetscInt o, PetscInt r) {
298   return (o < 0 ? 4-(o+r) : o+r)%4;
299 }
300 PETSC_STATIC_INLINE PetscInt GetQuadSubfaceInverse_Static(PetscInt o, PetscInt s) {
301   return (o < 0 ? 4-(o+s) : 4+s-o)%4;
302 }
303 
304 #undef __FUNCT__
305 #define __FUNCT__ "CellRefinerSetConeSizes"
306 static PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
307 {
308   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, e, r;
309   PetscErrorCode ierr;
310 
311   PetscFunctionBegin;
312   if (!refiner) PetscFunctionReturn(0);
313   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
314   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
315   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
316   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
317   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
318   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
319   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
320   switch (refiner) {
321   case REFINER_SIMPLEX_1D:
322     /* All cells have 2 vertices */
323     for (c = cStart; c < cEnd; ++c) {
324       for (r = 0; r < 2; ++r) {
325         const PetscInt newp = cStartNew + (c - cStart)*2 + r;
326 
327         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
328       }
329     }
330     /* Old vertices have identical supports */
331     for (v = vStart; v < vEnd; ++v) {
332       const PetscInt newp = vStartNew + (v - vStart);
333       PetscInt       size;
334 
335       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
336       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
337     }
338     /* Cell vertices have support 2 */
339     for (c = cStart; c < cEnd; ++c) {
340       const PetscInt newp = vStartNew + (vEnd - vStart) + (c - cStart);
341 
342       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
343     }
344     break;
345   case REFINER_SIMPLEX_2D:
346     /* All cells have 3 faces */
347     for (c = cStart; c < cEnd; ++c) {
348       for (r = 0; r < 4; ++r) {
349         const PetscInt newp = (c - cStart)*4 + r;
350 
351         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
352       }
353     }
354     /* Split faces have 2 vertices and the same cells as the parent */
355     for (f = fStart; f < fEnd; ++f) {
356       for (r = 0; r < 2; ++r) {
357         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
358         PetscInt       size;
359 
360         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
361         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
362         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
363       }
364     }
365     /* Interior faces have 2 vertices and 2 cells */
366     for (c = cStart; c < cEnd; ++c) {
367       for (r = 0; r < 3; ++r) {
368         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
369 
370         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
371         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
372       }
373     }
374     /* Old vertices have identical supports */
375     for (v = vStart; v < vEnd; ++v) {
376       const PetscInt newp = vStartNew + (v - vStart);
377       PetscInt       size;
378 
379       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
380       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
381     }
382     /* Face vertices have 2 + cells*2 supports */
383     for (f = fStart; f < fEnd; ++f) {
384       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
385       PetscInt       size;
386 
387       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
388       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
389     }
390     break;
391   case REFINER_HEX_2D:
392     /* All cells have 4 faces */
393     for (c = cStart; c < cEnd; ++c) {
394       for (r = 0; r < 4; ++r) {
395         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
396 
397         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
398       }
399     }
400     /* Split faces have 2 vertices and the same cells as the parent */
401     for (f = fStart; f < fEnd; ++f) {
402       for (r = 0; r < 2; ++r) {
403         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
404         PetscInt       size;
405 
406         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
407         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
408         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
409       }
410     }
411     /* Interior faces have 2 vertices and 2 cells */
412     for (c = cStart; c < cEnd; ++c) {
413       for (r = 0; r < 4; ++r) {
414         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
415 
416         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
417         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
418       }
419     }
420     /* Old vertices have identical supports */
421     for (v = vStart; v < vEnd; ++v) {
422       const PetscInt newp = vStartNew + (v - vStart);
423       PetscInt       size;
424 
425       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
426       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
427     }
428     /* Face vertices have 2 + cells supports */
429     for (f = fStart; f < fEnd; ++f) {
430       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
431       PetscInt       size;
432 
433       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
434       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
435     }
436     /* Cell vertices have 4 supports */
437     for (c = cStart; c < cEnd; ++c) {
438       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
439 
440       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
441     }
442     break;
443   case REFINER_HYBRID_SIMPLEX_2D:
444     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
445     cMax = PetscMin(cEnd, cMax);
446     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
447     fMax = PetscMin(fEnd, fMax);
448     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
449     /* Interior cells have 3 faces */
450     for (c = cStart; c < cMax; ++c) {
451       for (r = 0; r < 4; ++r) {
452         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
453 
454         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
455       }
456     }
457     /* Hybrid cells have 4 faces */
458     for (c = cMax; c < cEnd; ++c) {
459       for (r = 0; r < 2; ++r) {
460         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
461 
462         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
463       }
464     }
465     /* Interior split faces have 2 vertices and the same cells as the parent */
466     for (f = fStart; f < fMax; ++f) {
467       for (r = 0; r < 2; ++r) {
468         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
469         PetscInt       size;
470 
471         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
472         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
473         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
474       }
475     }
476     /* Interior cell faces have 2 vertices and 2 cells */
477     for (c = cStart; c < cMax; ++c) {
478       for (r = 0; r < 3; ++r) {
479         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
480 
481         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
482         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
483       }
484     }
485     /* Hybrid faces have 2 vertices and the same cells */
486     for (f = fMax; f < fEnd; ++f) {
487       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
488       PetscInt       size;
489 
490       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
491       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
492       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
493     }
494     /* Hybrid cell faces have 2 vertices and 2 cells */
495     for (c = cMax; c < cEnd; ++c) {
496       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
497 
498       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
499       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
500     }
501     /* Old vertices have identical supports */
502     for (v = vStart; v < vEnd; ++v) {
503       const PetscInt newp = vStartNew + (v - vStart);
504       PetscInt       size;
505 
506       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
507       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
508     }
509     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
510     for (f = fStart; f < fMax; ++f) {
511       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
512       const PetscInt *support;
513       PetscInt       size, newSize = 2, s;
514 
515       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
516       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
517       for (s = 0; s < size; ++s) {
518         if (support[s] >= cMax) newSize += 1;
519         else newSize += 2;
520       }
521       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
522     }
523     break;
524   case REFINER_HYBRID_HEX_2D:
525     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
526     cMax = PetscMin(cEnd, cMax);
527     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
528     fMax = PetscMin(fEnd, fMax);
529     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
530     /* Interior cells have 4 faces */
531     for (c = cStart; c < cMax; ++c) {
532       for (r = 0; r < 4; ++r) {
533         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
534 
535         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
536       }
537     }
538     /* Hybrid cells have 4 faces */
539     for (c = cMax; c < cEnd; ++c) {
540       for (r = 0; r < 2; ++r) {
541         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
542 
543         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
544       }
545     }
546     /* Interior split faces have 2 vertices and the same cells as the parent */
547     for (f = fStart; f < fMax; ++f) {
548       for (r = 0; r < 2; ++r) {
549         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
550         PetscInt       size;
551 
552         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
553         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
554         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
555       }
556     }
557     /* Interior cell faces have 2 vertices and 2 cells */
558     for (c = cStart; c < cMax; ++c) {
559       for (r = 0; r < 4; ++r) {
560         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
561 
562         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
563         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
564       }
565     }
566     /* Hybrid faces have 2 vertices and the same cells */
567     for (f = fMax; f < fEnd; ++f) {
568       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
569       PetscInt       size;
570 
571       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
572       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
573       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
574     }
575     /* Hybrid cell faces have 2 vertices and 2 cells */
576     for (c = cMax; c < cEnd; ++c) {
577       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
578 
579       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
580       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
581     }
582     /* Old vertices have identical supports */
583     for (v = vStart; v < vEnd; ++v) {
584       const PetscInt newp = vStartNew + (v - vStart);
585       PetscInt       size;
586 
587       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
588       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
589     }
590     /* Face vertices have 2 + cells supports */
591     for (f = fStart; f < fMax; ++f) {
592       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
593       PetscInt       size;
594 
595       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
596       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
597     }
598     /* Cell vertices have 4 supports */
599     for (c = cStart; c < cMax; ++c) {
600       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
601 
602       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
603     }
604     break;
605   case REFINER_SIMPLEX_3D:
606     /* All cells have 4 faces */
607     for (c = cStart; c < cEnd; ++c) {
608       for (r = 0; r < 8; ++r) {
609         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
610 
611         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
612       }
613     }
614     /* Split faces have 3 edges and the same cells as the parent */
615     for (f = fStart; f < fEnd; ++f) {
616       for (r = 0; r < 4; ++r) {
617         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
618         PetscInt       size;
619 
620         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
621         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
622         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
623       }
624     }
625     /* Interior cell faces have 3 edges and 2 cells */
626     for (c = cStart; c < cEnd; ++c) {
627       for (r = 0; r < 8; ++r) {
628         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + r;
629 
630         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
631         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
632       }
633     }
634     /* Split edges have 2 vertices and the same faces */
635     for (e = eStart; e < eEnd; ++e) {
636       for (r = 0; r < 2; ++r) {
637         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
638         PetscInt       size;
639 
640         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
641         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
642         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
643       }
644     }
645     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
646     for (f = fStart; f < fEnd; ++f) {
647       for (r = 0; r < 3; ++r) {
648         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
649         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
650         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;
651 
652         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
653         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
654         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
655         for (s = 0; s < supportSize; ++s) {
656           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
657           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
658           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
659           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
660           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
661           er = GetTetSomethingInverse_Static(ornt[c], r);
662           if (er == eint[c]) {
663             intFaces += 1;
664           } else {
665             intFaces += 2;
666           }
667         }
668         ierr = DMPlexSetSupportSize(rdm, newp, 2+intFaces);CHKERRQ(ierr);
669       }
670     }
671     /* Interior cell edges have 2 vertices and 4 faces */
672     for (c = cStart; c < cEnd; ++c) {
673       const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
674 
675       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
676       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
677     }
678     /* Old vertices have identical supports */
679     for (v = vStart; v < vEnd; ++v) {
680       const PetscInt newp = vStartNew + (v - vStart);
681       PetscInt       size;
682 
683       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
684       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
685     }
686     /* Edge vertices have 2 + faces*2 + cells*0/1 supports */
687     for (e = eStart; e < eEnd; ++e) {
688       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
689       PetscInt       size, *star = NULL, starSize, s, cellSize = 0;
690 
691       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
692       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
693       for (s = 0; s < starSize*2; s += 2) {
694         const PetscInt *cone, *ornt;
695         PetscInt        e01, e23;
696 
697         if ((star[s] >= cStart) && (star[s] < cEnd)) {
698           /* Check edge 0-1 */
699           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
700           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
701           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
702           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
703           /* Check edge 2-3 */
704           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
705           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
706           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
707           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
708           if ((e01 == e) || (e23 == e)) ++cellSize;
709         }
710       }
711       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
712       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2 + cellSize);CHKERRQ(ierr);
713     }
714     break;
715   case REFINER_HYBRID_SIMPLEX_3D:
716     ierr = DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 8*(cMax - cStart),
717                                  eStartNew + 2*(eMax - eStart) + 3*(fMax - fStart) + (cMax - cStart), PETSC_DETERMINE);CHKERRQ(ierr);
718     /* Interior cells have 4 faces */
719     for (c = cStart; c < cMax; ++c) {
720       for (r = 0; r < 8; ++r) {
721         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
722 
723         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
724       }
725     }
726     /* Hybrid cells have 5 faces */
727     for (c = cMax; c < cEnd; ++c) {
728       for (r = 0; r < 4; ++r) {
729         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;
730 
731         ierr = DMPlexSetConeSize(rdm, newp, 5);CHKERRQ(ierr);
732       }
733     }
734     /* Interior split faces have 3 edges and the same cells as the parent */
735     for (f = fStart; f < fMax; ++f) {
736       for (r = 0; r < 4; ++r) {
737         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
738         PetscInt       size;
739 
740         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
741         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
742         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
743       }
744     }
745     /* Interior cell faces have 3 edges and 2 cells */
746     for (c = cStart; c < cMax; ++c) {
747       for (r = 0; r < 8; ++r) {
748         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + r;
749 
750         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
751         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
752       }
753     }
754     /* Hybrid split faces have 4 edges and the same cells as the parent */
755     for (f = fMax; f < fEnd; ++f) {
756       for (r = 0; r < 2; ++r) {
757         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
758         PetscInt       size;
759 
760         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
761         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
762         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
763       }
764     }
765     /* Hybrid cells faces have 4 edges and 2 cells */
766     for (c = cMax; c < cEnd; ++c) {
767       for (r = 0; r < 3; ++r) {
768         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + r;
769 
770         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
771         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
772       }
773     }
774     /* Interior split edges have 2 vertices and the same faces */
775     for (e = eStart; e < eMax; ++e) {
776       for (r = 0; r < 2; ++r) {
777         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
778         PetscInt       size;
779 
780         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
781         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
782         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
783       }
784     }
785     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
786     for (f = fStart; f < fMax; ++f) {
787       for (r = 0; r < 3; ++r) {
788         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
789         const PetscInt *cone, *ornt, *support, eint[4] = {1, 0, 2, 0};
790         PetscInt        coneSize, c, supportSize, s, er, intFaces = 0;
791 
792         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
793         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
794         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
795         for (s = 0; s < supportSize; ++s) {
796           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
797           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
798           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
799           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
800           if (support[s] < cMax) {
801             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
802             er = GetTetSomethingInverse_Static(ornt[c], r);
803             if (er == eint[c]) {
804               intFaces += 1;
805             } else {
806               intFaces += 2;
807             }
808           } else {
809             intFaces += 1;
810           }
811         }
812         ierr = DMPlexSetSupportSize(rdm, newp, 2+intFaces);CHKERRQ(ierr);
813       }
814     }
815     /* Interior cell edges have 2 vertices and 4 faces */
816     for (c = cStart; c < cMax; ++c) {
817       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
818 
819       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
820       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
821     }
822     /* Hybrid edges have 2 vertices and the same faces */
823     for (e = eMax; e < eEnd; ++e) {
824       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
825       PetscInt       size;
826 
827       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
828       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
829       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
830     }
831     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
832     for (f = fMax; f < fEnd; ++f) {
833       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
834       PetscInt       size;
835 
836       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
837       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
838       ierr = DMPlexSetSupportSize(rdm, newp, 2+2*size);CHKERRQ(ierr);
839     }
840     /* Interior vertices have identical supports */
841     for (v = vStart; v < vEnd; ++v) {
842       const PetscInt newp = vStartNew + (v - vStart);
843       PetscInt       size;
844 
845       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
846       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
847     }
848     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
849     for (e = eStart; e < eMax; ++e) {
850       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
851       const PetscInt *support;
852       PetscInt        size, *star = NULL, starSize, s, faceSize = 0, cellSize = 0;
853 
854       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
855       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
856       for (s = 0; s < size; ++s) {
857         if (support[s] < fMax) faceSize += 2;
858         else                   faceSize += 1;
859       }
860       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
861       for (s = 0; s < starSize*2; s += 2) {
862         const PetscInt *cone, *ornt;
863         PetscInt        e01, e23;
864 
865         if ((star[s] >= cStart) && (star[s] < cMax)) {
866           /* Check edge 0-1 */
867           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
868           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
869           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
870           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
871           /* Check edge 2-3 */
872           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
873           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
874           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
875           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
876           if ((e01 == e) || (e23 == e)) ++cellSize;
877         }
878       }
879       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
880       ierr = DMPlexSetSupportSize(rdm, newp, 2 + faceSize + cellSize);CHKERRQ(ierr);
881     }
882     break;
883   case REFINER_HEX_3D:
884     /* All cells have 6 faces */
885     for (c = cStart; c < cEnd; ++c) {
886       for (r = 0; r < 8; ++r) {
887         const PetscInt newp = (c - cStart)*8 + r;
888 
889         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
890       }
891     }
892     /* Split faces have 4 edges and the same cells as the parent */
893     for (f = fStart; f < fEnd; ++f) {
894       for (r = 0; r < 4; ++r) {
895         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
896         PetscInt       size;
897 
898         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
899         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
900         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
901       }
902     }
903     /* Interior faces have 4 edges and 2 cells */
904     for (c = cStart; c < cEnd; ++c) {
905       for (r = 0; r < 12; ++r) {
906         const PetscInt newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
907 
908         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
909         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
910       }
911     }
912     /* Split edges have 2 vertices and the same faces as the parent */
913     for (e = eStart; e < eEnd; ++e) {
914       for (r = 0; r < 2; ++r) {
915         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
916         PetscInt       size;
917 
918         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
919         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
920         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
921       }
922     }
923     /* Face edges have 2 vertices and 2+cells faces */
924     for (f = fStart; f < fEnd; ++f) {
925       for (r = 0; r < 4; ++r) {
926         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
927         PetscInt       size;
928 
929         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
930         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
931         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
932       }
933     }
934     /* Cell edges have 2 vertices and 4 faces */
935     for (c = cStart; c < cEnd; ++c) {
936       for (r = 0; r < 6; ++r) {
937         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
938 
939         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
940         ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
941       }
942     }
943     /* Old vertices have identical supports */
944     for (v = vStart; v < vEnd; ++v) {
945       const PetscInt newp = vStartNew + (v - vStart);
946       PetscInt       size;
947 
948       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
949       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
950     }
951     /* Edge vertices have 2 + faces supports */
952     for (e = eStart; e < eEnd; ++e) {
953       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
954       PetscInt       size;
955 
956       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
957       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
958     }
959     /* Face vertices have 4 + cells supports */
960     for (f = fStart; f < fEnd; ++f) {
961       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
962       PetscInt       size;
963 
964       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
965       ierr = DMPlexSetSupportSize(rdm, newp, 4 + size);CHKERRQ(ierr);
966     }
967     /* Cell vertices have 6 supports */
968     for (c = cStart; c < cEnd; ++c) {
969       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
970 
971       ierr = DMPlexSetSupportSize(rdm, newp, 6);CHKERRQ(ierr);
972     }
973     break;
974   case REFINER_HYBRID_HEX_3D:
975     ierr = DMPlexSetHybridBounds(rdm, cStartNew + 8*(cMax-cStart), fStartNew + 4*(fMax - fStart) + 12*(cMax - cStart),
976                                  eStartNew + 2*(eMax - eStart) + 4*(fMax - fStart) + 6*(cMax - cStart), PETSC_DETERMINE);CHKERRQ(ierr);
977     /* Interior cells have 6 faces */
978     for (c = cStart; c < cMax; ++c) {
979       for (r = 0; r < 8; ++r) {
980         const PetscInt newp = cStartNew + (c - cStart)*8 + r;
981 
982         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
983       }
984     }
985     /* Hybrid cells have 6 faces */
986     for (c = cMax; c < cEnd; ++c) {
987       for (r = 0; r < 4; ++r) {
988         const PetscInt newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + r;
989 
990         ierr = DMPlexSetConeSize(rdm, newp, 6);CHKERRQ(ierr);
991       }
992     }
993     /* Interior split faces have 4 edges and the same cells as the parent */
994     for (f = fStart; f < fMax; ++f) {
995       for (r = 0; r < 4; ++r) {
996         const PetscInt newp = fStartNew + (f - fStart)*4 + r;
997         PetscInt       size;
998 
999         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1000         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1001         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1002       }
1003     }
1004     /* Interior cell faces have 4 edges and 2 cells */
1005     for (c = cStart; c < cMax; ++c) {
1006       for (r = 0; r < 12; ++r) {
1007         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
1008 
1009         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1010         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1011       }
1012     }
1013     /* Hybrid split faces have 4 edges and the same cells as the parent */
1014     for (f = fMax; f < fEnd; ++f) {
1015       for (r = 0; r < 2; ++r) {
1016         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
1017         PetscInt       size;
1018 
1019         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1020         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1021         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1022       }
1023     }
1024     /* Hybrid cells faces have 4 edges and 2 cells */
1025     for (c = cMax; c < cEnd; ++c) {
1026       for (r = 0; r < 4; ++r) {
1027         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + r;
1028 
1029         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
1030         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
1031       }
1032     }
1033     /* Interior split edges have 2 vertices and the same faces as the parent */
1034     for (e = eStart; e < eMax; ++e) {
1035       for (r = 0; r < 2; ++r) {
1036         const PetscInt newp = eStartNew + (e - eStart)*2 + r;
1037         PetscInt       size;
1038 
1039         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1040         ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1041         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1042       }
1043     }
1044     /* Interior face edges have 2 vertices and 2+cells faces */
1045     for (f = fStart; f < fMax; ++f) {
1046       for (r = 0; r < 4; ++r) {
1047         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
1048         PetscInt       size;
1049 
1050         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1051         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1052         ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1053       }
1054     }
1055     /* Interior cell edges have 2 vertices and 4 faces */
1056     for (c = cStart; c < cMax; ++c) {
1057       for (r = 0; r < 6; ++r) {
1058         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
1059 
1060         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1061         ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1062       }
1063     }
1064     /* Hybrid edges have 2 vertices and the same faces */
1065     for (e = eMax; e < eEnd; ++e) {
1066       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
1067       PetscInt       size;
1068 
1069       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1070       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1071       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1072     }
1073     /* Hybrid face edges have 2 vertices and 2+cells faces */
1074     for (f = fMax; f < fEnd; ++f) {
1075       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
1076       PetscInt       size;
1077 
1078       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1079       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1080       ierr = DMPlexSetSupportSize(rdm, newp, 2+size);CHKERRQ(ierr);
1081     }
1082     /* Hybrid cell edges have 2 vertices and 4 faces */
1083     for (c = cMax; c < cEnd; ++c) {
1084       const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
1085 
1086       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
1087       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
1088     }
1089     /* Interior vertices have identical supports */
1090     for (v = vStart; v < vEnd; ++v) {
1091       const PetscInt newp = vStartNew + (v - vStart);
1092       PetscInt       size;
1093 
1094       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1095       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
1096     }
1097     /* Interior edge vertices have 2 + faces supports */
1098     for (e = eStart; e < eMax; ++e) {
1099       const PetscInt newp = vStartNew + (vEnd - vStart) + (e - eStart);
1100       PetscInt       size;
1101 
1102       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
1103       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
1104     }
1105     /* Interior face vertices have 4 + cells supports */
1106     for (f = fStart; f < fMax; ++f) {
1107       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
1108       PetscInt       size;
1109 
1110       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1111       ierr = DMPlexSetSupportSize(rdm, newp, 4 + size);CHKERRQ(ierr);
1112     }
1113     /* Interior cell vertices have 6 supports */
1114     for (c = cStart; c < cMax; ++c) {
1115       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
1116 
1117       ierr = DMPlexSetSupportSize(rdm, newp, 6);CHKERRQ(ierr);
1118     }
1119     break;
1120   default:
1121     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
1122   }
1123   PetscFunctionReturn(0);
1124 }
1125 
1126 #undef __FUNCT__
1127 #define __FUNCT__ "CellRefinerSetCones"
1128 static PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
1129 {
1130   const PetscInt *faces, cellInd[4] = {0, 1, 2, 3};
1131   PetscInt        cStart,    cEnd,    cMax,    vStart,    vEnd, vMax, fStart,    fEnd,    fMax,    eStart,    eEnd,    eMax;
1132   PetscInt        cStartNew, cEndNew, cMaxNew, vStartNew, vEndNew,    fStartNew, fEndNew, fMaxNew, eStartNew, eEndNew, eMaxNew;
1133   PetscInt        depth, maxSupportSize, *supportRef, c, f, e, v, r, p;
1134   PetscErrorCode  ierr;
1135 
1136   PetscFunctionBegin;
1137   if (!refiner) PetscFunctionReturn(0);
1138   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1139   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
1140   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
1141   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1142   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
1143   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
1144   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
1145   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
1146   switch (refiner) {
1147   case REFINER_SIMPLEX_1D:
1148     /* Max support size of refined mesh is 2 */
1149     ierr = PetscMalloc1(2, &supportRef);CHKERRQ(ierr);
1150     /* All cells have 2 vertices */
1151     for (c = cStart; c < cEnd; ++c) {
1152       const PetscInt  newv = vStartNew + (vEnd - vStart) + (c - cStart);
1153 
1154       for (r = 0; r < 2; ++r) {
1155         const PetscInt newp = cStartNew + (c - cStart)*2 + r;
1156         const PetscInt *cone;
1157         PetscInt        coneNew[2];
1158 
1159         ierr             = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1160         coneNew[0]       = vStartNew + (cone[0] - vStart);
1161         coneNew[1]       = vStartNew + (cone[1] - vStart);
1162         coneNew[(r+1)%2] = newv;
1163         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1164 #if 1
1165         if ((newp < cStartNew) || (newp >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp, cStartNew, cEndNew);
1166         for (p = 0; p < 2; ++p) {
1167           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);
1168         }
1169 #endif
1170       }
1171     }
1172     /* Old vertices have identical supports */
1173     for (v = vStart; v < vEnd; ++v) {
1174       const PetscInt  newp = vStartNew + (v - vStart);
1175       const PetscInt *support, *cone;
1176       PetscInt        size, s;
1177 
1178       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1179       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1180       for (s = 0; s < size; ++s) {
1181         PetscInt r = 0;
1182 
1183         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1184         if (cone[1] == v) r = 1;
1185         supportRef[s] = cStartNew + (support[s] - cStart)*2 + r;
1186       }
1187       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1188 #if 1
1189       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1190       for (p = 0; p < size; ++p) {
1191         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);
1192       }
1193 #endif
1194     }
1195     /* Cell vertices have support of 2 cells */
1196     for (c = cStart; c < cEnd; ++c) {
1197       const PetscInt  newp = vStartNew + (vEnd - vStart) + (c - cStart);
1198 
1199       supportRef[0] = cStartNew + (c - cStart)*2 + 0;
1200       supportRef[1] = cStartNew + (c - cStart)*2 + 1;
1201       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1202 #if 1
1203       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1204       for (p = 0; p < 2; ++p) {
1205         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);
1206       }
1207 #endif
1208     }
1209     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1210     break;
1211   case REFINER_SIMPLEX_2D:
1212     /*
1213      2
1214      |\
1215      | \
1216      |  \
1217      |   \
1218      | C  \
1219      |     \
1220      |      \
1221      2---1---1
1222      |\  D  / \
1223      | 2   0   \
1224      |A \ /  B  \
1225      0---0-------1
1226      */
1227     /* All cells have 3 faces */
1228     for (c = cStart; c < cEnd; ++c) {
1229       const PetscInt  newp = cStartNew + (c - cStart)*4;
1230       const PetscInt *cone, *ornt;
1231       PetscInt        coneNew[3], orntNew[3];
1232 
1233       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1234       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1235       /* A triangle */
1236       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1237       orntNew[0] = ornt[0];
1238       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1239       orntNew[1] = -2;
1240       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1241       orntNew[2] = ornt[2];
1242       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1243       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1244 #if 1
1245       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);
1246       for (p = 0; p < 3; ++p) {
1247         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);
1248       }
1249 #endif
1250       /* B triangle */
1251       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1252       orntNew[0] = ornt[0];
1253       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1254       orntNew[1] = ornt[1];
1255       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1256       orntNew[2] = -2;
1257       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1258       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1259 #if 1
1260       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);
1261       for (p = 0; p < 3; ++p) {
1262         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);
1263       }
1264 #endif
1265       /* C triangle */
1266       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1267       orntNew[0] = -2;
1268       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1269       orntNew[1] = ornt[1];
1270       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1271       orntNew[2] = ornt[2];
1272       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1273       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1274 #if 1
1275       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);
1276       for (p = 0; p < 3; ++p) {
1277         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);
1278       }
1279 #endif
1280       /* D triangle */
1281       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
1282       orntNew[0] = 0;
1283       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
1284       orntNew[1] = 0;
1285       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
1286       orntNew[2] = 0;
1287       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1288       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1289 #if 1
1290       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);
1291       for (p = 0; p < 3; ++p) {
1292         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);
1293       }
1294 #endif
1295     }
1296     /* Split faces have 2 vertices and the same cells as the parent */
1297     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1298     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
1299     for (f = fStart; f < fEnd; ++f) {
1300       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1301 
1302       for (r = 0; r < 2; ++r) {
1303         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1304         const PetscInt *cone, *ornt, *support;
1305         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1306 
1307         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1308         coneNew[0]       = vStartNew + (cone[0] - vStart);
1309         coneNew[1]       = vStartNew + (cone[1] - vStart);
1310         coneNew[(r+1)%2] = newv;
1311         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1312 #if 1
1313         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1314         for (p = 0; p < 2; ++p) {
1315           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);
1316         }
1317 #endif
1318         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1319         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1320         for (s = 0; s < supportSize; ++s) {
1321           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1322           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1323           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1324           for (c = 0; c < coneSize; ++c) {
1325             if (cone[c] == f) break;
1326           }
1327           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1328         }
1329         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1330 #if 1
1331         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1332         for (p = 0; p < supportSize; ++p) {
1333           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);
1334         }
1335 #endif
1336       }
1337     }
1338     /* Interior faces have 2 vertices and 2 cells */
1339     for (c = cStart; c < cEnd; ++c) {
1340       const PetscInt *cone;
1341 
1342       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1343       for (r = 0; r < 3; ++r) {
1344         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
1345         PetscInt       coneNew[2];
1346         PetscInt       supportNew[2];
1347 
1348         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
1349         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
1350         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1351 #if 1
1352         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1353         for (p = 0; p < 2; ++p) {
1354           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);
1355         }
1356 #endif
1357         supportNew[0] = (c - cStart)*4 + (r+1)%3;
1358         supportNew[1] = (c - cStart)*4 + 3;
1359         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1360 #if 1
1361         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1362         for (p = 0; p < 2; ++p) {
1363           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);
1364         }
1365 #endif
1366       }
1367     }
1368     /* Old vertices have identical supports */
1369     for (v = vStart; v < vEnd; ++v) {
1370       const PetscInt  newp = vStartNew + (v - vStart);
1371       const PetscInt *support, *cone;
1372       PetscInt        size, s;
1373 
1374       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1375       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1376       for (s = 0; s < size; ++s) {
1377         PetscInt r = 0;
1378 
1379         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1380         if (cone[1] == v) r = 1;
1381         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1382       }
1383       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1384 #if 1
1385       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1386       for (p = 0; p < size; ++p) {
1387         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);
1388       }
1389 #endif
1390     }
1391     /* Face vertices have 2 + cells*2 supports */
1392     for (f = fStart; f < fEnd; ++f) {
1393       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1394       const PetscInt *cone, *support;
1395       PetscInt        size, s;
1396 
1397       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1398       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1399       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1400       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1401       for (s = 0; s < size; ++s) {
1402         PetscInt r = 0;
1403 
1404         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1405         if      (cone[1] == f) r = 1;
1406         else if (cone[2] == f) r = 2;
1407         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
1408         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
1409       }
1410       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1411 #if 1
1412       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1413       for (p = 0; p < 2+size*2; ++p) {
1414         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);
1415       }
1416 #endif
1417     }
1418     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1419     break;
1420   case REFINER_HEX_2D:
1421     /*
1422      3---------2---------2
1423      |         |         |
1424      |    D    2    C    |
1425      |         |         |
1426      3----3----0----1----1
1427      |         |         |
1428      |    A    0    B    |
1429      |         |         |
1430      0---------0---------1
1431      */
1432     /* All cells have 4 faces */
1433     for (c = cStart; c < cEnd; ++c) {
1434       const PetscInt  newp = (c - cStart)*4;
1435       const PetscInt *cone, *ornt;
1436       PetscInt        coneNew[4], orntNew[4];
1437 
1438       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1439       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1440       /* A quad */
1441       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1442       orntNew[0] = ornt[0];
1443       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
1444       orntNew[1] = 0;
1445       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
1446       orntNew[2] = -2;
1447       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
1448       orntNew[3] = ornt[3];
1449       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1450       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1451 #if 1
1452       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);
1453       for (p = 0; p < 4; ++p) {
1454         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);
1455       }
1456 #endif
1457       /* B quad */
1458       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1459       orntNew[0] = ornt[0];
1460       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1461       orntNew[1] = ornt[1];
1462       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
1463       orntNew[2] = 0;
1464       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
1465       orntNew[3] = -2;
1466       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1467       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1468 #if 1
1469       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);
1470       for (p = 0; p < 4; ++p) {
1471         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);
1472       }
1473 #endif
1474       /* C quad */
1475       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
1476       orntNew[0] = -2;
1477       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1478       orntNew[1] = ornt[1];
1479       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1480       orntNew[2] = ornt[2];
1481       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
1482       orntNew[3] = 0;
1483       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1484       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1485 #if 1
1486       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);
1487       for (p = 0; p < 4; ++p) {
1488         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);
1489       }
1490 #endif
1491       /* D quad */
1492       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
1493       orntNew[0] = 0;
1494       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
1495       orntNew[1] = -2;
1496       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1497       orntNew[2] = ornt[2];
1498       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
1499       orntNew[3] = ornt[3];
1500       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1501       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1502 #if 1
1503       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);
1504       for (p = 0; p < 4; ++p) {
1505         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);
1506       }
1507 #endif
1508     }
1509     /* Split faces have 2 vertices and the same cells as the parent */
1510     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1511     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
1512     for (f = fStart; f < fEnd; ++f) {
1513       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1514 
1515       for (r = 0; r < 2; ++r) {
1516         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1517         const PetscInt *cone, *ornt, *support;
1518         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1519 
1520         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1521         coneNew[0]       = vStartNew + (cone[0] - vStart);
1522         coneNew[1]       = vStartNew + (cone[1] - vStart);
1523         coneNew[(r+1)%2] = newv;
1524         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1525 #if 1
1526         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1527         for (p = 0; p < 2; ++p) {
1528           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);
1529         }
1530 #endif
1531         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1532         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1533         for (s = 0; s < supportSize; ++s) {
1534           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1535           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1536           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1537           for (c = 0; c < coneSize; ++c) {
1538             if (cone[c] == f) break;
1539           }
1540           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
1541         }
1542         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1543 #if 1
1544         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1545         for (p = 0; p < supportSize; ++p) {
1546           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);
1547         }
1548 #endif
1549       }
1550     }
1551     /* Interior faces have 2 vertices and 2 cells */
1552     for (c = cStart; c < cEnd; ++c) {
1553       const PetscInt *cone;
1554       PetscInt        coneNew[2], supportNew[2];
1555 
1556       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1557       for (r = 0; r < 4; ++r) {
1558         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
1559 
1560         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
1561         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
1562         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1563 #if 1
1564         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1565         for (p = 0; p < 2; ++p) {
1566           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);
1567         }
1568 #endif
1569         supportNew[0] = (c - cStart)*4 + r;
1570         supportNew[1] = (c - cStart)*4 + (r+1)%4;
1571         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1572 #if 1
1573         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1574         for (p = 0; p < 2; ++p) {
1575           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);
1576         }
1577 #endif
1578       }
1579     }
1580     /* Old vertices have identical supports */
1581     for (v = vStart; v < vEnd; ++v) {
1582       const PetscInt  newp = vStartNew + (v - vStart);
1583       const PetscInt *support, *cone;
1584       PetscInt        size, s;
1585 
1586       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1587       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1588       for (s = 0; s < size; ++s) {
1589         PetscInt r = 0;
1590 
1591         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1592         if (cone[1] == v) r = 1;
1593         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1594       }
1595       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1596 #if 1
1597       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1598       for (p = 0; p < size; ++p) {
1599         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);
1600       }
1601 #endif
1602     }
1603     /* Face vertices have 2 + cells supports */
1604     for (f = fStart; f < fEnd; ++f) {
1605       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1606       const PetscInt *cone, *support;
1607       PetscInt        size, s;
1608 
1609       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1610       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1611       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1612       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1613       for (s = 0; s < size; ++s) {
1614         PetscInt r = 0;
1615 
1616         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1617         if      (cone[1] == f) r = 1;
1618         else if (cone[2] == f) r = 2;
1619         else if (cone[3] == f) r = 3;
1620         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
1621       }
1622       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1623 #if 1
1624       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1625       for (p = 0; p < 2+size; ++p) {
1626         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);
1627       }
1628 #endif
1629     }
1630     /* Cell vertices have 4 supports */
1631     for (c = cStart; c < cEnd; ++c) {
1632       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
1633       PetscInt       supportNew[4];
1634 
1635       for (r = 0; r < 4; ++r) {
1636         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
1637       }
1638       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1639     }
1640     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1641     break;
1642   case REFINER_HYBRID_SIMPLEX_2D:
1643     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
1644     cMax = PetscMin(cEnd, cMax);
1645     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
1646     fMax = PetscMin(fEnd, fMax);
1647     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);CHKERRQ(ierr);
1648     /* Interior cells have 3 faces */
1649     for (c = cStart; c < cMax; ++c) {
1650       const PetscInt  newp = cStartNew + (c - cStart)*4;
1651       const PetscInt *cone, *ornt;
1652       PetscInt        coneNew[3], orntNew[3];
1653 
1654       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1655       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1656       /* A triangle */
1657       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1658       orntNew[0] = ornt[0];
1659       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
1660       orntNew[1] = -2;
1661       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
1662       orntNew[2] = ornt[2];
1663       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1664       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1665 #if 1
1666       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);
1667       for (p = 0; p < 3; ++p) {
1668         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);
1669       }
1670 #endif
1671       /* B triangle */
1672       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
1673       orntNew[0] = ornt[0];
1674       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
1675       orntNew[1] = ornt[1];
1676       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
1677       orntNew[2] = -2;
1678       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1679       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1680 #if 1
1681       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);
1682       for (p = 0; p < 3; ++p) {
1683         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);
1684       }
1685 #endif
1686       /* C triangle */
1687       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
1688       orntNew[0] = -2;
1689       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
1690       orntNew[1] = ornt[1];
1691       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
1692       orntNew[2] = ornt[2];
1693       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
1694       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
1695 #if 1
1696       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);
1697       for (p = 0; p < 3; ++p) {
1698         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);
1699       }
1700 #endif
1701       /* D triangle */
1702       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
1703       orntNew[0] = 0;
1704       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
1705       orntNew[1] = 0;
1706       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
1707       orntNew[2] = 0;
1708       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
1709       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
1710 #if 1
1711       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);
1712       for (p = 0; p < 3; ++p) {
1713         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);
1714       }
1715 #endif
1716     }
1717     /*
1718      2----3----3
1719      |         |
1720      |    B    |
1721      |         |
1722      0----4--- 1
1723      |         |
1724      |    A    |
1725      |         |
1726      0----2----1
1727      */
1728     /* Hybrid cells have 4 faces */
1729     for (c = cMax; c < cEnd; ++c) {
1730       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
1731       const PetscInt *cone, *ornt;
1732       PetscInt        coneNew[4], orntNew[4], r;
1733 
1734       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1735       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1736       r    = (ornt[0] < 0 ? 1 : 0);
1737       /* A quad */
1738       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + r;
1739       orntNew[0]   = ornt[0];
1740       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + r;
1741       orntNew[1]   = ornt[1];
1742       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2+r] - fMax);
1743       orntNew[2+r] = 0;
1744       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
1745       orntNew[3-r] = 0;
1746       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1747       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
1748 #if 1
1749       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);
1750       for (p = 0; p < 4; ++p) {
1751         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);
1752       }
1753 #endif
1754       /* B quad */
1755       coneNew[0]   = fStartNew + (cone[0] - fStart)*2 + 1-r;
1756       orntNew[0]   = ornt[0];
1757       coneNew[1]   = fStartNew + (cone[1] - fStart)*2 + 1-r;
1758       orntNew[1]   = ornt[1];
1759       coneNew[2+r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
1760       orntNew[2+r] = 0;
1761       coneNew[3-r] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3-r] - fMax);
1762       orntNew[3-r] = 0;
1763       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
1764       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
1765 #if 1
1766       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);
1767       for (p = 0; p < 4; ++p) {
1768         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);
1769       }
1770 #endif
1771     }
1772     /* Interior split faces have 2 vertices and the same cells as the parent */
1773     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
1774     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
1775     for (f = fStart; f < fMax; ++f) {
1776       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
1777 
1778       for (r = 0; r < 2; ++r) {
1779         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
1780         const PetscInt *cone, *ornt, *support;
1781         PetscInt        coneNew[2], coneSize, c, supportSize, s;
1782 
1783         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1784         coneNew[0]       = vStartNew + (cone[0] - vStart);
1785         coneNew[1]       = vStartNew + (cone[1] - vStart);
1786         coneNew[(r+1)%2] = newv;
1787         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1788 #if 1
1789         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1790         for (p = 0; p < 2; ++p) {
1791           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);
1792         }
1793 #endif
1794         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
1795         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1796         for (s = 0; s < supportSize; ++s) {
1797           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
1798           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1799           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1800           for (c = 0; c < coneSize; ++c) if (cone[c] == f) break;
1801           if (support[s] >= cMax) {
1802             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[c] < 0 ? 1-r : r);
1803           } else {
1804             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%3 : (c+r)%3);
1805           }
1806         }
1807         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1808 #if 1
1809         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1810         for (p = 0; p < supportSize; ++p) {
1811           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);
1812         }
1813 #endif
1814       }
1815     }
1816     /* Interior cell faces have 2 vertices and 2 cells */
1817     for (c = cStart; c < cMax; ++c) {
1818       const PetscInt *cone;
1819 
1820       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1821       for (r = 0; r < 3; ++r) {
1822         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
1823         PetscInt       coneNew[2];
1824         PetscInt       supportNew[2];
1825 
1826         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
1827         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
1828         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1829 #if 1
1830         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1831         for (p = 0; p < 2; ++p) {
1832           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);
1833         }
1834 #endif
1835         supportNew[0] = (c - cStart)*4 + (r+1)%3;
1836         supportNew[1] = (c - cStart)*4 + 3;
1837         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1838 #if 1
1839         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1840         for (p = 0; p < 2; ++p) {
1841           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);
1842         }
1843 #endif
1844       }
1845     }
1846     /* Interior hybrid faces have 2 vertices and the same cells */
1847     for (f = fMax; f < fEnd; ++f) {
1848       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
1849       const PetscInt *cone, *ornt;
1850       const PetscInt *support;
1851       PetscInt        coneNew[2];
1852       PetscInt        supportNew[2];
1853       PetscInt        size, s, r;
1854 
1855       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
1856       coneNew[0] = vStartNew + (cone[0] - vStart);
1857       coneNew[1] = vStartNew + (cone[1] - vStart);
1858       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1859 #if 1
1860       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1861       for (p = 0; p < 2; ++p) {
1862         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);
1863       }
1864 #endif
1865       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1866       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1867       for (s = 0; s < size; ++s) {
1868         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1869         ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
1870         for (r = 0; r < 2; ++r) {
1871           if (cone[r+2] == f) break;
1872         }
1873         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + (ornt[0] < 0 ? 1-r : r);
1874       }
1875       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1876 #if 1
1877       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1878       for (p = 0; p < size; ++p) {
1879         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);
1880       }
1881 #endif
1882     }
1883     /* Cell hybrid faces have 2 vertices and 2 cells */
1884     for (c = cMax; c < cEnd; ++c) {
1885       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
1886       const PetscInt *cone;
1887       PetscInt        coneNew[2];
1888       PetscInt        supportNew[2];
1889 
1890       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1891       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
1892       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
1893       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
1894 #if 1
1895       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1896       for (p = 0; p < 2; ++p) {
1897         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);
1898       }
1899 #endif
1900       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
1901       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
1902       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
1903 #if 1
1904       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
1905       for (p = 0; p < 2; ++p) {
1906         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);
1907       }
1908 #endif
1909     }
1910     /* Old vertices have identical supports */
1911     for (v = vStart; v < vEnd; ++v) {
1912       const PetscInt  newp = vStartNew + (v - vStart);
1913       const PetscInt *support, *cone;
1914       PetscInt        size, s;
1915 
1916       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
1917       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
1918       for (s = 0; s < size; ++s) {
1919         if (support[s] >= fMax) {
1920           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
1921         } else {
1922           PetscInt r = 0;
1923 
1924           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1925           if (cone[1] == v) r = 1;
1926           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
1927         }
1928       }
1929       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1930 #if 1
1931       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1932       for (p = 0; p < size; ++p) {
1933         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);
1934       }
1935 #endif
1936     }
1937     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
1938     for (f = fStart; f < fMax; ++f) {
1939       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
1940       const PetscInt *cone, *support;
1941       PetscInt        size, newSize = 2, s;
1942 
1943       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
1944       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
1945       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
1946       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
1947       for (s = 0; s < size; ++s) {
1948         PetscInt r = 0;
1949 
1950         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
1951         if (support[s] >= cMax) {
1952           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
1953 
1954           newSize += 1;
1955         } else {
1956           if      (cone[1] == f) r = 1;
1957           else if (cone[2] == f) r = 2;
1958           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
1959           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
1960 
1961           newSize += 2;
1962         }
1963       }
1964       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
1965 #if 1
1966       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
1967       for (p = 0; p < newSize; ++p) {
1968         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);
1969       }
1970 #endif
1971     }
1972     ierr = PetscFree(supportRef);CHKERRQ(ierr);
1973     break;
1974   case REFINER_HYBRID_HEX_2D:
1975     /* Hybrid Hex 2D */
1976     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
1977     cMax = PetscMin(cEnd, cMax);
1978     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
1979     fMax = PetscMin(fEnd, fMax);
1980     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, NULL, NULL);CHKERRQ(ierr);
1981     /* Interior cells have 4 faces */
1982     for (c = cStart; c < cMax; ++c) {
1983       const PetscInt  newp = cStartNew + (c - cStart)*4;
1984       const PetscInt *cone, *ornt;
1985       PetscInt        coneNew[4], orntNew[4];
1986 
1987       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
1988       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
1989       /* A quad */
1990       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
1991       orntNew[0] = ornt[0];
1992       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
1993       orntNew[1] = 0;
1994       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
1995       orntNew[2] = -2;
1996       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
1997       orntNew[3] = ornt[3];
1998       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
1999       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2000 #if 1
2001       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);
2002       for (p = 0; p < 4; ++p) {
2003         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);
2004       }
2005 #endif
2006       /* B quad */
2007       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2008       orntNew[0] = ornt[0];
2009       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2010       orntNew[1] = ornt[1];
2011       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
2012       orntNew[2] = 0;
2013       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 0;
2014       orntNew[3] = -2;
2015       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2016       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2017 #if 1
2018       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);
2019       for (p = 0; p < 4; ++p) {
2020         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);
2021       }
2022 #endif
2023       /* C quad */
2024       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 1;
2025       orntNew[0] = -2;
2026       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2027       orntNew[1] = ornt[1];
2028       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
2029       orntNew[2] = ornt[2];
2030       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
2031       orntNew[3] = 0;
2032       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2033       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2034 #if 1
2035       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);
2036       for (p = 0; p < 4; ++p) {
2037         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);
2038       }
2039 #endif
2040       /* D quad */
2041       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 3;
2042       orntNew[0] = 0;
2043       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*4 + 2;
2044       orntNew[1] = -2;
2045       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
2046       orntNew[2] = ornt[2];
2047       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
2048       orntNew[3] = ornt[3];
2049       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2050       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2051 #if 1
2052       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);
2053       for (p = 0; p < 4; ++p) {
2054         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);
2055       }
2056 #endif
2057     }
2058     /*
2059      2----3----3
2060      |         |
2061      |    B    |
2062      |         |
2063      0----4--- 1
2064      |         |
2065      |    A    |
2066      |         |
2067      0----2----1
2068      */
2069     /* Hybrid cells have 4 faces */
2070     for (c = cMax; c < cEnd; ++c) {
2071       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
2072       const PetscInt *cone, *ornt;
2073       PetscInt        coneNew[4], orntNew[4];
2074 
2075       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2076       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2077       /* A quad */
2078       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
2079       orntNew[0] = ornt[0];
2080       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
2081       orntNew[1] = ornt[1];
2082       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[2] - fMax);
2083       orntNew[2] = 0;
2084       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
2085       orntNew[3] = 0;
2086       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2087       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2088 #if 1
2089       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);
2090       for (p = 0; p < 4; ++p) {
2091         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);
2092       }
2093 #endif
2094       /* B quad */
2095       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
2096       orntNew[0] = ornt[0];
2097       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
2098       orntNew[1] = ornt[1];
2099       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (fEnd    - fMax) + (c - cMax);
2100       orntNew[2] = 0;
2101       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*4 + (cone[3] - fMax);
2102       orntNew[3] = 0;
2103       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2104       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2105 #if 1
2106       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);
2107       for (p = 0; p < 4; ++p) {
2108         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);
2109       }
2110 #endif
2111     }
2112     /* Interior split faces have 2 vertices and the same cells as the parent */
2113     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2114     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2115     for (f = fStart; f < fMax; ++f) {
2116       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
2117 
2118       for (r = 0; r < 2; ++r) {
2119         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
2120         const PetscInt *cone, *ornt, *support;
2121         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2122 
2123         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2124         coneNew[0]       = vStartNew + (cone[0] - vStart);
2125         coneNew[1]       = vStartNew + (cone[1] - vStart);
2126         coneNew[(r+1)%2] = newv;
2127         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2128 #if 1
2129         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2130         for (p = 0; p < 2; ++p) {
2131           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);
2132         }
2133 #endif
2134         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2135         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2136         for (s = 0; s < supportSize; ++s) {
2137           if (support[s] >= cMax) {
2138             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
2139           } else {
2140             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2141             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2142             ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2143             for (c = 0; c < coneSize; ++c) {
2144               if (cone[c] == f) break;
2145             }
2146             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
2147           }
2148         }
2149         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2150 #if 1
2151         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2152         for (p = 0; p < supportSize; ++p) {
2153           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);
2154         }
2155 #endif
2156       }
2157     }
2158     /* Interior cell faces have 2 vertices and 2 cells */
2159     for (c = cStart; c < cMax; ++c) {
2160       const PetscInt *cone;
2161 
2162       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2163       for (r = 0; r < 4; ++r) {
2164         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
2165         PetscInt       coneNew[2], supportNew[2];
2166 
2167         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
2168         coneNew[1] = vStartNew + (vEnd - vStart) + (fMax    - fStart) + (c - cStart);
2169         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2170 #if 1
2171         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2172         for (p = 0; p < 2; ++p) {
2173           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);
2174         }
2175 #endif
2176         supportNew[0] = (c - cStart)*4 + r;
2177         supportNew[1] = (c - cStart)*4 + (r+1)%4;
2178         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2179 #if 1
2180         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2181         for (p = 0; p < 2; ++p) {
2182           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);
2183         }
2184 #endif
2185       }
2186     }
2187     /* Hybrid faces have 2 vertices and the same cells */
2188     for (f = fMax; f < fEnd; ++f) {
2189       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (f - fMax);
2190       const PetscInt *cone, *support;
2191       PetscInt        coneNew[2], supportNew[2];
2192       PetscInt        size, s, r;
2193 
2194       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2195       coneNew[0] = vStartNew + (cone[0] - vStart);
2196       coneNew[1] = vStartNew + (cone[1] - vStart);
2197       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2198 #if 1
2199       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2200       for (p = 0; p < 2; ++p) {
2201         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);
2202       }
2203 #endif
2204       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2205       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2206       for (s = 0; s < size; ++s) {
2207         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2208         for (r = 0; r < 2; ++r) {
2209           if (cone[r+2] == f) break;
2210         }
2211         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
2212       }
2213       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2214 #if 1
2215       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2216       for (p = 0; p < size; ++p) {
2217         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);
2218       }
2219 #endif
2220     }
2221     /* Cell hybrid faces have 2 vertices and 2 cells */
2222     for (c = cMax; c < cEnd; ++c) {
2223       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (c - cMax);
2224       const PetscInt *cone;
2225       PetscInt        coneNew[2], supportNew[2];
2226 
2227       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2228       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
2229       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
2230       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2231 #if 1
2232       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2233       for (p = 0; p < 2; ++p) {
2234         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);
2235       }
2236 #endif
2237       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
2238       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
2239       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2240 #if 1
2241       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2242       for (p = 0; p < 2; ++p) {
2243         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);
2244       }
2245 #endif
2246     }
2247     /* Old vertices have identical supports */
2248     for (v = vStart; v < vEnd; ++v) {
2249       const PetscInt  newp = vStartNew + (v - vStart);
2250       const PetscInt *support, *cone;
2251       PetscInt        size, s;
2252 
2253       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2254       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2255       for (s = 0; s < size; ++s) {
2256         if (support[s] >= fMax) {
2257           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (support[s] - fMax);
2258         } else {
2259           PetscInt r = 0;
2260 
2261           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2262           if (cone[1] == v) r = 1;
2263           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
2264         }
2265       }
2266       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2267 #if 1
2268       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2269       for (p = 0; p < size; ++p) {
2270         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);
2271       }
2272 #endif
2273     }
2274     /* Face vertices have 2 + cells supports */
2275     for (f = fStart; f < fMax; ++f) {
2276       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
2277       const PetscInt *cone, *support;
2278       PetscInt        size, s;
2279 
2280       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
2281       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2282       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
2283       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
2284       for (s = 0; s < size; ++s) {
2285         PetscInt r = 0;
2286 
2287         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2288         if (support[s] >= cMax) {
2289           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (fEnd - fMax) + (support[s] - cMax);
2290         } else {
2291           if      (cone[1] == f) r = 1;
2292           else if (cone[2] == f) r = 2;
2293           else if (cone[3] == f) r = 3;
2294           supportRef[2+s] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*4 + r;
2295         }
2296       }
2297       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2298 #if 1
2299       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2300       for (p = 0; p < 2+size; ++p) {
2301         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);
2302       }
2303 #endif
2304     }
2305     /* Cell vertices have 4 supports */
2306     for (c = cStart; c < cMax; ++c) {
2307       const PetscInt newp = vStartNew + (vEnd - vStart) + (fMax - fStart) + (c - cStart);
2308       PetscInt       supportNew[4];
2309 
2310       for (r = 0; r < 4; ++r) {
2311         supportNew[r] = fStartNew + (fMax - fStart)*2 + (c - cStart)*4 + r;
2312       }
2313       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2314     }
2315     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2316     break;
2317   case REFINER_SIMPLEX_3D:
2318     /* All cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
2319     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
2320     for (c = cStart; c < cEnd; ++c) {
2321       const PetscInt  newp = cStartNew + (c - cStart)*8;
2322       const PetscInt *cone, *ornt;
2323       PetscInt        coneNew[4], orntNew[4];
2324 
2325       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2326       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2327       /* A tetrahedron: {0, a, c, d} */
2328       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
2329       orntNew[0] = ornt[0];
2330       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
2331       orntNew[1] = ornt[1];
2332       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
2333       orntNew[2] = ornt[2];
2334       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
2335       orntNew[3] = 0;
2336       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2337       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2338 #if 1
2339       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);
2340       for (p = 0; p < 4; ++p) {
2341         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);
2342       }
2343 #endif
2344       /* B tetrahedron: {a, 1, b, e} */
2345       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
2346       orntNew[0] = ornt[0];
2347       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
2348       orntNew[1] = ornt[1];
2349       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
2350       orntNew[2] = 0;
2351       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
2352       orntNew[3] = ornt[3];
2353       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2354       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2355 #if 1
2356       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);
2357       for (p = 0; p < 4; ++p) {
2358         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);
2359       }
2360 #endif
2361       /* C tetrahedron: {c, b, 2, f} */
2362       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
2363       orntNew[0] = ornt[0];
2364       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
2365       orntNew[1] = 0;
2366       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
2367       orntNew[2] = ornt[2];
2368       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
2369       orntNew[3] = ornt[3];
2370       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2371       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2372 #if 1
2373       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);
2374       for (p = 0; p < 4; ++p) {
2375         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);
2376       }
2377 #endif
2378       /* D tetrahedron: {d, e, f, 3} */
2379       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
2380       orntNew[0] = 0;
2381       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
2382       orntNew[1] = ornt[1];
2383       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
2384       orntNew[2] = ornt[2];
2385       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
2386       orntNew[3] = ornt[3];
2387       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2388       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2389 #if 1
2390       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);
2391       for (p = 0; p < 4; ++p) {
2392         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);
2393       }
2394 #endif
2395       /* A' tetrahedron: {c, d, a, f} */
2396       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 0;
2397       orntNew[0] = -3;
2398       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
2399       orntNew[1] = ornt[2] < 0 ? -(GetTetSomething_Static(ornt[2], 0)+1) : GetTetSomething_Static(ornt[2], 0);
2400       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
2401       orntNew[2] = 0;
2402       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
2403       orntNew[3] = 2;
2404       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
2405       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
2406 #if 1
2407       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);
2408       for (p = 0; p < 4; ++p) {
2409         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);
2410       }
2411 #endif
2412 #if 0
2413       /* B' tetrahedron: {a, e, b, f} */
2414       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
2415       orntNew[0] = -3;
2416       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
2417       orntNew[1] = 1;
2418       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
2419       orntNew[2] = 0;
2420       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + 3;
2421       orntNew[3] = ornt[3] < 0 ? -(GetTetSomething_Static(ornt[3], 0)+1) : GetTetSomething_Static(ornt[3], 0);
2422 #else
2423       /* B' tetrahedron: {e, b, a, f} */
2424       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 1;
2425       orntNew[0] = -2;
2426       coneNew[1] = fStartNew + (cone[3] - fStart)*4 + 3;
2427       orntNew[1] = ornt[3] < 0 ? -(GetTetSomething_Static(ornt[3], 1)+1) : GetTetSomething_Static(ornt[3], 1);
2428       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
2429       orntNew[2] = 0;
2430       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
2431       orntNew[3] = 0;
2432 #endif
2433       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
2434       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
2435 #if 1
2436       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);
2437       for (p = 0; p < 4; ++p) {
2438         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);
2439       }
2440 #endif
2441 #if 0
2442       /* C' tetrahedron: {c, b, f, a} */
2443       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
2444       orntNew[0] = -3;
2445       coneNew[1] = fStartNew + (cone[0] - fStart)*4 + 3;
2446       orntNew[1] = ornt[0] < 0 ? -(GetTetSomething_Static(ornt[0], 2)+1) : GetTetSomething_Static(ornt[0], 2);
2447       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
2448       orntNew[2] = -3;
2449       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
2450       orntNew[3] = -2;
2451 #else
2452       /* C' tetrahedron: {f, a, c, b} */
2453       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 5;
2454       orntNew[0] = -2;
2455       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 7;
2456       orntNew[1] = -2;
2457       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 2;
2458       orntNew[2] = -1;
2459       coneNew[3] = fStartNew + (cone[0] - fStart)*4 + 3;
2460       orntNew[3] = ornt[0] < 0 ? -(GetTetSomething_Static(ornt[0], 2)+1) : GetTetSomething_Static(ornt[0], 2);
2461 #endif
2462       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
2463       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
2464 #if 1
2465       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);
2466       for (p = 0; p < 4; ++p) {
2467         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);
2468       }
2469 #endif
2470 #if 0
2471       /* D' tetrahedron: {d, f, e, a} */
2472       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
2473       orntNew[0] = -3;
2474       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
2475       orntNew[1] = -3;
2476       coneNew[2] = fStartNew + (cone[1] - fStart)*4 + 3;
2477       orntNew[2] = ornt[1] < 0 ? -(GetTetSomething_Static(ornt[1], 0)+1) : GetTetSomething_Static(ornt[1], 0);
2478       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
2479       orntNew[3] = -3;
2480 #else
2481       /* D' tetrahedron: {f, a, e, d} */
2482       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 6;
2483       orntNew[0] = -2;
2484       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 4;
2485       orntNew[1] = -1;
2486       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*8 + 3;
2487       orntNew[2] = -2;
2488       coneNew[3] = fStartNew + (cone[1] - fStart)*4 + 3;
2489       orntNew[3] = ornt[1] < 0 ? -(GetTetSomething_Static(ornt[1], 1)+1) : GetTetSomething_Static(ornt[1], 1);
2490 #endif
2491       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
2492       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
2493 #if 1
2494       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);
2495       for (p = 0; p < 4; ++p) {
2496         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);
2497       }
2498 #endif
2499     }
2500     /* Split faces have 3 edges and the same cells as the parent */
2501     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
2502     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
2503     for (f = fStart; f < fEnd; ++f) {
2504       const PetscInt  newp = fStartNew + (f - fStart)*4;
2505       const PetscInt *cone, *ornt, *support;
2506       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
2507 
2508       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2509       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
2510       /* A triangle */
2511       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
2512       orntNew[0] = ornt[0];
2513       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
2514       orntNew[1] = -2;
2515       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
2516       orntNew[2] = ornt[2];
2517       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
2518       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
2519 #if 1
2520       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);
2521       for (p = 0; p < 3; ++p) {
2522         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);
2523       }
2524 #endif
2525       /* B triangle */
2526       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
2527       orntNew[0] = ornt[0];
2528       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
2529       orntNew[1] = ornt[1];
2530       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
2531       orntNew[2] = -2;
2532       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
2533       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
2534 #if 1
2535       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);
2536       for (p = 0; p < 3; ++p) {
2537         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);
2538       }
2539 #endif
2540       /* C triangle */
2541       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
2542       orntNew[0] = -2;
2543       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
2544       orntNew[1] = ornt[1];
2545       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
2546       orntNew[2] = ornt[2];
2547       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
2548       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
2549 #if 1
2550       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);
2551       for (p = 0; p < 3; ++p) {
2552         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);
2553       }
2554 #endif
2555       /* D triangle */
2556       coneNew[0] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 0;
2557       orntNew[0] = 0;
2558       coneNew[1] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 1;
2559       orntNew[1] = 0;
2560       coneNew[2] = eStartNew + (eEnd    - eStart)*2 + (f - fStart)*3 + 2;
2561       orntNew[2] = 0;
2562       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
2563       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
2564 #if 1
2565       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);
2566       for (p = 0; p < 3; ++p) {
2567         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);
2568       }
2569 #endif
2570       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2571       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2572       for (r = 0; r < 4; ++r) {
2573         for (s = 0; s < supportSize; ++s) {
2574           PetscInt subf;
2575           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2576           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2577           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2578           for (c = 0; c < coneSize; ++c) {
2579             if (cone[c] == f) break;
2580           }
2581           subf = GetTriSubfaceInverse_Static(ornt[c], r);
2582           supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
2583         }
2584         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
2585 #if 1
2586         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);
2587         for (p = 0; p < supportSize; ++p) {
2588           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);
2589         }
2590 #endif
2591       }
2592     }
2593     /* Interior faces have 3 edges and 2 cells */
2594     for (c = cStart; c < cEnd; ++c) {
2595       PetscInt        newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8;
2596       const PetscInt *cone, *ornt;
2597       PetscInt        coneNew[3], orntNew[3];
2598       PetscInt        supportNew[2];
2599 
2600       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2601       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2602       /* Face A: {c, a, d} */
2603       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
2604       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2605       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
2606       orntNew[1] = ornt[1] < 0 ? -2 : 0;
2607       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 2);
2608       orntNew[2] = ornt[2] < 0 ? -2 : 0;
2609       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2610       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2611 #if 1
2612       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2613       for (p = 0; p < 3; ++p) {
2614         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);
2615       }
2616 #endif
2617       supportNew[0] = (c - cStart)*8 + 0;
2618       supportNew[1] = (c - cStart)*8 + 0+4;
2619       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2620 #if 1
2621       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2622       for (p = 0; p < 2; ++p) {
2623         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);
2624       }
2625 #endif
2626       ++newp;
2627       /* Face B: {a, b, e} */
2628       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
2629       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2630       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 0);
2631       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2632       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
2633       orntNew[2] = ornt[1] < 0 ? -2 : 0;
2634       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2635       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2636 #if 1
2637       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2638       for (p = 0; p < 3; ++p) {
2639         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);
2640       }
2641 #endif
2642       supportNew[0] = (c - cStart)*8 + 1;
2643       supportNew[1] = (c - cStart)*8 + 1+4;
2644       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2645 #if 1
2646       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2647       for (p = 0; p < 2; ++p) {
2648         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);
2649       }
2650 #endif
2651       ++newp;
2652       /* Face C: {c, f, b} */
2653       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
2654       orntNew[0] = ornt[2] < 0 ? -2 : 0;
2655       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
2656       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2657       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 1);
2658       orntNew[2] = ornt[0] < 0 ? -2 : 0;
2659       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2660       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2661 #if 1
2662       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2663       for (p = 0; p < 3; ++p) {
2664         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);
2665       }
2666 #endif
2667       supportNew[0] = (c - cStart)*8 + 2;
2668       supportNew[1] = (c - cStart)*8 + 2+4;
2669       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2670 #if 1
2671       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2672       for (p = 0; p < 2; ++p) {
2673         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);
2674       }
2675 #endif
2676       ++newp;
2677       /* Face D: {d, e, f} */
2678       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 0);
2679       orntNew[0] = ornt[1] < 0 ? -2 : 0;
2680       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
2681       orntNew[1] = ornt[3] < 0 ? -2 : 0;
2682       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
2683       orntNew[2] = ornt[2] < 0 ? -2 : 0;
2684       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2685       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2686 #if 1
2687       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2688       for (p = 0; p < 3; ++p) {
2689         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);
2690       }
2691 #endif
2692       supportNew[0] = (c - cStart)*8 + 3;
2693       supportNew[1] = (c - cStart)*8 + 3+4;
2694       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2695 #if 1
2696       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2697       for (p = 0; p < 2; ++p) {
2698         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);
2699       }
2700 #endif
2701       ++newp;
2702       /* Face E: {d, f, a} */
2703       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
2704       orntNew[0] = ornt[2] < 0 ? 0 : -2;
2705       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2706       orntNew[1] = -2;
2707       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
2708       orntNew[2] = ornt[1] < 0 ? -2 : 0;
2709       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2710       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2711 #if 1
2712       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2713       for (p = 0; p < 3; ++p) {
2714         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);
2715       }
2716 #endif
2717       supportNew[0] = (c - cStart)*8 + 0+4;
2718       supportNew[1] = (c - cStart)*8 + 3+4;
2719       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2720 #if 1
2721       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2722       for (p = 0; p < 2; ++p) {
2723         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);
2724       }
2725 #endif
2726       ++newp;
2727       /* Face F: {c, a, f} */
2728       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
2729       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2730       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2731       orntNew[1] = 0;
2732       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
2733       orntNew[2] = ornt[2] < 0 ? 0 : -2;
2734       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2735       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2736 #if 1
2737       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2738       for (p = 0; p < 3; ++p) {
2739         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);
2740       }
2741 #endif
2742       supportNew[0] = (c - cStart)*8 + 0+4;
2743       supportNew[1] = (c - cStart)*8 + 2+4;
2744       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2745 #if 1
2746       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2747       for (p = 0; p < 2; ++p) {
2748         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);
2749       }
2750 #endif
2751       ++newp;
2752       /* Face G: {e, a, f} */
2753       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
2754       orntNew[0] = ornt[1] < 0 ? -2 : 0;
2755       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2756       orntNew[1] = 0;
2757       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
2758       orntNew[2] = ornt[3] < 0 ? 0 : -2;
2759       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2760       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2761 #if 1
2762       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2763       for (p = 0; p < 3; ++p) {
2764         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);
2765       }
2766 #endif
2767       supportNew[0] = (c - cStart)*8 + 1+4;
2768       supportNew[1] = (c - cStart)*8 + 3+4;
2769       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2770 #if 1
2771       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2772       for (p = 0; p < 2; ++p) {
2773         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);
2774       }
2775 #endif
2776       ++newp;
2777       /* Face H: {a, b, f} */
2778       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
2779       orntNew[0] = ornt[0] < 0 ? -2 : 0;
2780       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
2781       orntNew[1] = ornt[3] < 0 ? 0 : -2;
2782       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2783       orntNew[2] = -2;
2784       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2785       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
2786 #if 1
2787       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2788       for (p = 0; p < 3; ++p) {
2789         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);
2790       }
2791 #endif
2792       supportNew[0] = (c - cStart)*8 + 1+4;
2793       supportNew[1] = (c - cStart)*8 + 2+4;
2794       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2795 #if 1
2796       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
2797       for (p = 0; p < 2; ++p) {
2798         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);
2799       }
2800 #endif
2801       ++newp;
2802     }
2803     /* Split Edges have 2 vertices and the same faces as the parent */
2804     for (e = eStart; e < eEnd; ++e) {
2805       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
2806 
2807       for (r = 0; r < 2; ++r) {
2808         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
2809         const PetscInt *cone, *ornt, *support;
2810         PetscInt        coneNew[2], coneSize, c, supportSize, s;
2811 
2812         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
2813         coneNew[0]       = vStartNew + (cone[0] - vStart);
2814         coneNew[1]       = vStartNew + (cone[1] - vStart);
2815         coneNew[(r+1)%2] = newv;
2816         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2817 #if 1
2818         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2819         for (p = 0; p < 2; ++p) {
2820           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);
2821         }
2822 #endif
2823         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
2824         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
2825         for (s = 0; s < supportSize; ++s) {
2826           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2827           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2828           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2829           for (c = 0; c < coneSize; ++c) {
2830             if (cone[c] == e) break;
2831           }
2832           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
2833         }
2834         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2835 #if 1
2836         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2837         for (p = 0; p < supportSize; ++p) {
2838           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);
2839         }
2840 #endif
2841       }
2842     }
2843     /* Face edges have 2 vertices and 2+cells*(1/2) faces */
2844     for (f = fStart; f < fEnd; ++f) {
2845       const PetscInt *cone, *ornt, *support;
2846       PetscInt        coneSize, supportSize, s;
2847 
2848       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
2849       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
2850       for (r = 0; r < 3; ++r) {
2851         const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*3 + r;
2852         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
2853         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
2854                                     -1, -1,  1,  6,  0,  4,
2855                                      2,  5,  3,  4, -1, -1,
2856                                     -1, -1,  3,  6,  2,  7};
2857 
2858         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
2859         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
2860         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
2861         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2862 #if 1
2863         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2864         for (p = 0; p < 2; ++p) {
2865           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);
2866         }
2867 #endif
2868         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
2869         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
2870         for (s = 0; s < supportSize; ++s) {
2871           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2872           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2873           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
2874           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
2875           /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
2876           er = GetTetSomethingInverse_Static(ornt[c], r);
2877           if (er == eint[c]) {
2878             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
2879           } else {
2880             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
2881             supportRef[2+intFaces++] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
2882           }
2883         }
2884         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2885 #if 1
2886         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2887         for (p = 0; p < intFaces; ++p) {
2888           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);
2889         }
2890 #endif
2891       }
2892     }
2893     /* Interior edges have 2 vertices and 4 faces */
2894     for (c = cStart; c < cEnd; ++c) {
2895       const PetscInt  newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (c - cStart);
2896       const PetscInt *cone, *ornt, *fcone;
2897       PetscInt        coneNew[2], supportNew[4], find;
2898 
2899       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2900       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
2901       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
2902       find = GetTriEdge_Static(ornt[0], 0);
2903       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
2904       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
2905       find = GetTriEdge_Static(ornt[2], 1);
2906       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
2907       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
2908 #if 1
2909       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2910       for (p = 0; p < 2; ++p) {
2911         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);
2912       }
2913 #endif
2914       supportNew[0] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 4;
2915       supportNew[1] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 5;
2916       supportNew[2] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 6;
2917       supportNew[3] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*8 + 7;
2918       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
2919 #if 1
2920       if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
2921       for (p = 0; p < 4; ++p) {
2922         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);
2923       }
2924 #endif
2925     }
2926     /* Old vertices have identical supports */
2927     for (v = vStart; v < vEnd; ++v) {
2928       const PetscInt  newp = vStartNew + (v - vStart);
2929       const PetscInt *support, *cone;
2930       PetscInt        size, s;
2931 
2932       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
2933       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
2934       for (s = 0; s < size; ++s) {
2935         PetscInt r = 0;
2936 
2937         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2938         if (cone[1] == v) r = 1;
2939         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
2940       }
2941       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2942 #if 1
2943       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2944       for (p = 0; p < size; ++p) {
2945         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);
2946       }
2947 #endif
2948     }
2949     /* Edge vertices have 2 + face*2 + 0/1 supports */
2950     for (e = eStart; e < eEnd; ++e) {
2951       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
2952       const PetscInt *cone, *support;
2953       PetscInt       *star = NULL, starSize, cellSize = 0, coneSize, size, s;
2954 
2955       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
2956       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
2957       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
2958       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
2959       for (s = 0; s < size; ++s) {
2960         PetscInt r = 0;
2961 
2962         ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2963         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2964         for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
2965         supportRef[2+s*2+0] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
2966         supportRef[2+s*2+1] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
2967       }
2968       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
2969       for (s = 0; s < starSize*2; s += 2) {
2970         const PetscInt *cone, *ornt;
2971         PetscInt        e01, e23;
2972 
2973         if ((star[s] >= cStart) && (star[s] < cEnd)) {
2974           /* Check edge 0-1 */
2975           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
2976           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
2977           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
2978           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
2979           /* Check edge 2-3 */
2980           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
2981           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
2982           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
2983           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
2984           if ((e01 == e) || (e23 == e)) {supportRef[2+size*2+cellSize++] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (star[s] - cStart);}
2985         }
2986       }
2987       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
2988       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
2989 #if 1
2990       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
2991       for (p = 0; p < 2+size*2+cellSize; ++p) {
2992         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);
2993       }
2994 #endif
2995     }
2996     ierr = PetscFree(supportRef);CHKERRQ(ierr);
2997     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
2998     break;
2999   case REFINER_HYBRID_SIMPLEX_3D:
3000     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
3001     /* Interior cells have 4 faces: Tet face order is prescribed in DMPlexGetFaces_Internal() */
3002     ierr = DMPlexGetRawFaces_Internal(dm, 3, 4, cellInd, NULL, NULL, &faces);CHKERRQ(ierr);
3003     for (c = cStart; c < cMax; ++c) {
3004       const PetscInt  newp = cStartNew + (c - cStart)*8;
3005       const PetscInt *cone, *ornt;
3006       PetscInt        coneNew[4], orntNew[4];
3007 
3008       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3009       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3010       /* A tetrahedron: {0, a, c, d} */
3011       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 0); /* A */
3012       orntNew[0] = ornt[0];
3013       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 0); /* A */
3014       orntNew[1] = ornt[1];
3015       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 0); /* A */
3016       orntNew[2] = ornt[2];
3017       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
3018       orntNew[3] = 0;
3019       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3020       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3021 #if 1
3022       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);
3023       for (p = 0; p < 4; ++p) {
3024         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);
3025       }
3026 #endif
3027       /* B tetrahedron: {a, 1, b, e} */
3028       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 1); /* B */
3029       orntNew[0] = ornt[0];
3030       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 2); /* C */
3031       orntNew[1] = ornt[1];
3032       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
3033       orntNew[2] = 0;
3034       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 1); /* B */
3035       orntNew[3] = ornt[3];
3036       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3037       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3038 #if 1
3039       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);
3040       for (p = 0; p < 4; ++p) {
3041         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);
3042       }
3043 #endif
3044       /* C tetrahedron: {c, b, 2, f} */
3045       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], 2); /* C */
3046       orntNew[0] = ornt[0];
3047       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
3048       orntNew[1] = 0;
3049       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 1); /* B */
3050       orntNew[2] = ornt[2];
3051       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 0); /* A */
3052       orntNew[3] = ornt[3];
3053       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3054       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3055 #if 1
3056       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);
3057       for (p = 0; p < 4; ++p) {
3058         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);
3059       }
3060 #endif
3061       /* D tetrahedron: {d, e, f, 3} */
3062       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
3063       orntNew[0] = 0;
3064       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], 1); /* B */
3065       orntNew[1] = ornt[1];
3066       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetTriSubface_Static(ornt[2], 2); /* C */
3067       orntNew[2] = ornt[2];
3068       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetTriSubface_Static(ornt[3], 2); /* C */
3069       orntNew[3] = ornt[3];
3070       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3071       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3072 #if 1
3073       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);
3074       for (p = 0; p < 4; ++p) {
3075         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);
3076       }
3077 #endif
3078       /* A' tetrahedron: {d, a, c, f} */
3079       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 0;
3080       orntNew[0] = -3;
3081       coneNew[1] = fStartNew + (cone[2] - fStart)*4 + 3;
3082       orntNew[1] = ornt[2] < 0 ? -(GetTetSomething_Static(ornt[2], 0)+1) : GetTetSomething_Static(ornt[2], 0);
3083       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
3084       orntNew[2] = 0;
3085       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
3086       orntNew[3] = 2;
3087       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
3088       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
3089 #if 1
3090       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);
3091       for (p = 0; p < 4; ++p) {
3092         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);
3093       }
3094 #endif
3095       /* B' tetrahedron: {e, b, a, f} */
3096       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 1;
3097       orntNew[0] = -3;
3098       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
3099       orntNew[1] = 1;
3100       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
3101       orntNew[2] = 0;
3102       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + 3;
3103       orntNew[3] = ornt[3] < 0 ? -(GetTetSomething_Static(ornt[3], 0)+1) : GetTetSomething_Static(ornt[3], 0);
3104       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
3105       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
3106 #if 1
3107       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);
3108       for (p = 0; p < 4; ++p) {
3109         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);
3110       }
3111 #endif
3112       /* C' tetrahedron: {b, f, c, a} */
3113       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 2;
3114       orntNew[0] = -3;
3115       coneNew[1] = fStartNew + (cone[0] - fStart)*4 + 3;
3116       orntNew[1] = ornt[0] < 0 ? -(GetTetSomething_Static(ornt[0], 2)+1) : GetTetSomething_Static(ornt[0], 2);
3117       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 5;
3118       orntNew[2] = -3;
3119       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 7;
3120       orntNew[3] = -2;
3121       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
3122       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
3123 #if 1
3124       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);
3125       for (p = 0; p < 4; ++p) {
3126         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fMaxNew);
3127       }
3128 #endif
3129       /* D' tetrahedron: {f, e, d, a} */
3130       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 3;
3131       orntNew[0] = -3;
3132       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 4;
3133       orntNew[1] = -3;
3134       coneNew[2] = fStartNew + (cone[1] - fStart)*4 + 3;
3135       orntNew[2] = ornt[1] < 0 ? -(GetTetSomething_Static(ornt[1], 0)+1) : GetTetSomething_Static(ornt[1], 0);
3136       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*8 + 6;
3137       orntNew[3] = -3;
3138       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
3139       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
3140 #if 1
3141       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);
3142       for (p = 0; p < 4; ++p) {
3143         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);
3144       }
3145 #endif
3146     }
3147     /* Hybrid cells have 5 faces */
3148     for (c = cMax; c < cEnd; ++c) {
3149       const PetscInt  newp = cStartNew + (cMax - cStart)*8 + (c - cMax)*4;
3150       const PetscInt *cone, *ornt, *fornt;
3151       PetscInt        coneNew[5], orntNew[5], o, of, i;
3152 
3153       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3154       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3155       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
3156       o = ornt[0] < 0 ? -1 : 1;
3157       for (r = 0; r < 3; ++r) {
3158         coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetTriSubface_Static(ornt[0], r);
3159         orntNew[0] = ornt[0];
3160         coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetTriSubface_Static(ornt[1], r);
3161         orntNew[1] = ornt[1];
3162         of = fornt[GetTriEdge_Static(ornt[0], r)]       < 0 ? -1 : 1;
3163         i  = GetTriEdgeInverse_Static(ornt[0], r)       + 2;
3164         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (cone[2+GetTriEdge_Static(ornt[0], r)]       - fMax)*2 + (o*of < 0 ? 1 : 0);
3165         orntNew[i] = 0;
3166         i  = GetTriEdgeInverse_Static(ornt[0], (r+1)%3) + 2;
3167         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + GetTriSubface_Static(ornt[0], r);
3168         orntNew[i] = 0;
3169         of = fornt[GetTriEdge_Static(ornt[0], (r+2)%3)] < 0 ? -1 : 1;
3170         i  = GetTriEdgeInverse_Static(ornt[0], (r+2)%3) + 2;
3171         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);
3172         orntNew[i] = 0;
3173         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
3174         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
3175 #if 1
3176         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);
3177         for (p = 0; p < 2; ++p) {
3178           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);
3179         }
3180         for (p = 2; p < 5; ++p) {
3181           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);
3182         }
3183 #endif
3184       }
3185       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + 3;
3186       orntNew[0] = 0;
3187       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + 3;
3188       orntNew[1] = 0;
3189       coneNew[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 1;
3190       orntNew[2] = 0;
3191       coneNew[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 2;
3192       orntNew[3] = 0;
3193       coneNew[4] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3 + 0;
3194       orntNew[4] = 0;
3195       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3196       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3197 #if 1
3198       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);
3199       for (p = 0; p < 2; ++p) {
3200         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);
3201       }
3202       for (p = 2; p < 5; ++p) {
3203         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);
3204       }
3205 #endif
3206     }
3207     /* Split faces have 3 edges and the same cells as the parent */
3208     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
3209     ierr = PetscMalloc1(2 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
3210     for (f = fStart; f < fMax; ++f) {
3211       const PetscInt  newp = fStartNew + (f - fStart)*4;
3212       const PetscInt *cone, *ornt, *support;
3213       PetscInt        coneNew[3], orntNew[3], coneSize, supportSize, s;
3214 
3215       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3216       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3217       /* A triangle */
3218       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1 : 0);
3219       orntNew[0] = ornt[0];
3220       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
3221       orntNew[1] = -2;
3222       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 0 : 1);
3223       orntNew[2] = ornt[2];
3224       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3225       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3226 #if 1
3227       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);
3228       for (p = 0; p < 3; ++p) {
3229         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);
3230       }
3231 #endif
3232       /* B triangle */
3233       coneNew[0] = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 0 : 1);
3234       orntNew[0] = ornt[0];
3235       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1 : 0);
3236       orntNew[1] = ornt[1];
3237       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
3238       orntNew[2] = -2;
3239       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3240       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3241 #if 1
3242       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);
3243       for (p = 0; p < 3; ++p) {
3244         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);
3245       }
3246 #endif
3247       /* C triangle */
3248       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
3249       orntNew[0] = -2;
3250       coneNew[1] = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 0 : 1);
3251       orntNew[1] = ornt[1];
3252       coneNew[2] = eStartNew + (cone[2] - eStart)*2 + (ornt[2] < 0 ? 1 : 0);
3253       orntNew[2] = ornt[2];
3254       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3255       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3256 #if 1
3257       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);
3258       for (p = 0; p < 3; ++p) {
3259         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);
3260       }
3261 #endif
3262       /* D triangle */
3263       coneNew[0] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 0;
3264       orntNew[0] = 0;
3265       coneNew[1] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 1;
3266       orntNew[1] = 0;
3267       coneNew[2] = eStartNew + (eMax    - eStart)*2 + (f - fStart)*3 + 2;
3268       orntNew[2] = 0;
3269       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3270       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3271 #if 1
3272       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);
3273       for (p = 0; p < 3; ++p) {
3274         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);
3275       }
3276 #endif
3277       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3278       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3279       for (r = 0; r < 4; ++r) {
3280         for (s = 0; s < supportSize; ++s) {
3281           PetscInt subf;
3282           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3283           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3284           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3285           for (c = 0; c < coneSize; ++c) {
3286             if (cone[c] == f) break;
3287           }
3288           subf = GetTriSubfaceInverse_Static(ornt[c], r);
3289           if (support[s] < cMax) {
3290             supportRef[s] = cStartNew + (support[s] - cStart)*8 + (r==3 ? (c+2)%4 + 4 : faces[c*3+subf]);
3291           } else {
3292             supportRef[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (r==3 ? r : subf);
3293           }
3294         }
3295         ierr = DMPlexSetSupport(rdm, newp+r, supportRef);CHKERRQ(ierr);
3296 #if 1
3297         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);
3298         for (p = 0; p < supportSize; ++p) {
3299           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);
3300         }
3301 #endif
3302       }
3303     }
3304     /* Interior cell faces have 3 edges and 2 cells */
3305     for (c = cStart; c < cMax; ++c) {
3306       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*8;
3307       const PetscInt *cone, *ornt;
3308       PetscInt        coneNew[3], orntNew[3];
3309       PetscInt        supportNew[2];
3310 
3311       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3312       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3313       /* Face A: {c, a, d} */
3314       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
3315       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3316       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
3317       orntNew[1] = ornt[1] < 0 ? -2 : 0;
3318       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 2);
3319       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3320       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3321       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3322 #if 1
3323       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3324       for (p = 0; p < 3; ++p) {
3325         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);
3326       }
3327 #endif
3328       supportNew[0] = (c - cStart)*8 + 0;
3329       supportNew[1] = (c - cStart)*8 + 0+4;
3330       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3331 #if 1
3332       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3333       for (p = 0; p < 2; ++p) {
3334         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);
3335       }
3336 #endif
3337       ++newp;
3338       /* Face B: {a, b, e} */
3339       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
3340       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3341       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 0);
3342       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3343       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
3344       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3345       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3346       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3347 #if 1
3348       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);
3349       for (p = 0; p < 3; ++p) {
3350         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);
3351       }
3352 #endif
3353       supportNew[0] = (c - cStart)*8 + 1;
3354       supportNew[1] = (c - cStart)*8 + 1+4;
3355       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3356 #if 1
3357       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3358       for (p = 0; p < 2; ++p) {
3359         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);
3360       }
3361 #endif
3362       ++newp;
3363       /* Face C: {c, f, b} */
3364       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
3365       orntNew[0] = ornt[2] < 0 ? -2 : 0;
3366       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
3367       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3368       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 1);
3369       orntNew[2] = ornt[0] < 0 ? -2 : 0;
3370       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3371       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3372 #if 1
3373       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3374       for (p = 0; p < 3; ++p) {
3375         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);
3376       }
3377 #endif
3378       supportNew[0] = (c - cStart)*8 + 2;
3379       supportNew[1] = (c - cStart)*8 + 2+4;
3380       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3381 #if 1
3382       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3383       for (p = 0; p < 2; ++p) {
3384         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);
3385       }
3386 #endif
3387       ++newp;
3388       /* Face D: {d, e, f} */
3389       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 0);
3390       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3391       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
3392       orntNew[1] = ornt[3] < 0 ? -2 : 0;
3393       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
3394       orntNew[2] = ornt[2] < 0 ? -2 : 0;
3395       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3396       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3397 #if 1
3398       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3399       for (p = 0; p < 3; ++p) {
3400         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);
3401       }
3402 #endif
3403       supportNew[0] = (c - cStart)*8 + 3;
3404       supportNew[1] = (c - cStart)*8 + 3+4;
3405       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3406 #if 1
3407       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3408       for (p = 0; p < 2; ++p) {
3409         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);
3410       }
3411 #endif
3412       ++newp;
3413       /* Face E: {d, f, a} */
3414       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 1);
3415       orntNew[0] = ornt[2] < 0 ? 0 : -2;
3416       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3417       orntNew[1] = -2;
3418       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 2);
3419       orntNew[2] = ornt[1] < 0 ? -2 : 0;
3420       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3421       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3422 #if 1
3423       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3424       for (p = 0; p < 3; ++p) {
3425         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);
3426       }
3427 #endif
3428       supportNew[0] = (c - cStart)*8 + 0+4;
3429       supportNew[1] = (c - cStart)*8 + 3+4;
3430       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3431 #if 1
3432       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3433       for (p = 0; p < 2; ++p) {
3434         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);
3435       }
3436 #endif
3437       ++newp;
3438       /* Face F: {c, a, f} */
3439       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 2);
3440       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3441       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3442       orntNew[1] = 0;
3443       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*3 + GetTetSomething_Static(ornt[2], 0);
3444       orntNew[2] = ornt[2] < 0 ? 0 : -2;
3445       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3446       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3447 #if 1
3448       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3449       for (p = 0; p < 3; ++p) {
3450         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);
3451       }
3452 #endif
3453       supportNew[0] = (c - cStart)*8 + 0+4;
3454       supportNew[1] = (c - cStart)*8 + 2+4;
3455       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3456 #if 1
3457       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3458       for (p = 0; p < 2; ++p) {
3459         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);
3460       }
3461 #endif
3462       ++newp;
3463       /* Face G: {e, a, f} */
3464       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + GetTetSomething_Static(ornt[1], 1);
3465       orntNew[0] = ornt[1] < 0 ? -2 : 0;
3466       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3467       orntNew[1] = 0;
3468       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 1);
3469       orntNew[2] = ornt[3] < 0 ? 0 : -2;
3470       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3471       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3472 #if 1
3473       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3474       for (p = 0; p < 3; ++p) {
3475         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);
3476       }
3477 #endif
3478       supportNew[0] = (c - cStart)*8 + 1+4;
3479       supportNew[1] = (c - cStart)*8 + 3+4;
3480       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3481 #if 1
3482       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3483       for (p = 0; p < 2; ++p) {
3484         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);
3485       }
3486 #endif
3487       ++newp;
3488       /* Face H: {a, b, f} */
3489       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + GetTetSomething_Static(ornt[0], 0);
3490       orntNew[0] = ornt[0] < 0 ? -2 : 0;
3491       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*3 + GetTetSomething_Static(ornt[3], 2);
3492       orntNew[1] = ornt[3] < 0 ? 0 : -2;
3493       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3494       orntNew[2] = -2;
3495       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3496       ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3497 #if 1
3498       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3499       for (p = 0; p < 3; ++p) {
3500         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);
3501       }
3502 #endif
3503       supportNew[0] = (c - cStart)*8 + 1+4;
3504       supportNew[1] = (c - cStart)*8 + 2+4;
3505       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3506 #if 1
3507       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
3508       for (p = 0; p < 2; ++p) {
3509         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);
3510       }
3511 #endif
3512       ++newp;
3513     }
3514     /* Hybrid split faces have 4 edges and same cells */
3515     for (f = fMax; f < fEnd; ++f) {
3516       const PetscInt *cone, *ornt, *support;
3517       PetscInt        coneNew[4], orntNew[4];
3518       PetscInt        supportNew[2], size, s, c;
3519 
3520       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3521       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
3522       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3523       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3524       for (r = 0; r < 2; ++r) {
3525         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + r;
3526 
3527         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
3528         orntNew[0]   = ornt[0];
3529         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
3530         orntNew[1]   = ornt[1];
3531         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (cone[2+r] - eMax);
3532         orntNew[2+r] = 0;
3533         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd      - eMax) + (f - fMax);
3534         orntNew[3-r] = 0;
3535         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3536         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
3537 #if 1
3538         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
3539         for (p = 0; p < 2; ++p) {
3540           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);
3541         }
3542         for (p = 2; p < 4; ++p) {
3543           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);
3544         }
3545 #endif
3546         for (s = 0; s < size; ++s) {
3547           const PetscInt *coneCell, *orntCell, *fornt;
3548           PetscInt        o, of;
3549 
3550           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
3551           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
3552           o = orntCell[0] < 0 ? -1 : 1;
3553           for (c = 2; c < 5; ++c) if (coneCell[c] == f) break;
3554           if (c >= 5) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
3555           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
3556           of = fornt[c-2] < 0 ? -1 : 1;
3557           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetTriEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%3;
3558         }
3559         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3560 #if 1
3561         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
3562         for (p = 0; p < size; ++p) {
3563           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);
3564         }
3565 #endif
3566       }
3567     }
3568     /* Hybrid cell faces have 4 edges and 2 cells */
3569     for (c = cMax; c < cEnd; ++c) {
3570       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (c - cMax)*3;
3571       const PetscInt *cone, *ornt;
3572       PetscInt        coneNew[4], orntNew[4];
3573       PetscInt        supportNew[2];
3574 
3575       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3576       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3577       for (r = 0; r < 3; ++r) {
3578         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*3 + (r+2)%3;
3579         orntNew[0] = 0;
3580         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*3 + (r+2)%3;
3581         orntNew[1] = 0;
3582         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+(r+2)%3] - fMax);
3583         orntNew[2] = 0;
3584         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (cone[2+r]       - fMax);
3585         orntNew[3] = 0;
3586         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
3587         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
3588 #if 1
3589         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);
3590         for (p = 0; p < 2; ++p) {
3591           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);
3592         }
3593         for (p = 2; p < 4; ++p) {
3594           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);
3595         }
3596 #endif
3597         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetTriSubface_Static(ornt[0], r);
3598         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + 3;
3599         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
3600 #if 1
3601         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);
3602         for (p = 0; p < 2; ++p) {
3603           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);
3604         }
3605 #endif
3606       }
3607     }
3608     /* Interior split edges have 2 vertices and the same faces as the parent */
3609     for (e = eStart; e < eMax; ++e) {
3610       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
3611 
3612       for (r = 0; r < 2; ++r) {
3613         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
3614         const PetscInt *cone, *ornt, *support;
3615         PetscInt        coneNew[2], coneSize, c, supportSize, s;
3616 
3617         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3618         coneNew[0]       = vStartNew + (cone[0] - vStart);
3619         coneNew[1]       = vStartNew + (cone[1] - vStart);
3620         coneNew[(r+1)%2] = newv;
3621         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3622 #if 1
3623         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3624         for (p = 0; p < 2; ++p) {
3625           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);
3626         }
3627 #endif
3628         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
3629         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3630         for (s = 0; s < supportSize; ++s) {
3631           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3632           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3633           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3634           for (c = 0; c < coneSize; ++c) if (cone[c] == e) break;
3635           if (support[s] < fMax) {
3636             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%3;
3637           } else {
3638             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
3639           }
3640         }
3641         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3642 #if 1
3643         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3644         for (p = 0; p < supportSize; ++p) {
3645           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);
3646         }
3647 #endif
3648       }
3649     }
3650     /* Interior face edges have 2 vertices and 2+cells*(1/2) faces */
3651     for (f = fStart; f < fMax; ++f) {
3652       const PetscInt *cone, *ornt, *support;
3653       PetscInt        coneSize, supportSize, s;
3654 
3655       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
3656       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3657       for (r = 0; r < 3; ++r) {
3658         const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*3 + r;
3659         PetscInt        coneNew[2], intFaces = 0, er, eint[4] = {1, 0, 2, 0};
3660         PetscInt        fint[24] = { 1,  7, -1, -1,  0,  5,
3661                                     -1, -1,  1,  6,  0,  4,
3662                                      2,  5,  3,  4, -1, -1,
3663                                     -1, -1,  3,  6,  2,  7};
3664 
3665         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3666         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[(r+0)%3] - eStart);
3667         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - eStart);
3668         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3669 #if 1
3670         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3671         for (p = 0; p < 2; ++p) {
3672           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);
3673         }
3674 #endif
3675         supportRef[0] = fStartNew + (f - fStart)*4 + (r+1)%3;
3676         supportRef[1] = fStartNew + (f - fStart)*4 + 3;
3677         for (s = 0; s < supportSize; ++s) {
3678           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3679           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3680           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
3681           for (c = 0; c < coneSize; ++c) {if (cone[c] == f) break;}
3682           if (support[s] < cMax) {
3683             /* Here we want to determine whether edge newp contains a vertex which is part of the cross-tet edge */
3684             er = GetTetSomethingInverse_Static(ornt[c], r);
3685             if (er == eint[c]) {
3686               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + (c + 2)%4;
3687             } else {
3688               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 0];
3689               supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*8 + fint[(c*3 + er)*2 + 1];
3690             }
3691           } else {
3692             supportRef[2+intFaces++] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (r + 1)%3;
3693           }
3694         }
3695         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3696 #if 1
3697         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3698         for (p = 0; p < intFaces; ++p) {
3699           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);
3700         }
3701 #endif
3702       }
3703     }
3704     /* Interior cell edges have 2 vertices and 4 faces */
3705     for (c = cStart; c < cMax; ++c) {
3706       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (c - cStart);
3707       const PetscInt *cone, *ornt, *fcone;
3708       PetscInt        coneNew[2], supportNew[4], find;
3709 
3710       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3711       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3712       ierr = DMPlexGetCone(dm, cone[0], &fcone);CHKERRQ(ierr);
3713       find = GetTriEdge_Static(ornt[0], 0);
3714       coneNew[0] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3715       ierr = DMPlexGetCone(dm, cone[2], &fcone);CHKERRQ(ierr);
3716       find = GetTriEdge_Static(ornt[2], 1);
3717       coneNew[1] = vStartNew + (vEnd - vStart) + (fcone[find] - eStart);
3718       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3719 #if 1
3720       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3721       for (p = 0; p < 2; ++p) {
3722         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);
3723       }
3724 #endif
3725       supportNew[0] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 4;
3726       supportNew[1] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 5;
3727       supportNew[2] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 6;
3728       supportNew[3] = fStartNew + (fMax - fStart)*4 + (c - cStart)*8 + 7;
3729       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
3730 #if 1
3731       if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
3732       for (p = 0; p < 4; ++p) {
3733         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);
3734       }
3735 #endif
3736     }
3737     /* Hybrid edges have two vertices and the same faces */
3738     for (e = eMax; e < eEnd; ++e) {
3739       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (e - eMax);
3740       const PetscInt *cone, *support, *fcone;
3741       PetscInt        coneNew[2], size, fsize, s;
3742 
3743       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
3744       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
3745       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3746       coneNew[0] = vStartNew + (cone[0] - vStart);
3747       coneNew[1] = vStartNew + (cone[1] - vStart);
3748       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3749 #if 1
3750       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3751       for (p = 0; p < 2; ++p) {
3752         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);
3753       }
3754 #endif
3755       for (s = 0; s < size; ++s) {
3756         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
3757         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
3758         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
3759         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
3760         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (support[s] - fMax)*2 + c-2;
3761       }
3762       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3763 #if 1
3764       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3765       for (p = 0; p < size; ++p) {
3766         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);
3767       }
3768 #endif
3769     }
3770     /* Hybrid face edges have 2 vertices and 2+2*cells faces */
3771     for (f = fMax; f < fEnd; ++f) {
3772       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (f - fMax);
3773       const PetscInt *cone, *support, *ccone, *cornt;
3774       PetscInt        coneNew[2], size, csize, s;
3775 
3776       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
3777       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3778       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
3779       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
3780       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
3781       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
3782 #if 1
3783       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3784       for (p = 0; p < 2; ++p) {
3785         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);
3786       }
3787 #endif
3788       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 0;
3789       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (f - fMax)*2 + 1;
3790       for (s = 0; s < size; ++s) {
3791         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
3792         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
3793         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
3794         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
3795         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]);
3796         supportRef[2+s*2+0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + c-2;
3797         supportRef[2+s*2+1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (support[s] - cMax)*3 + (c-1)%3;
3798       }
3799       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3800 #if 1
3801       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
3802       for (p = 0; p < 2+size*2; ++p) {
3803         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);
3804       }
3805 #endif
3806     }
3807     /* Interior vertices have identical supports */
3808     for (v = vStart; v < vEnd; ++v) {
3809       const PetscInt  newp = vStartNew + (v - vStart);
3810       const PetscInt *support, *cone;
3811       PetscInt        size, s;
3812 
3813       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
3814       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
3815       for (s = 0; s < size; ++s) {
3816         PetscInt r = 0;
3817 
3818         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3819         if (cone[1] == v) r = 1;
3820         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
3821         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (support[s] - eMax);
3822       }
3823       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3824 #if 1
3825       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3826       for (p = 0; p < size; ++p) {
3827         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);
3828       }
3829 #endif
3830     }
3831     /* Interior edge vertices have 2 + interior face*2 + hybrid face + cells*0/1 supports */
3832     for (e = eStart; e < eMax; ++e) {
3833       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
3834       const PetscInt *cone, *support;
3835       PetscInt       *star = NULL, starSize, faceSize = 0, cellSize = 0, coneSize, size, s;
3836 
3837       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
3838       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
3839       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
3840       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
3841       for (s = 0; s < size; ++s) {
3842         PetscInt r = 0;
3843 
3844         if (support[s] < fMax) {
3845           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
3846           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
3847           for (r = 0; r < coneSize; ++r) {if (cone[r] == e) break;}
3848           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+0)%3;
3849           supportRef[2+faceSize+1] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*3 + (r+2)%3;
3850           faceSize += 2;
3851         } else {
3852           supportRef[2+faceSize+0] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*3 + (cMax - cStart) + (eEnd - eMax) + (support[s] - fMax);
3853           ++faceSize;
3854         }
3855       }
3856       ierr = DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
3857       for (s = 0; s < starSize*2; s += 2) {
3858         const PetscInt *cone, *ornt;
3859         PetscInt        e01, e23;
3860 
3861         if ((star[s] >= cStart) && (star[s] < cMax)) {
3862           /* Check edge 0-1 */
3863           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
3864           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
3865           ierr = DMPlexGetCone(dm, cone[0], &cone);CHKERRQ(ierr);
3866           e01  = cone[GetTriEdge_Static(ornt[0], 0)];
3867           /* Check edge 2-3 */
3868           ierr = DMPlexGetCone(dm, star[s], &cone);CHKERRQ(ierr);
3869           ierr = DMPlexGetConeOrientation(dm, star[s], &ornt);CHKERRQ(ierr);
3870           ierr = DMPlexGetCone(dm, cone[2], &cone);CHKERRQ(ierr);
3871           e23  = cone[GetTriEdge_Static(ornt[2], 1)];
3872           if ((e01 == e) || (e23 == e)) {supportRef[2+faceSize+cellSize++] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (star[s] - cStart);}
3873         }
3874       }
3875       ierr = DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
3876       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
3877 #if 1
3878       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
3879       for (p = 0; p < 2+faceSize+cellSize; ++p) {
3880         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);
3881       }
3882 #endif
3883     }
3884     ierr = PetscFree(supportRef);CHKERRQ(ierr);
3885     ierr = DMPlexRestoreFaces_Internal(dm, 3, cStart, NULL, NULL, &faces);CHKERRQ(ierr);
3886     break;
3887   case REFINER_HEX_3D:
3888     /*
3889      Bottom (viewed from top)    Top
3890      1---------2---------2       7---------2---------6
3891      |         |         |       |         |         |
3892      |    B    2    C    |       |    H    2    G    |
3893      |         |         |       |         |         |
3894      3----3----0----1----1       3----3----0----1----1
3895      |         |         |       |         |         |
3896      |    A    0    D    |       |    E    0    F    |
3897      |         |         |       |         |         |
3898      0---------0---------3       4---------0---------5
3899      */
3900     /* All cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
3901     for (c = cStart; c < cEnd; ++c) {
3902       const PetscInt  newp = (c - cStart)*8;
3903       const PetscInt *cone, *ornt;
3904       PetscInt        coneNew[6], orntNew[6];
3905 
3906       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
3907       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
3908       /* A hex */
3909       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
3910       orntNew[0] = ornt[0];
3911       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
3912       orntNew[1] = 0;
3913       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
3914       orntNew[2] = ornt[2];
3915       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
3916       orntNew[3] = 0;
3917       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
3918       orntNew[4] = 0;
3919       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
3920       orntNew[5] = ornt[5];
3921       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
3922       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
3923 #if 1
3924       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);
3925       for (p = 0; p < 6; ++p) {
3926         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);
3927       }
3928 #endif
3929       /* B hex */
3930       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
3931       orntNew[0] = ornt[0];
3932       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
3933       orntNew[1] = 0;
3934       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
3935       orntNew[2] = -1;
3936       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
3937       orntNew[3] = ornt[3];
3938       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
3939       orntNew[4] = 0;
3940       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
3941       orntNew[5] = ornt[5];
3942       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
3943       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
3944 #if 1
3945       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);
3946       for (p = 0; p < 6; ++p) {
3947         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);
3948       }
3949 #endif
3950       /* C hex */
3951       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
3952       orntNew[0] = ornt[0];
3953       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
3954       orntNew[1] = 0;
3955       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
3956       orntNew[2] = -1;
3957       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
3958       orntNew[3] = ornt[3];
3959       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
3960       orntNew[4] = ornt[4];
3961       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
3962       orntNew[5] = -4;
3963       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
3964       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
3965 #if 1
3966       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);
3967       for (p = 0; p < 6; ++p) {
3968         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);
3969       }
3970 #endif
3971       /* D hex */
3972       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
3973       orntNew[0] = ornt[0];
3974       coneNew[1] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
3975       orntNew[1] = 0;
3976       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
3977       orntNew[2] = ornt[2];
3978       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
3979       orntNew[3] = 0;
3980       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
3981       orntNew[4] = ornt[4];
3982       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
3983       orntNew[5] = -4;
3984       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
3985       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
3986 #if 1
3987       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);
3988       for (p = 0; p < 6; ++p) {
3989         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);
3990       }
3991 #endif
3992       /* E hex */
3993       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
3994       orntNew[0] = -4;
3995       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
3996       orntNew[1] = ornt[1];
3997       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
3998       orntNew[2] = ornt[2];
3999       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
4000       orntNew[3] = 0;
4001       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
4002       orntNew[4] = -1;
4003       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
4004       orntNew[5] = ornt[5];
4005       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
4006       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
4007 #if 1
4008       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);
4009       for (p = 0; p < 6; ++p) {
4010         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);
4011       }
4012 #endif
4013       /* F hex */
4014       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
4015       orntNew[0] = -4;
4016       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
4017       orntNew[1] = ornt[1];
4018       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
4019       orntNew[2] = ornt[2];
4020       coneNew[3] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4021       orntNew[3] = -1;
4022       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
4023       orntNew[4] = ornt[4];
4024       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
4025       orntNew[5] = 1;
4026       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
4027       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
4028 #if 1
4029       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);
4030       for (p = 0; p < 6; ++p) {
4031         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);
4032       }
4033 #endif
4034       /* G hex */
4035       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
4036       orntNew[0] = -4;
4037       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
4038       orntNew[1] = ornt[1];
4039       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4040       orntNew[2] = 0;
4041       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
4042       orntNew[3] = ornt[3];
4043       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
4044       orntNew[4] = ornt[4];
4045       coneNew[5] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
4046       orntNew[5] = -3;
4047       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
4048       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
4049 #if 1
4050       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);
4051       for (p = 0; p < 6; ++p) {
4052         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);
4053       }
4054 #endif
4055       /* H hex */
4056       coneNew[0] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
4057       orntNew[0] = -4;
4058       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
4059       orntNew[1] = ornt[1];
4060       coneNew[2] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
4061       orntNew[2] = -1;
4062       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
4063       orntNew[3] = ornt[3];
4064       coneNew[4] = fStartNew + (fEnd    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
4065       orntNew[4] = 3;
4066       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
4067       orntNew[5] = ornt[5];
4068       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
4069       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
4070 #if 1
4071       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);
4072       for (p = 0; p < 6; ++p) {
4073         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);
4074       }
4075 #endif
4076     }
4077     /* Split faces have 4 edges and the same cells as the parent */
4078     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4079     ierr = PetscMalloc1(4 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
4080     for (f = fStart; f < fEnd; ++f) {
4081       for (r = 0; r < 4; ++r) {
4082         /* TODO: This can come from GetFaces_Internal() */
4083         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};
4084         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
4085         const PetscInt *cone, *ornt, *support;
4086         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
4087 
4088         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4089         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4090         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
4091         orntNew[(r+3)%4] = ornt[(r+3)%4];
4092         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
4093         orntNew[(r+0)%4] = ornt[r];
4094         coneNew[(r+1)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
4095         orntNew[(r+1)%4] = 0;
4096         coneNew[(r+2)%4] = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + (r+3)%4;
4097         orntNew[(r+2)%4] = -2;
4098         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4099         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4100 #if 1
4101         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4102         for (p = 0; p < 4; ++p) {
4103           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);
4104         }
4105 #endif
4106         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4107         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4108         for (s = 0; s < supportSize; ++s) {
4109           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4110           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4111           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4112           for (c = 0; c < coneSize; ++c) {
4113             if (cone[c] == f) break;
4114           }
4115           supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+GetQuadSubfaceInverse_Static(ornt[c], r)];
4116         }
4117         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4118 #if 1
4119         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4120         for (p = 0; p < supportSize; ++p) {
4121           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);
4122         }
4123 #endif
4124       }
4125     }
4126     /* Interior faces have 4 edges and 2 cells */
4127     for (c = cStart; c < cEnd; ++c) {
4128       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};
4129       const PetscInt *cone, *ornt;
4130       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
4131 
4132       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4133       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4134       /* A-D face */
4135       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 0;
4136       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
4137       orntNew[0] = 0;
4138       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
4139       orntNew[1] = 0;
4140       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
4141       orntNew[2] = -2;
4142       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
4143       orntNew[3] = -2;
4144       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4145       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4146 #if 1
4147       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4148       for (p = 0; p < 4; ++p) {
4149         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);
4150       }
4151 #endif
4152       /* C-D face */
4153       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 1;
4154       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
4155       orntNew[0] = 0;
4156       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
4157       orntNew[1] = 0;
4158       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
4159       orntNew[2] = -2;
4160       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
4161       orntNew[3] = -2;
4162       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4163       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4164 #if 1
4165       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4166       for (p = 0; p < 4; ++p) {
4167         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);
4168       }
4169 #endif
4170       /* B-C face */
4171       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 2;
4172       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
4173       orntNew[0] = -2;
4174       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
4175       orntNew[1] = 0;
4176       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
4177       orntNew[2] = 0;
4178       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
4179       orntNew[3] = -2;
4180       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4181       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4182 #if 1
4183       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4184       for (p = 0; p < 4; ++p) {
4185         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);
4186       }
4187 #endif
4188       /* A-B face */
4189       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 3;
4190       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
4191       orntNew[0] = -2;
4192       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
4193       orntNew[1] = 0;
4194       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
4195       orntNew[2] = 0;
4196       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 0;
4197       orntNew[3] = -2;
4198       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4199       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4200 #if 1
4201       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4202       for (p = 0; p < 4; ++p) {
4203         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);
4204       }
4205 #endif
4206       /* E-F face */
4207       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 4;
4208       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
4209       orntNew[0] = -2;
4210       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
4211       orntNew[1] = -2;
4212       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
4213       orntNew[2] = 0;
4214       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
4215       orntNew[3] = 0;
4216       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4217       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4218 #if 1
4219       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4220       for (p = 0; p < 4; ++p) {
4221         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);
4222       }
4223 #endif
4224       /* F-G face */
4225       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 5;
4226       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
4227       orntNew[0] = -2;
4228       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
4229       orntNew[1] = -2;
4230       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
4231       orntNew[2] = 0;
4232       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
4233       orntNew[3] = 0;
4234       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4235       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4236 #if 1
4237       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4238       for (p = 0; p < 4; ++p) {
4239         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);
4240       }
4241 #endif
4242       /* G-H face */
4243       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 6;
4244       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
4245       orntNew[0] = -2;
4246       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
4247       orntNew[1] = 0;
4248       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
4249       orntNew[2] = 0;
4250       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
4251       orntNew[3] = -2;
4252       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4253       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4254 #if 1
4255       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4256       for (p = 0; p < 4; ++p) {
4257         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);
4258       }
4259 #endif
4260       /* E-H face */
4261       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 7;
4262       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
4263       orntNew[0] = -2;
4264       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
4265       orntNew[1] = -2;
4266       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
4267       orntNew[2] = 0;
4268       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 1;
4269       orntNew[3] = 0;
4270       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4271       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4272 #if 1
4273       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4274       for (p = 0; p < 4; ++p) {
4275         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);
4276       }
4277 #endif
4278       /* A-E face */
4279       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 8;
4280       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
4281       orntNew[0] = 0;
4282       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
4283       orntNew[1] = 0;
4284       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
4285       orntNew[2] = -2;
4286       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
4287       orntNew[3] = -2;
4288       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4289       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4290 #if 1
4291       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4292       for (p = 0; p < 4; ++p) {
4293         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);
4294       }
4295 #endif
4296       /* D-F face */
4297       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 9;
4298       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
4299       orntNew[0] = -2;
4300       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
4301       orntNew[1] = 0;
4302       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
4303       orntNew[2] = 0;
4304       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 2;
4305       orntNew[3] = -2;
4306       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4307       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4308 #if 1
4309       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4310       for (p = 0; p < 4; ++p) {
4311         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);
4312       }
4313 #endif
4314       /* C-G face */
4315       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 10;
4316       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 4;
4317       orntNew[0] = -2;
4318       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
4319       orntNew[1] = -2;
4320       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
4321       orntNew[2] = 0;
4322       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
4323       orntNew[3] = 0;
4324       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4325       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4326 #if 1
4327       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4328       for (p = 0; p < 4; ++p) {
4329         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);
4330       }
4331 #endif
4332       /* B-H face */
4333       newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + 11;
4334       coneNew[0] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 5;
4335       orntNew[0] = 0;
4336       coneNew[1] = eStartNew + (eEnd - eStart)*2 + (fEnd    - fStart)*4 + (c - cStart)*6 + 3;
4337       orntNew[1] = -2;
4338       coneNew[2] = eStartNew + (eEnd - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
4339       orntNew[2] = -2;
4340       coneNew[3] = eStartNew + (eEnd - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
4341       orntNew[3] = 0;
4342       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4343       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4344 #if 1
4345       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4346       for (p = 0; p < 4; ++p) {
4347         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);
4348       }
4349 #endif
4350       for (r = 0; r < 12; ++r) {
4351         newp = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + r;
4352         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
4353         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
4354         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4355 #if 1
4356         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4357         for (p = 0; p < 2; ++p) {
4358           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);
4359         }
4360 #endif
4361       }
4362     }
4363     /* Split edges have 2 vertices and the same faces as the parent */
4364     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4365     for (e = eStart; e < eEnd; ++e) {
4366       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
4367 
4368       for (r = 0; r < 2; ++r) {
4369         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
4370         const PetscInt *cone, *ornt, *support;
4371         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4372 
4373         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
4374         coneNew[0]       = vStartNew + (cone[0] - vStart);
4375         coneNew[1]       = vStartNew + (cone[1] - vStart);
4376         coneNew[(r+1)%2] = newv;
4377         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4378 #if 1
4379         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4380         for (p = 0; p < 2; ++p) {
4381           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);
4382         }
4383 #endif
4384         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
4385         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4386         for (s = 0; s < supportSize; ++s) {
4387           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4388           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4389           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4390           for (c = 0; c < coneSize; ++c) {
4391             if (cone[c] == e) break;
4392           }
4393           supportRef[s] = fStartNew + (support[s] - fStart)*4 + (ornt[c] < 0 ? (c+1-r)%4 : (c+r)%4);
4394         }
4395         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4396 #if 1
4397         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4398         for (p = 0; p < supportSize; ++p) {
4399           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);
4400         }
4401 #endif
4402       }
4403     }
4404     /* Face edges have 2 vertices and 2+cells faces */
4405     for (f = fStart; f < fEnd; ++f) {
4406       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};
4407       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
4408       const PetscInt *cone, *coneCell, *orntCell, *support;
4409       PetscInt        coneNew[2], coneSize, c, supportSize, s;
4410 
4411       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4412       for (r = 0; r < 4; ++r) {
4413         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (f - fStart)*4 + r;
4414 
4415         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
4416         coneNew[1] = newv;
4417         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4418 #if 1
4419         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4420         for (p = 0; p < 2; ++p) {
4421           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);
4422         }
4423 #endif
4424         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4425         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4426         supportRef[0] = fStartNew + (f - fStart)*4 + r;
4427         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
4428         for (s = 0; s < supportSize; ++s) {
4429           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4430           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
4431           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
4432           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
4433           supportRef[2+s] = fStartNew + (fEnd - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
4434         }
4435         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4436 #if 1
4437         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4438         for (p = 0; p < 2+supportSize; ++p) {
4439           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);
4440         }
4441 #endif
4442       }
4443     }
4444     /* Cell edges have 2 vertices and 4 faces */
4445     for (c = cStart; c < cEnd; ++c) {
4446       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};
4447       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
4448       const PetscInt *cone;
4449       PetscInt        coneNew[2], supportNew[4];
4450 
4451       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4452       for (r = 0; r < 6; ++r) {
4453         const PetscInt newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
4454 
4455         coneNew[0] = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (cone[r] - fStart);
4456         coneNew[1] = newv;
4457         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4458 #if 1
4459         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4460         for (p = 0; p < 2; ++p) {
4461           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);
4462         }
4463 #endif
4464         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fEnd - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
4465         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4466 #if 1
4467         if ((newp < eStartNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eEndNew);
4468         for (p = 0; p < 4; ++p) {
4469           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);
4470         }
4471 #endif
4472       }
4473     }
4474     /* Old vertices have identical supports */
4475     for (v = vStart; v < vEnd; ++v) {
4476       const PetscInt  newp = vStartNew + (v - vStart);
4477       const PetscInt *support, *cone;
4478       PetscInt        size, s;
4479 
4480       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4481       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4482       for (s = 0; s < size; ++s) {
4483         PetscInt r = 0;
4484 
4485         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4486         if (cone[1] == v) r = 1;
4487         supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
4488       }
4489       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4490 #if 1
4491       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4492       for (p = 0; p < size; ++p) {
4493         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);
4494       }
4495 #endif
4496     }
4497     /* Edge vertices have 2 + faces supports */
4498     for (e = eStart; e < eEnd; ++e) {
4499       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
4500       const PetscInt *cone, *support;
4501       PetscInt        size, s;
4502 
4503       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
4504       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
4505       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
4506       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
4507       for (s = 0; s < size; ++s) {
4508         PetscInt r;
4509 
4510         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4511         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
4512         supportRef[2+s] = eStartNew + (eEnd - eStart)*2 + (support[s] - fStart)*4 + r;
4513       }
4514       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4515 #if 1
4516       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4517       for (p = 0; p < 2+size; ++p) {
4518         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);
4519       }
4520 #endif
4521     }
4522     /* Face vertices have 4 + cells supports */
4523     for (f = fStart; f < fEnd; ++f) {
4524       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (f - fStart);
4525       const PetscInt *cone, *support;
4526       PetscInt        size, s;
4527 
4528       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4529       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4530       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eEnd - eStart)*2 +  (f - fStart)*4 + r;
4531       for (s = 0; s < size; ++s) {
4532         PetscInt r;
4533 
4534         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4535         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
4536         supportRef[4+s] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (support[s] - cStart)*6 + r;
4537       }
4538       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4539 #if 1
4540       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4541       for (p = 0; p < 4+size; ++p) {
4542         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);
4543       }
4544 #endif
4545     }
4546     /* Cell vertices have 6 supports */
4547     for (c = cStart; c < cEnd; ++c) {
4548       const PetscInt newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (c - cStart);
4549       PetscInt       supportNew[6];
4550 
4551       for (r = 0; r < 6; ++r) {
4552         supportNew[r] = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (c - cStart)*6 + r;
4553       }
4554       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4555     }
4556     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4557     break;
4558   case REFINER_HYBRID_HEX_3D:
4559     ierr = DMPlexGetHybridBounds(rdm, &cMaxNew, &fMaxNew, &eMaxNew, NULL);CHKERRQ(ierr);
4560     /*
4561      Bottom (viewed from top)    Top
4562      1---------2---------2       7---------2---------6
4563      |         |         |       |         |         |
4564      |    B    2    C    |       |    H    2    G    |
4565      |         |         |       |         |         |
4566      3----3----0----1----1       3----3----0----1----1
4567      |         |         |       |         |         |
4568      |    A    0    D    |       |    E    0    F    |
4569      |         |         |       |         |         |
4570      0---------0---------3       4---------0---------5
4571      */
4572     /* Interior cells have 6 faces: Bottom, Top, Front, Back, Right, Left */
4573     for (c = cStart; c < cMax; ++c) {
4574       const PetscInt  newp = (c - cStart)*8;
4575       const PetscInt *cone, *ornt;
4576       PetscInt        coneNew[6], orntNew[6];
4577 
4578       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4579       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4580       /* A hex */
4581       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 0);
4582       orntNew[0] = ornt[0];
4583       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
4584       orntNew[1] = 0;
4585       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 0);
4586       orntNew[2] = ornt[2];
4587       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
4588       orntNew[3] = 0;
4589       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
4590       orntNew[4] = 0;
4591       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 0);
4592       orntNew[5] = ornt[5];
4593       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4594       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4595 #if 1
4596       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);
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       /* B hex */
4602       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 1);
4603       orntNew[0] = ornt[0];
4604       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
4605       orntNew[1] = 0;
4606       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  3; /* AB */
4607       orntNew[2] = -1;
4608       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 1);
4609       orntNew[3] = ornt[3];
4610       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
4611       orntNew[4] = 0;
4612       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 3);
4613       orntNew[5] = ornt[5];
4614       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4615       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4616 #if 1
4617       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);
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       /* C hex */
4623       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 2);
4624       orntNew[0] = ornt[0];
4625       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
4626       orntNew[1] = 0;
4627       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
4628       orntNew[2] = -1;
4629       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 0);
4630       orntNew[3] = ornt[3];
4631       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 1);
4632       orntNew[4] = ornt[4];
4633       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  2; /* BC */
4634       orntNew[5] = -4;
4635       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4636       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4637 #if 1
4638       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);
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       /* D hex */
4644       coneNew[0] = fStartNew + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], 3);
4645       orntNew[0] = ornt[0];
4646       coneNew[1] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
4647       orntNew[1] = 0;
4648       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 1);
4649       orntNew[2] = ornt[2];
4650       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  1; /* CD */
4651       orntNew[3] = 0;
4652       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 0);
4653       orntNew[4] = ornt[4];
4654       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  0; /* AD */
4655       orntNew[5] = -4;
4656       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4657       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4658 #if 1
4659       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);
4660       for (p = 0; p < 6; ++p) {
4661         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);
4662       }
4663 #endif
4664       /* E hex */
4665       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  8; /* AE */
4666       orntNew[0] = -4;
4667       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 0);
4668       orntNew[1] = ornt[1];
4669       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 3);
4670       orntNew[2] = ornt[2];
4671       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
4672       orntNew[3] = 0;
4673       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
4674       orntNew[4] = -1;
4675       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 1);
4676       orntNew[5] = ornt[5];
4677       ierr       = DMPlexSetCone(rdm, newp+4, coneNew);CHKERRQ(ierr);
4678       ierr       = DMPlexSetConeOrientation(rdm, newp+4, orntNew);CHKERRQ(ierr);
4679 #if 1
4680       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);
4681       for (p = 0; p < 6; ++p) {
4682         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);
4683       }
4684 #endif
4685       /* F hex */
4686       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  9; /* DF */
4687       orntNew[0] = -4;
4688       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 1);
4689       orntNew[1] = ornt[1];
4690       coneNew[2] = fStartNew + (cone[2] - fStart)*4 + GetQuadSubface_Static(ornt[2], 2);
4691       orntNew[2] = ornt[2];
4692       coneNew[3] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4693       orntNew[3] = -1;
4694       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 3);
4695       orntNew[4] = ornt[4];
4696       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  4; /* EF */
4697       orntNew[5] = 1;
4698       ierr       = DMPlexSetCone(rdm, newp+5, coneNew);CHKERRQ(ierr);
4699       ierr       = DMPlexSetConeOrientation(rdm, newp+5, orntNew);CHKERRQ(ierr);
4700 #if 1
4701       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);
4702       for (p = 0; p < 6; ++p) {
4703         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);
4704       }
4705 #endif
4706       /* G hex */
4707       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 10; /* CG */
4708       orntNew[0] = -4;
4709       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 2);
4710       orntNew[1] = ornt[1];
4711       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  5; /* FG */
4712       orntNew[2] = 0;
4713       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 3);
4714       orntNew[3] = ornt[3];
4715       coneNew[4] = fStartNew + (cone[4] - fStart)*4 + GetQuadSubface_Static(ornt[4], 2);
4716       orntNew[4] = ornt[4];
4717       coneNew[5] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
4718       orntNew[5] = -3;
4719       ierr       = DMPlexSetCone(rdm, newp+6, coneNew);CHKERRQ(ierr);
4720       ierr       = DMPlexSetConeOrientation(rdm, newp+6, orntNew);CHKERRQ(ierr);
4721 #if 1
4722       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);
4723       for (p = 0; p < 6; ++p) {
4724         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);
4725       }
4726 #endif
4727       /* H hex */
4728       coneNew[0] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 + 11; /* BH */
4729       orntNew[0] = -4;
4730       coneNew[1] = fStartNew + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], 3);
4731       orntNew[1] = ornt[1];
4732       coneNew[2] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  7; /* EH */
4733       orntNew[2] = -1;
4734       coneNew[3] = fStartNew + (cone[3] - fStart)*4 + GetQuadSubface_Static(ornt[3], 2);
4735       orntNew[3] = ornt[3];
4736       coneNew[4] = fStartNew + (fMax    - fStart)*4 + (c - cStart)*12 +  6; /* GH */
4737       orntNew[4] = 3;
4738       coneNew[5] = fStartNew + (cone[5] - fStart)*4 + GetQuadSubface_Static(ornt[5], 2);
4739       orntNew[5] = ornt[5];
4740       ierr       = DMPlexSetCone(rdm, newp+7, coneNew);CHKERRQ(ierr);
4741       ierr       = DMPlexSetConeOrientation(rdm, newp+7, orntNew);CHKERRQ(ierr);
4742 #if 1
4743       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);
4744       for (p = 0; p < 6; ++p) {
4745         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);
4746       }
4747 #endif
4748     }
4749     /* Hybrid cells have 6 faces: Front, Back, Sides */
4750     /*
4751      3---------2---------2
4752      |         |         |
4753      |    D    2    C    |
4754      |         |         |
4755      3----3----0----1----1
4756      |         |         |
4757      |    A    0    B    |
4758      |         |         |
4759      0---------0---------1
4760      */
4761     for (c = cMax; c < cEnd; ++c) {
4762       const PetscInt  newp = (cMax - cStart)*8 + (c - cMax)*4;
4763       const PetscInt *cone, *ornt, *fornt;
4764       PetscInt        coneNew[6], orntNew[6], o, of, i;
4765 
4766       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4767       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4768       ierr = DMPlexGetConeOrientation(dm, cone[0], &fornt);CHKERRQ(ierr);
4769       o = ornt[0] < 0 ? -1 : 1;
4770       for (r = 0; r < 4; ++r) {
4771         PetscInt subfA = GetQuadSubface_Static(ornt[0], r);
4772         PetscInt edgeA = GetQuadEdge_Static(ornt[0], r);
4773         PetscInt edgeB = GetQuadEdge_Static(ornt[0], (r+3)%4);
4774         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]);
4775         coneNew[0]         = fStartNew + (cone[0] - fStart)*4 + subfA;
4776         orntNew[0]         = ornt[0];
4777         coneNew[1]         = fStartNew + (cone[1] - fStart)*4 + subfA;
4778         orntNew[1]         = ornt[0];
4779         of = fornt[edgeA] < 0 ? -1 : 1;
4780         i  = GetQuadEdgeInverse_Static(ornt[0], r) + 2;
4781         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeA] - fMax)*2 + (o*of < 0 ? 1 : 0);
4782         orntNew[i] = ornt[edgeA];
4783         i  = GetQuadEdgeInverse_Static(ornt[0], (r+1)%4) + 2;
4784         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeA;
4785         orntNew[i] = 0;
4786         i  = GetQuadEdgeInverse_Static(ornt[0], (r+2)%4) + 2;
4787         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd          - fMax)*2 + (c - cMax)*4 + edgeB;
4788         orntNew[i] = -2;
4789         of = fornt[edgeB] < 0 ? -1 : 1;
4790         i  = GetQuadEdgeInverse_Static(ornt[0], (r+3)%4) + 2;
4791         coneNew[i] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (cone[2+edgeB] - fMax)*2 + (o*of < 0 ? 0 : 1);
4792         orntNew[i] = ornt[edgeB];
4793         ierr       = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
4794         ierr       = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
4795 #if 1
4796         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);
4797         for (p = 0; p < 2; ++p) {
4798           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);
4799         }
4800         for (p = 2; p < 6; ++p) {
4801           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);
4802         }
4803 #endif
4804       }
4805     }
4806     /* Interior split faces have 4 edges and the same cells as the parent */
4807     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4808     ierr = PetscMalloc1(4 + maxSupportSize*2, &supportRef);CHKERRQ(ierr);
4809     for (f = fStart; f < fMax; ++f) {
4810       for (r = 0; r < 4; ++r) {
4811         /* TODO: This can come from GetFaces_Internal() */
4812         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};
4813         const PetscInt  newp = fStartNew + (f - fStart)*4 + r;
4814         const PetscInt *cone, *ornt, *support;
4815         PetscInt        coneNew[4], orntNew[4], coneSize, c, supportSize, s;
4816 
4817         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4818         ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
4819         coneNew[(r+3)%4] = eStartNew + (cone[(r+3)%4] - eStart)*2 + (ornt[(r+3)%4] < 0 ? 0 : 1);
4820         orntNew[(r+3)%4] = ornt[(r+3)%4];
4821         coneNew[(r+0)%4] = eStartNew + (cone[r]       - eStart)*2 + (ornt[r] < 0 ? 1 : 0);
4822         orntNew[(r+0)%4] = ornt[r];
4823         coneNew[(r+1)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
4824         orntNew[(r+1)%4] = 0;
4825         coneNew[(r+2)%4] = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + (r+3)%4;
4826         orntNew[(r+2)%4] = -2;
4827         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4828         ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4829 #if 1
4830         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4831         for (p = 0; p < 4; ++p) {
4832           if ((coneNew[p] < eStartNew) || (coneNew[p] >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", coneNew[p], eStartNew, eMaxNew);
4833         }
4834 #endif
4835         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4836         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4837         for (s = 0; s < supportSize; ++s) {
4838           PetscInt subf;
4839           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4840           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4841           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4842           for (c = 0; c < coneSize; ++c) {
4843             if (cone[c] == f) break;
4844           }
4845           subf = GetQuadSubfaceInverse_Static(ornt[c], r);
4846           if (support[s] < cMax) {
4847             supportRef[s] = cStartNew + (support[s] - cStart)*8 + newCells[c*4+subf];
4848           } else {
4849             supportRef[s] = cStartNew + (cMax       - cStart)*8 + (support[s] - cMax)*4 + subf;
4850           }
4851         }
4852         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4853 #if 1
4854         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4855         for (p = 0; p < supportSize; ++p) {
4856           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);
4857         }
4858 #endif
4859       }
4860     }
4861     /* Interior cell faces have 4 edges and 2 cells */
4862     for (c = cStart; c < cMax; ++c) {
4863       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};
4864       const PetscInt *cone, *ornt;
4865       PetscInt        newp, coneNew[4], orntNew[4], supportNew[2];
4866 
4867       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4868       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4869       /* A-D face */
4870       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 0;
4871       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 3);
4872       orntNew[0] = 0;
4873       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4874       orntNew[1] = 0;
4875       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4876       orntNew[2] = -2;
4877       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 0);
4878       orntNew[3] = -2;
4879       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4880       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4881 #if 1
4882       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4883       for (p = 0; p < 4; ++p) {
4884         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);
4885       }
4886 #endif
4887       /* C-D face */
4888       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 1;
4889       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 2);
4890       orntNew[0] = 0;
4891       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4892       orntNew[1] = 0;
4893       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4894       orntNew[2] = -2;
4895       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 0);
4896       orntNew[3] = -2;
4897       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4898       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4899 #if 1
4900       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4901       for (p = 0; p < 4; ++p) {
4902         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);
4903       }
4904 #endif
4905       /* B-C face */
4906       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 2;
4907       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 1);
4908       orntNew[0] = -2;
4909       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 0);
4910       orntNew[1] = 0;
4911       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4912       orntNew[2] = 0;
4913       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4914       orntNew[3] = -2;
4915       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4916       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4917 #if 1
4918       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4919       for (p = 0; p < 4; ++p) {
4920         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);
4921       }
4922 #endif
4923       /* A-B face */
4924       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 3;
4925       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadEdge_Static(ornt[0], 0);
4926       orntNew[0] = -2;
4927       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 3);
4928       orntNew[1] = 0;
4929       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4930       orntNew[2] = 0;
4931       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 0;
4932       orntNew[3] = -2;
4933       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4934       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4935 #if 1
4936       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4937       for (p = 0; p < 4; ++p) {
4938         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);
4939       }
4940 #endif
4941       /* E-F face */
4942       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 4;
4943       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
4944       orntNew[0] = -2;
4945       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 2);
4946       orntNew[1] = -2;
4947       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 0);
4948       orntNew[2] = 0;
4949       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4950       orntNew[3] = 0;
4951       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4952       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4953 #if 1
4954       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4955       for (p = 0; p < 4; ++p) {
4956         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);
4957       }
4958 #endif
4959       /* F-G face */
4960       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 5;
4961       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
4962       orntNew[0] = -2;
4963       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 2);
4964       orntNew[1] = -2;
4965       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 1);
4966       orntNew[2] = 0;
4967       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4968       orntNew[3] = 0;
4969       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4970       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4971 #if 1
4972       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4973       for (p = 0; p < 4; ++p) {
4974         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);
4975       }
4976 #endif
4977       /* G-H face */
4978       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 6;
4979       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 2);
4980       orntNew[0] = -2;
4981       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 2);
4982       orntNew[1] = 0;
4983       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
4984       orntNew[2] = 0;
4985       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
4986       orntNew[3] = -2;
4987       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4988       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
4989 #if 1
4990       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
4991       for (p = 0; p < 4; ++p) {
4992         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);
4993       }
4994 #endif
4995       /* E-H face */
4996       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 7;
4997       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
4998       orntNew[0] = -2;
4999       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 1);
5000       orntNew[1] = -2;
5001       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadEdge_Static(ornt[1], 3);
5002       orntNew[2] = 0;
5003       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 1;
5004       orntNew[3] = 0;
5005       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5006       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5007 #if 1
5008       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5009       for (p = 0; p < 4; ++p) {
5010         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);
5011       }
5012 #endif
5013       /* A-E face */
5014       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 8;
5015       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 3);
5016       orntNew[0] = 0;
5017       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
5018       orntNew[1] = 0;
5019       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
5020       orntNew[2] = -2;
5021       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 0);
5022       orntNew[3] = -2;
5023       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5024       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5025 #if 1
5026       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5027       for (p = 0; p < 4; ++p) {
5028         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);
5029       }
5030 #endif
5031       /* D-F face */
5032       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 9;
5033       coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[2] - fStart)*4 + GetQuadEdge_Static(ornt[2], 1);
5034       orntNew[0] = -2;
5035       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 3);
5036       orntNew[1] = 0;
5037       coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
5038       orntNew[2] = 0;
5039       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 2;
5040       orntNew[3] = -2;
5041       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5042       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5043 #if 1
5044       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5045       for (p = 0; p < 4; ++p) {
5046         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);
5047       }
5048 #endif
5049       /* C-G face */
5050       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 10;
5051       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 4;
5052       orntNew[0] = -2;
5053       coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[4] - fStart)*4 + GetQuadEdge_Static(ornt[4], 1);
5054       orntNew[1] = -2;
5055       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 3);
5056       orntNew[2] = 0;
5057       coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
5058       orntNew[3] = 0;
5059       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5060       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5061 #if 1
5062       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5063       for (p = 0; p < 4; ++p) {
5064         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);
5065       }
5066 #endif
5067       /* B-H face */
5068       newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + 11;
5069       coneNew[0] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 5;
5070       orntNew[0] = 0;
5071       coneNew[1] = eStartNew + (eMax - eStart)*2 + (fMax    - fStart)*4 + (c - cStart)*6 + 3;
5072       orntNew[1] = -2;
5073       coneNew[2] = eStartNew + (eMax - eStart)*2 + (cone[3] - fStart)*4 + GetQuadEdge_Static(ornt[3], 1);
5074       orntNew[2] = -2;
5075       coneNew[3] = eStartNew + (eMax - eStart)*2 + (cone[5] - fStart)*4 + GetQuadEdge_Static(ornt[5], 2);
5076       orntNew[3] = 0;
5077       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5078       ierr       = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5079 #if 1
5080       if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5081       for (p = 0; p < 4; ++p) {
5082         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);
5083       }
5084 #endif
5085       for (r = 0; r < 12; ++r) {
5086         newp = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + r;
5087         supportNew[0] = cStartNew + (c - cStart)*8 + newCells[r*2+0];
5088         supportNew[1] = cStartNew + (c - cStart)*8 + newCells[r*2+1];
5089         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5090 #if 1
5091         if ((newp < fStartNew) || (newp >= fMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fMaxNew);
5092         for (p = 0; p < 2; ++p) {
5093           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);
5094         }
5095 #endif
5096       }
5097     }
5098     /* Hybrid split faces have 4 edges and same cells */
5099     for (f = fMax; f < fEnd; ++f) {
5100       const PetscInt *cone, *ornt, *support;
5101       PetscInt        coneNew[4], orntNew[4];
5102       PetscInt        supportNew[2], size, s, c;
5103 
5104       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5105       ierr = DMPlexGetConeOrientation(dm, f, &ornt);CHKERRQ(ierr);
5106       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5107       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5108       for (r = 0; r < 2; ++r) {
5109         const PetscInt newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + r;
5110 
5111         coneNew[0]   = eStartNew + (cone[0] - eStart)*2 + (ornt[0] < 0 ? 1-r : r);
5112         orntNew[0]   = ornt[0];
5113         coneNew[1]   = eStartNew + (cone[1] - eStart)*2 + (ornt[1] < 0 ? 1-r : r);
5114         orntNew[1]   = ornt[1];
5115         coneNew[2+r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (cone[2+r] - eMax);
5116         orntNew[2+r] = 0;
5117         coneNew[3-r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd      - eMax) + (f - fMax);
5118         orntNew[3-r] = 0;
5119         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5120         ierr = DMPlexSetConeOrientation(rdm, newp, orntNew);CHKERRQ(ierr);
5121 #if 1
5122         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
5123         for (p = 0; p < 2; ++p) {
5124           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);
5125         }
5126         for (p = 2; p < 4; ++p) {
5127           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);
5128         }
5129 #endif
5130         for (s = 0; s < size; ++s) {
5131           const PetscInt *coneCell, *orntCell, *fornt;
5132           PetscInt        o, of;
5133 
5134           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
5135           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
5136           o = orntCell[0] < 0 ? -1 : 1;
5137           for (c = 2; c < 6; ++c) if (coneCell[c] == f) break;
5138           if (c >= 6) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %d in cone of cell %d", f, support[s]);
5139           ierr = DMPlexGetConeOrientation(dm, coneCell[0], &fornt);CHKERRQ(ierr);
5140           of = fornt[c-2] < 0 ? -1 : 1;
5141           supportNew[s] = cStartNew + (cMax - cStart)*8 + (support[s] - cMax)*4 + (GetQuadEdgeInverse_Static(orntCell[0], c-2) + (o*of < 0 ? 1-r : r))%4;
5142         }
5143         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5144 #if 1
5145         if ((newp < fMaxNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid face [%d, %d)", newp, fMaxNew, fEndNew);
5146         for (p = 0; p < size; ++p) {
5147           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);
5148         }
5149 #endif
5150       }
5151     }
5152     /* Hybrid cell faces have 4 edges and 2 cells */
5153     for (c = cMax; c < cEnd; ++c) {
5154       PetscInt        newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4;
5155       const PetscInt *cone, *ornt;
5156       PetscInt        coneNew[4], orntNew[4];
5157       PetscInt        supportNew[2];
5158 
5159       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5160       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5161       for (r = 0; r < 4; ++r) {
5162 #if 0
5163         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + GetQuadSubface_Static(ornt[0], r);
5164         orntNew[0] = 0;
5165         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + GetQuadSubface_Static(ornt[1], r);
5166         orntNew[1] = 0;
5167         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+GetQuadEdge_Static(ornt[0], r)] - fMax);
5168         orntNew[2] = 0;
5169         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd                                   - fMax) + (c - cMax);
5170         orntNew[3] = 0;
5171 #else
5172         coneNew[0] = eStartNew + (eMax - eStart)*2 + (cone[0] - fStart)*4 + r;
5173         orntNew[0] = 0;
5174         coneNew[1] = eStartNew + (eMax - eStart)*2 + (cone[1] - fStart)*4 + r;
5175         orntNew[1] = 0;
5176         coneNew[2] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (cone[2+r] - fMax);
5177         orntNew[2] = 0;
5178         coneNew[3] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd      - fMax) + (c - cMax);
5179         orntNew[3] = 0;
5180 #endif
5181         ierr = DMPlexSetCone(rdm, newp+r, coneNew);CHKERRQ(ierr);
5182         ierr = DMPlexSetConeOrientation(rdm, newp+r, orntNew);CHKERRQ(ierr);
5183 #if 1
5184         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);
5185         for (p = 0; p < 2; ++p) {
5186           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);
5187         }
5188         for (p = 2; p < 4; ++p) {
5189           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);
5190         }
5191 #endif
5192         supportNew[0] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], r);
5193         supportNew[1] = cStartNew + (cMax - cStart)*8 + (c - cMax)*4 + GetQuadSubface_Static(ornt[0], (r+1)%4);
5194         ierr          = DMPlexSetSupport(rdm, newp+r, supportNew);CHKERRQ(ierr);
5195 #if 1
5196         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);
5197         for (p = 0; p < 2; ++p) {
5198           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);
5199         }
5200 #endif
5201       }
5202     }
5203     /* Interior split edges have 2 vertices and the same faces as the parent */
5204     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
5205     for (e = eStart; e < eMax; ++e) {
5206       const PetscInt newv = vStartNew + (vEnd - vStart) + (e - eStart);
5207 
5208       for (r = 0; r < 2; ++r) {
5209         const PetscInt  newp = eStartNew + (e - eStart)*2 + r;
5210         const PetscInt *cone, *ornt, *support;
5211         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5212 
5213         ierr             = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
5214         coneNew[0]       = vStartNew + (cone[0] - vStart);
5215         coneNew[1]       = vStartNew + (cone[1] - vStart);
5216         coneNew[(r+1)%2] = newv;
5217         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5218 #if 1
5219         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5220         for (p = 0; p < 2; ++p) {
5221           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);
5222         }
5223 #endif
5224         ierr = DMPlexGetSupportSize(dm, e, &supportSize);CHKERRQ(ierr);
5225         ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5226         for (s = 0; s < supportSize; ++s) {
5227           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5228           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5229           ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
5230           for (c = 0; c < coneSize; ++c) {
5231             if (cone[c] == e) break;
5232           }
5233           if (support[s] < fMax) {
5234             supportRef[s] = fStartNew + (support[s] - fStart)*4 + (c + (ornt[c] < 0 ? 1-r : r))%4;
5235           } else {
5236             supportRef[s] = fStartNew + (fMax       - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + (ornt[c] < 0 ? 1-r : r);
5237           }
5238         }
5239         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5240 #if 1
5241         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5242         for (p = 0; p < supportSize; ++p) {
5243           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);
5244         }
5245 #endif
5246       }
5247     }
5248     /* Interior face edges have 2 vertices and 2+cells faces */
5249     for (f = fStart; f < fMax; ++f) {
5250       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};
5251       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
5252       const PetscInt *cone, *coneCell, *orntCell, *support;
5253       PetscInt        coneNew[2], coneSize, c, supportSize, s;
5254 
5255       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5256       for (r = 0; r < 4; ++r) {
5257         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (f - fStart)*4 + r;
5258 
5259         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - eStart);
5260         coneNew[1] = newv;
5261         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5262 #if 1
5263         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5264         for (p = 0; p < 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         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5269         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5270         supportRef[0] = fStartNew + (f - fStart)*4 + r;
5271         supportRef[1] = fStartNew + (f - fStart)*4 + (r+1)%4;
5272         for (s = 0; s < supportSize; ++s) {
5273           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5274           ierr = DMPlexGetCone(dm, support[s], &coneCell);CHKERRQ(ierr);
5275           ierr = DMPlexGetConeOrientation(dm, support[s], &orntCell);CHKERRQ(ierr);
5276           for (c = 0; c < coneSize; ++c) if (coneCell[c] == f) break;
5277           if (support[s] < cMax) {
5278             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (support[s] - cStart)*12 + newFaces[c*4 + GetQuadEdgeInverse_Static(orntCell[c], r)];
5279           } else {
5280             supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + r;
5281           }
5282         }
5283         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5284 #if 1
5285         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5286         for (p = 0; p < 2+supportSize; ++p) {
5287           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);
5288         }
5289 #endif
5290       }
5291     }
5292     /* Interior cell edges have 2 vertices and 4 faces */
5293     for (c = cStart; c < cMax; ++c) {
5294       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};
5295       const PetscInt  newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
5296       const PetscInt *cone;
5297       PetscInt        coneNew[2], supportNew[4];
5298 
5299       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5300       for (r = 0; r < 6; ++r) {
5301         const PetscInt newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
5302 
5303         coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[r] - fStart);
5304         coneNew[1] = newv;
5305         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5306 #if 1
5307         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5308         for (p = 0; p < 2; ++p) {
5309           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);
5310         }
5311 #endif
5312         for (f = 0; f < 4; ++f) supportNew[f] = fStartNew + (fMax - fStart)*4 + (c - cStart)*12 + newFaces[r*4+f];
5313         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5314 #if 1
5315         if ((newp < eStartNew) || (newp >= eMaxNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not an edge [%d, %d)", newp, eStartNew, eMaxNew);
5316         for (p = 0; p < 4; ++p) {
5317           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);
5318         }
5319 #endif
5320       }
5321     }
5322     /* Hybrid edges have two vertices and the same faces */
5323     for (e = eMax; e < eEnd; ++e) {
5324       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (e - eMax);
5325       const PetscInt *cone, *support, *fcone;
5326       PetscInt        coneNew[2], size, fsize, s;
5327 
5328       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
5329       ierr = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
5330       ierr = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5331       coneNew[0] = vStartNew + (cone[0] - vStart);
5332       coneNew[1] = vStartNew + (cone[1] - vStart);
5333       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5334 #if 1
5335       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5336       for (p = 0; p < 2; ++p) {
5337         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);
5338       }
5339 #endif
5340       for (s = 0; s < size; ++s) {
5341         ierr = DMPlexGetConeSize(dm, support[s], &fsize);CHKERRQ(ierr);
5342         ierr = DMPlexGetCone(dm, support[s], &fcone);CHKERRQ(ierr);
5343         for (c = 0; c < fsize; ++c) if (fcone[c] == e) break;
5344         if ((c < 2) || (c > 3)) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Edge %d not found in cone of face %d", e, support[s]);
5345         supportRef[s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (support[s] - fMax)*2 + c-2;
5346       }
5347       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5348 #if 1
5349       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5350       for (p = 0; p < size; ++p) {
5351         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);
5352       }
5353 #endif
5354     }
5355     /* Hybrid face edges have 2 vertices and 2+cells faces */
5356     for (f = fMax; f < fEnd; ++f) {
5357       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (f - fMax);
5358       const PetscInt *cone, *support, *ccone, *cornt;
5359       PetscInt        coneNew[2], size, csize, s;
5360 
5361       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5362       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5363       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5364       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - eStart);
5365       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - eStart);
5366       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5367 #if 1
5368       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5369       for (p = 0; p < 2; ++p) {
5370         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);
5371       }
5372 #endif
5373       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 0;
5374       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (f - fMax)*2 + 1;
5375       for (s = 0; s < size; ++s) {
5376         ierr = DMPlexGetConeSize(dm, support[s], &csize);CHKERRQ(ierr);
5377         ierr = DMPlexGetCone(dm, support[s], &ccone);CHKERRQ(ierr);
5378         ierr = DMPlexGetConeOrientation(dm, support[s], &cornt);CHKERRQ(ierr);
5379         for (c = 0; c < csize; ++c) if (ccone[c] == f) break;
5380         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]);
5381         supportRef[2+s] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (support[s] - cMax)*4 + c-2;
5382       }
5383       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5384 #if 1
5385       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5386       for (p = 0; p < 2+size; ++p) {
5387         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);
5388       }
5389 #endif
5390     }
5391     /* Hybrid cell edges have 2 vertices and 4 faces */
5392     for (c = cMax; c < cEnd; ++c) {
5393       const PetscInt  newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (c - cMax);
5394       const PetscInt *cone, *support;
5395       PetscInt        coneNew[2], size;
5396 
5397       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5398       ierr = DMPlexGetSupportSize(dm, c, &size);CHKERRQ(ierr);
5399       ierr = DMPlexGetSupport(dm, c, &support);CHKERRQ(ierr);
5400       coneNew[0] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[0] - fStart);
5401       coneNew[1] = vStartNew + (vEnd - vStart) + (eMax - eStart) + (cone[1] - fStart);
5402       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5403 #if 1
5404       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5405       for (p = 0; p < 2; ++p) {
5406         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);
5407       }
5408 #endif
5409       supportRef[0] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 0;
5410       supportRef[1] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 1;
5411       supportRef[2] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 2;
5412       supportRef[3] = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (c - cMax)*4 + 3;
5413       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5414 #if 1
5415       if ((newp < eMaxNew) || (newp >= eEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a hybrid edge [%d, %d)", newp, eMaxNew, eEndNew);
5416       for (p = 0; p < 4; ++p) {
5417         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);
5418       }
5419 #endif
5420     }
5421     /* Interior vertices have identical supports */
5422     for (v = vStart; v < vEnd; ++v) {
5423       const PetscInt  newp = vStartNew + (v - vStart);
5424       const PetscInt *support, *cone;
5425       PetscInt        size, s;
5426 
5427       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5428       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5429       for (s = 0; s < size; ++s) {
5430         PetscInt r = 0;
5431 
5432         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5433         if (cone[1] == v) r = 1;
5434         if (support[s] < eMax) supportRef[s] = eStartNew + (support[s] - eStart)*2 + r;
5435         else                   supportRef[s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (support[s] - eMax);
5436       }
5437       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5438 #if 1
5439       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5440       for (p = 0; p < size; ++p) {
5441         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);
5442       }
5443 #endif
5444     }
5445     /* Interior edge vertices have 2 + faces supports */
5446     for (e = eStart; e < eMax; ++e) {
5447       const PetscInt  newp = vStartNew + (vEnd - vStart) + (e - eStart);
5448       const PetscInt *cone, *support;
5449       PetscInt        size, s;
5450 
5451       ierr          = DMPlexGetSupportSize(dm, e, &size);CHKERRQ(ierr);
5452       ierr          = DMPlexGetSupport(dm, e, &support);CHKERRQ(ierr);
5453       supportRef[0] = eStartNew + (e - eStart)*2 + 0;
5454       supportRef[1] = eStartNew + (e - eStart)*2 + 1;
5455       for (s = 0; s < size; ++s) {
5456         PetscInt r;
5457 
5458         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5459         for (r = 0; r < 4; ++r) if (cone[r] == e) break;
5460         if (support[s] < fMax) {
5461           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (support[s] - fStart)*4 + r;
5462         } else {
5463           supportRef[2+s] = eStartNew + (eMax - eStart)*2 + (fMax       - fStart)*4 + (cMax - cStart)*6 + (eEnd - eMax) + (support[s] - fMax);
5464         }
5465       }
5466       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5467 #if 1
5468       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5469       for (p = 0; p < 2+size; ++p) {
5470         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);
5471       }
5472 #endif
5473     }
5474     /* Interior face vertices have 4 + cells supports */
5475     for (f = fStart; f < fMax; ++f) {
5476       const PetscInt  newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
5477       const PetscInt *cone, *support;
5478       PetscInt        size, s;
5479 
5480       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5481       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5482       for (r = 0; r < 4; ++r) supportRef[r] = eStartNew + (eMax - eStart)*2 +  (f - fStart)*4 + r;
5483       for (s = 0; s < size; ++s) {
5484         PetscInt r;
5485 
5486         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5487         for (r = 0; r < 6; ++r) if (cone[r] == f) break;
5488         if (support[s] < cMax) {
5489           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (support[s] - cStart)*6 + r;
5490         } else {
5491           supportRef[4+s] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax       - cStart)*6 + (eEnd - eMax) + (fEnd - fMax) + (support[s] - cMax);
5492         }
5493       }
5494       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5495 #if 1
5496       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5497       for (p = 0; p < 4+size; ++p) {
5498         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);
5499       }
5500 #endif
5501     }
5502     /* Cell vertices have 6 supports */
5503     for (c = cStart; c < cMax; ++c) {
5504       const PetscInt newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (c - cStart);
5505       PetscInt       supportNew[6];
5506 
5507       for (r = 0; r < 6; ++r) {
5508         supportNew[r] = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (c - cStart)*6 + r;
5509       }
5510       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5511     }
5512     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5513     break;
5514   default:
5515     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5516   }
5517   PetscFunctionReturn(0);
5518 }
5519 
5520 #undef __FUNCT__
5521 #define __FUNCT__ "CellRefinerSetCoordinates"
5522 static PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5523 {
5524   PetscSection   coordSection, coordSectionNew;
5525   Vec            coordinates, coordinatesNew;
5526   PetscScalar   *coords, *coordsNew;
5527   const PetscInt numVertices = depthSize ? depthSize[0] : 0;
5528   PetscInt       dim, spaceDim, depth, bs, coordSizeNew, cStart, cEnd, cMax, c, vStart, vStartNew, vEnd, v, eStart, eEnd, eMax, e, fStart, fEnd, fMax, f;
5529   PetscErrorCode ierr;
5530 
5531   PetscFunctionBegin;
5532   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
5533   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5534   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5535   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5536   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5537   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5538   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, NULL);CHKERRQ(ierr);
5539   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);}
5540   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
5541   ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5542   ierr = PetscSectionGetFieldComponents(coordSection, 0, &spaceDim);CHKERRQ(ierr);
5543   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
5544   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
5545   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, spaceDim);CHKERRQ(ierr);
5546   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+numVertices);CHKERRQ(ierr);
5547   if (cMax < 0) cMax = cEnd;
5548   if (fMax < 0) fMax = fEnd;
5549   if (eMax < 0) eMax = eEnd;
5550   /* All vertices have the spaceDim coordinates */
5551   for (v = vStartNew; v < vStartNew+numVertices; ++v) {
5552     ierr = PetscSectionSetDof(coordSectionNew, v, spaceDim);CHKERRQ(ierr);
5553     ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, spaceDim);CHKERRQ(ierr);
5554   }
5555   ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
5556   ierr = DMSetCoordinateSection(rdm, PETSC_DETERMINE, coordSectionNew);CHKERRQ(ierr);
5557   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5558   ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
5559   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);CHKERRQ(ierr);
5560   ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
5561   ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
5562   ierr = VecGetBlockSize(coordinates, &bs);CHKERRQ(ierr);
5563   ierr = VecSetBlockSize(coordinatesNew, bs);CHKERRQ(ierr);
5564   ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
5565   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
5566   ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5567   switch (refiner) {
5568   case REFINER_NOOP: break;
5569   case REFINER_HEX_3D:
5570   case REFINER_HYBRID_HEX_3D:
5571     /* Face vertices have the average of corner coordinates */
5572     for (f = fStart; f < fMax; ++f) {
5573       const PetscInt newv = vStartNew + (vEnd - vStart) + (eMax - eStart) + (f - fStart);
5574       PetscInt      *cone = NULL;
5575       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
5576 
5577       ierr = DMPlexGetTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5578       for (p = 0; p < closureSize*2; p += 2) {
5579         const PetscInt point = cone[p];
5580         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
5581       }
5582       for (v = 0; v < coneSize; ++v) {
5583         ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
5584       }
5585       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5586       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
5587       for (v = 0; v < coneSize; ++v) {ierr = DMPlexLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);CHKERRQ(ierr);}
5588       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
5589       ierr = DMPlexRestoreTransitiveClosure(dm, f, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5590     }
5591   case REFINER_HEX_2D:
5592   case REFINER_HYBRID_HEX_2D:
5593   case REFINER_SIMPLEX_1D:
5594     /* Cell vertices have the average of corner coordinates */
5595     for (c = cStart; c < cMax; ++c) {
5596       const PetscInt newv = vStartNew + (vEnd - vStart) + (dim > 1 ? (eMax - eStart) : 0) + (c - cStart) + (dim > 2 ? (fMax - fStart) : 0);
5597       PetscInt      *cone = NULL;
5598       PetscInt       closureSize, coneSize = 0, off[8], offnew, p, d;
5599 
5600       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5601       for (p = 0; p < closureSize*2; p += 2) {
5602         const PetscInt point = cone[p];
5603         if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
5604       }
5605       for (v = 0; v < coneSize; ++v) {
5606         ierr = PetscSectionGetOffset(coordSection, cone[v], &off[v]);CHKERRQ(ierr);
5607       }
5608       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5609       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] = 0.0;
5610       for (v = 0; v < coneSize; ++v) {ierr = DMPlexLocalizeAddCoordinate_Internal(dm, spaceDim, &coords[off[0]], &coords[off[v]], &coordsNew[offnew]);CHKERRQ(ierr);}
5611       for (d = 0; d < spaceDim; ++d) coordsNew[offnew+d] /= coneSize;
5612       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5613     }
5614   case REFINER_SIMPLEX_2D:
5615   case REFINER_HYBRID_SIMPLEX_2D:
5616   case REFINER_SIMPLEX_3D:
5617   case REFINER_HYBRID_SIMPLEX_3D:
5618     /* Edge vertices have the average of endpoint coordinates */
5619     for (e = eStart; e < eMax; ++e) {
5620       const PetscInt  newv = vStartNew + (vEnd - vStart) + (e - eStart);
5621       const PetscInt *cone;
5622       PetscInt        coneSize, offA, offB, offnew, d;
5623 
5624       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
5625       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
5626       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
5627       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
5628       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
5629       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5630       ierr = DMPlexLocalizeCoordinate_Internal(dm, spaceDim, &coords[offA], &coords[offB], &coordsNew[offnew]);CHKERRQ(ierr);
5631       for (d = 0; d < spaceDim; ++d) {
5632         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coordsNew[offnew+d]);
5633       }
5634     }
5635     /* Old vertices have the same coordinates */
5636     for (v = vStart; v < vEnd; ++v) {
5637       const PetscInt newv = vStartNew + (v - vStart);
5638       PetscInt       off, offnew, d;
5639 
5640       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5641       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5642       for (d = 0; d < spaceDim; ++d) {
5643         coordsNew[offnew+d] = coords[off+d];
5644       }
5645     }
5646     break;
5647   default:
5648     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5649   }
5650   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
5651   ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5652   ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
5653   ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
5654   ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
5655   if (dm->maxCell) {
5656     const PetscReal *maxCell, *L;
5657     const DMBoundaryType *bd;
5658     ierr = DMGetPeriodicity(dm,  &maxCell, &L, &bd);CHKERRQ(ierr);
5659     ierr = DMSetPeriodicity(rdm,  maxCell,  L,  bd);CHKERRQ(ierr);
5660   }
5661   PetscFunctionReturn(0);
5662 }
5663 
5664 #undef __FUNCT__
5665 #define __FUNCT__ "DMPlexCreateProcessSF"
5666 /*@
5667   DMPlexCreateProcessSF - Create an SF which just has process connectivity
5668 
5669   Collective on DM
5670 
5671   Input Parameters:
5672 + dm      - The DM
5673 - sfPoint - The PetscSF which encodes point connectivity
5674 
5675   Output Parameters:
5676 + processRanks - A list of process neighbors, or NULL
5677 - sfProcess    - An SF encoding the process connectivity, or NULL
5678 
5679   Level: developer
5680 
5681 .seealso: PetscSFCreate(), DMPlexCreateTwoSidedProcessSF()
5682 @*/
5683 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
5684 {
5685   PetscInt           numRoots, numLeaves, l;
5686   const PetscInt    *localPoints;
5687   const PetscSFNode *remotePoints;
5688   PetscInt          *localPointsNew;
5689   PetscSFNode       *remotePointsNew;
5690   PetscInt          *ranks, *ranksNew;
5691   PetscMPIInt        numProcs;
5692   PetscErrorCode     ierr;
5693 
5694   PetscFunctionBegin;
5695   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5696   PetscValidHeaderSpecific(sfPoint, PETSCSF_CLASSID, 2);
5697   if (processRanks) {PetscValidPointer(processRanks, 3);}
5698   if (sfProcess)    {PetscValidPointer(sfProcess, 4);}
5699   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) dm), &numProcs);CHKERRQ(ierr);
5700   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5701   ierr = PetscMalloc1(numLeaves, &ranks);CHKERRQ(ierr);
5702   for (l = 0; l < numLeaves; ++l) {
5703     ranks[l] = remotePoints[l].rank;
5704   }
5705   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
5706   ierr = PetscMalloc1(numLeaves, &ranksNew);CHKERRQ(ierr);
5707   ierr = PetscMalloc1(numLeaves, &localPointsNew);CHKERRQ(ierr);
5708   ierr = PetscMalloc1(numLeaves, &remotePointsNew);CHKERRQ(ierr);
5709   for (l = 0; l < numLeaves; ++l) {
5710     ranksNew[l]              = ranks[l];
5711     localPointsNew[l]        = l;
5712     remotePointsNew[l].index = 0;
5713     remotePointsNew[l].rank  = ranksNew[l];
5714   }
5715   ierr = PetscFree(ranks);CHKERRQ(ierr);
5716   if (processRanks) {ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);}
5717   else              {ierr = PetscFree(ranksNew);CHKERRQ(ierr);}
5718   if (sfProcess) {
5719     ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
5720     ierr = PetscObjectSetName((PetscObject) *sfProcess, "Process SF");CHKERRQ(ierr);
5721     ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
5722     ierr = PetscSFSetGraph(*sfProcess, numProcs, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
5723   }
5724   PetscFunctionReturn(0);
5725 }
5726 
5727 #undef __FUNCT__
5728 #define __FUNCT__ "CellRefinerCreateSF"
5729 static PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5730 {
5731   PetscSF            sf, sfNew, sfProcess;
5732   IS                 processRanks;
5733   MPI_Datatype       depthType;
5734   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
5735   const PetscInt    *localPoints, *neighbors;
5736   const PetscSFNode *remotePoints;
5737   PetscInt          *localPointsNew;
5738   PetscSFNode       *remotePointsNew;
5739   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
5740   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r, n;
5741   PetscInt           cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
5742   PetscErrorCode     ierr;
5743 
5744   PetscFunctionBegin;
5745   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
5746   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5747   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5748   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5749   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5750   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5751   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5752   cMax = cMax < 0 ? cEnd : cMax;
5753   fMax = fMax < 0 ? fEnd : fMax;
5754   eMax = eMax < 0 ? eEnd : eMax;
5755   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
5756   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
5757   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
5758   /* Calculate size of new SF */
5759   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5760   if (numRoots < 0) PetscFunctionReturn(0);
5761   for (l = 0; l < numLeaves; ++l) {
5762     const PetscInt p = localPoints[l];
5763 
5764     switch (refiner) {
5765     case REFINER_SIMPLEX_1D:
5766       if ((p >= vStart) && (p < vEnd)) {
5767         /* Interior vertices stay the same */
5768         ++numLeavesNew;
5769       } else if ((p >= cStart && p < cMax)) {
5770         /* Interior cells add new cells and interior vertices */
5771         numLeavesNew += 2 + 1;
5772       }
5773       break;
5774     case REFINER_SIMPLEX_2D:
5775     case REFINER_HYBRID_SIMPLEX_2D:
5776       if ((p >= vStart) && (p < vEnd)) {
5777         /* Interior vertices stay the same */
5778         ++numLeavesNew;
5779       } else if ((p >= fStart) && (p < fMax)) {
5780         /* Interior faces add new faces and vertex */
5781         numLeavesNew += 2 + 1;
5782       } else if ((p >= fMax) && (p < fEnd)) {
5783         /* Hybrid faces stay the same */
5784         ++numLeavesNew;
5785       } else if ((p >= cStart) && (p < cMax)) {
5786         /* Interior cells add new cells and interior faces */
5787         numLeavesNew += 4 + 3;
5788       } else if ((p >= cMax) && (p < cEnd)) {
5789         /* Hybrid cells add new cells and hybrid face */
5790         numLeavesNew += 2 + 1;
5791       }
5792       break;
5793     case REFINER_HEX_2D:
5794     case REFINER_HYBRID_HEX_2D:
5795       if ((p >= vStart) && (p < vEnd)) {
5796         /* Interior vertices stay the same */
5797         ++numLeavesNew;
5798       } else if ((p >= fStart) && (p < fMax)) {
5799         /* Interior faces add new faces and vertex */
5800         numLeavesNew += 2 + 1;
5801       } else if ((p >= fMax) && (p < fEnd)) {
5802         /* Hybrid faces stay the same */
5803         ++numLeavesNew;
5804       } else if ((p >= cStart) && (p < cMax)) {
5805         /* Interior cells add new cells, interior faces, and vertex */
5806         numLeavesNew += 4 + 4 + 1;
5807       } else if ((p >= cMax) && (p < cEnd)) {
5808         /* Hybrid cells add new cells and hybrid face */
5809         numLeavesNew += 2 + 1;
5810       }
5811       break;
5812     case REFINER_SIMPLEX_3D:
5813     case REFINER_HYBRID_SIMPLEX_3D:
5814       if ((p >= vStart) && (p < vEnd)) {
5815         /* Interior vertices stay the same */
5816         ++numLeavesNew;
5817       } else if ((p >= eStart) && (p < eMax)) {
5818         /* Interior edges add new edges and vertex */
5819         numLeavesNew += 2 + 1;
5820       } else if ((p >= eMax) && (p < eEnd)) {
5821         /* Hybrid edges stay the same */
5822         ++numLeavesNew;
5823       } else if ((p >= fStart) && (p < fMax)) {
5824         /* Interior faces add new faces and edges */
5825         numLeavesNew += 4 + 3;
5826       } else if ((p >= fMax) && (p < fEnd)) {
5827         /* Hybrid faces add new faces and edges */
5828         numLeavesNew += 2 + 1;
5829       } else if ((p >= cStart) && (p < cMax)) {
5830         /* Interior cells add new cells, faces, and edges */
5831         numLeavesNew += 8 + 8 + 1;
5832       } else if ((p >= cMax) && (p < cEnd)) {
5833         /* Hybrid cells add new cells and faces */
5834         numLeavesNew += 4 + 3;
5835       }
5836       break;
5837     case REFINER_HEX_3D:
5838     case REFINER_HYBRID_HEX_3D:
5839       if ((p >= vStart) && (p < vEnd)) {
5840         /* Old vertices stay the same */
5841         ++numLeavesNew;
5842       } else if ((p >= eStart) && (p < eMax)) {
5843         /* Interior edges add new edges, and vertex */
5844         numLeavesNew += 2 + 1;
5845       } else if ((p >= eMax) && (p < eEnd)) {
5846         /* Hybrid edges stay the same */
5847         ++numLeavesNew;
5848       } else if ((p >= fStart) && (p < fMax)) {
5849         /* Interior faces add new faces, edges, and vertex */
5850         numLeavesNew += 4 + 4 + 1;
5851       } else if ((p >= fMax) && (p < fEnd)) {
5852         /* Hybrid faces add new faces and edges */
5853         numLeavesNew += 2 + 1;
5854       } else if ((p >= cStart) && (p < cMax)) {
5855         /* Interior cells add new cells, faces, edges, and vertex */
5856         numLeavesNew += 8 + 12 + 6 + 1;
5857       } else if ((p >= cStart) && (p < cEnd)) {
5858         /* Hybrid cells add new cells, faces, and edges */
5859         numLeavesNew += 4 + 4 + 1;
5860       }
5861       break;
5862     default:
5863       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5864     }
5865   }
5866   /* Communicate depthSizes for each remote rank */
5867   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
5868   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
5869   ierr = PetscMalloc5((depth+1)*numNeighbors,&rdepthSize,numNeighbors,&rvStartNew,numNeighbors,&reStartNew,numNeighbors,&rfStartNew,numNeighbors,&rcStartNew);CHKERRQ(ierr);
5870   ierr = PetscMalloc7(depth+1,&depthSizeOld,(depth+1)*numNeighbors,&rdepthSizeOld,(depth+1)*numNeighbors,&rdepthMaxOld,numNeighbors,&rvStart,numNeighbors,&reStart,numNeighbors,&rfStart,numNeighbors,&rcStart);CHKERRQ(ierr);
5871   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
5872   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
5873   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5874   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5875   for (n = 0; n < numNeighbors; ++n) {
5876     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
5877   }
5878   depthSizeOld[depth]   = cMax;
5879   depthSizeOld[0]       = vMax;
5880   depthSizeOld[depth-1] = fMax;
5881   depthSizeOld[1]       = eMax;
5882 
5883   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5884   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5885 
5886   depthSizeOld[depth]   = cEnd - cStart;
5887   depthSizeOld[0]       = vEnd - vStart;
5888   depthSizeOld[depth-1] = fEnd - fStart;
5889   depthSizeOld[1]       = eEnd - eStart;
5890 
5891   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5892   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5893   for (n = 0; n < numNeighbors; ++n) {
5894     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
5895     rdepthMaxOld[n*(depth+1)+depth]   = rdepthMaxOld[n*(depth+1)+depth]   < 0 ? rdepthSizeOld[n*(depth+1)+depth]  +rcStart[n]: rdepthMaxOld[n*(depth+1)+depth];
5896     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];
5897     rdepthMaxOld[n*(depth+1)+1]       = rdepthMaxOld[n*(depth+1)+1]       < 0 ? rdepthSizeOld[n*(depth+1)+1]      +reStart[n]: rdepthMaxOld[n*(depth+1)+1];
5898   }
5899   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
5900   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
5901   /* Calculate new point SF */
5902   ierr = PetscMalloc1(numLeavesNew, &localPointsNew);CHKERRQ(ierr);
5903   ierr = PetscMalloc1(numLeavesNew, &remotePointsNew);CHKERRQ(ierr);
5904   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
5905   for (l = 0, m = 0; l < numLeaves; ++l) {
5906     PetscInt    p     = localPoints[l];
5907     PetscInt    rp    = remotePoints[l].index, n;
5908     PetscMPIInt rrank = remotePoints[l].rank;
5909 
5910     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
5911     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
5912     switch (refiner) {
5913     case REFINER_SIMPLEX_1D:
5914       if ((p >= vStart) && (p < vEnd)) {
5915         /* Old vertices stay the same */
5916         localPointsNew[m]        = vStartNew     + (p  - vStart);
5917         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5918         remotePointsNew[m].rank  = rrank;
5919         ++m;
5920       } else if ((p >= cStart) && (p < cMax)) {
5921         /* Old interior cells add new cells and vertex */
5922         for (r = 0; r < 2; ++r, ++m) {
5923           localPointsNew[m]        = cStartNew     + (p  - cStart)*2     + r;
5924           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*2 + r;
5925           remotePointsNew[m].rank  = rrank;
5926         }
5927         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - cStart);
5928         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rcStart[n]);
5929         remotePointsNew[m].rank  = rrank;
5930         ++m;
5931       }
5932       break;
5933     case REFINER_SIMPLEX_2D:
5934     case REFINER_HYBRID_SIMPLEX_2D:
5935       if ((p >= vStart) && (p < vEnd)) {
5936         /* Old vertices stay the same */
5937         localPointsNew[m]        = vStartNew     + (p  - vStart);
5938         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5939         remotePointsNew[m].rank  = rrank;
5940         ++m;
5941       } else if ((p >= fStart) && (p < fMax)) {
5942         /* Old interior faces add new faces and vertex */
5943         for (r = 0; r < 2; ++r, ++m) {
5944           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5945           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5946           remotePointsNew[m].rank  = rrank;
5947         }
5948         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5949         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5950         remotePointsNew[m].rank  = rrank;
5951         ++m;
5952       } else if ((p >= fMax) && (p < fEnd)) {
5953         /* Old hybrid faces stay the same */
5954         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
5955         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
5956         remotePointsNew[m].rank  = rrank;
5957         ++m;
5958       } else if ((p >= cStart) && (p < cMax)) {
5959         /* Old interior cells add new cells and interior faces */
5960         for (r = 0; r < 4; ++r, ++m) {
5961           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5962           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5963           remotePointsNew[m].rank  = rrank;
5964         }
5965         for (r = 0; r < 3; ++r, ++m) {
5966           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
5967           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
5968           remotePointsNew[m].rank  = rrank;
5969         }
5970       } else if ((p >= cMax) && (p < cEnd)) {
5971         /* Old hybrid cells add new cells and hybrid face */
5972         for (r = 0; r < 2; ++r, ++m) {
5973           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5974           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5975           remotePointsNew[m].rank  = rrank;
5976         }
5977         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
5978         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]);
5979         remotePointsNew[m].rank  = rrank;
5980         ++m;
5981       }
5982       break;
5983     case REFINER_HEX_2D:
5984     case REFINER_HYBRID_HEX_2D:
5985       if ((p >= vStart) && (p < vEnd)) {
5986         /* Old vertices stay the same */
5987         localPointsNew[m]        = vStartNew     + (p  - vStart);
5988         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5989         remotePointsNew[m].rank  = rrank;
5990         ++m;
5991       } else if ((p >= fStart) && (p < fMax)) {
5992         /* Old interior faces add new faces and vertex */
5993         for (r = 0; r < 2; ++r, ++m) {
5994           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5995           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5996           remotePointsNew[m].rank  = rrank;
5997         }
5998         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5999         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6000         remotePointsNew[m].rank  = rrank;
6001         ++m;
6002       } else if ((p >= fMax) && (p < fEnd)) {
6003         /* Old hybrid faces stay the same */
6004         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
6005         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
6006         remotePointsNew[m].rank  = rrank;
6007         ++m;
6008       } else if ((p >= cStart) && (p < cMax)) {
6009         /* Old interior cells add new cells, interior faces, and vertex */
6010         for (r = 0; r < 4; ++r, ++m) {
6011           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6012           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6013           remotePointsNew[m].rank  = rrank;
6014         }
6015         for (r = 0; r < 4; ++r, ++m) {
6016           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*4     + r;
6017           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*4 + r;
6018           remotePointsNew[m].rank  = rrank;
6019         }
6020         localPointsNew[m]        = vStartNew     + (vEnd - vStart)               + (fMax                              - fStart)     + (p  - cStart);
6021         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0]  + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]);
6022         remotePointsNew[m].rank  = rrank;
6023         ++m;
6024       } else if ((p >= cStart) && (p < cMax)) {
6025         /* Old hybrid cells add new cells and hybrid face */
6026         for (r = 0; r < 2; ++r, ++m) {
6027           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6028           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6029           remotePointsNew[m].rank  = rrank;
6030         }
6031         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*4     + (p  - cMax);
6032         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]);
6033         remotePointsNew[m].rank  = rrank;
6034         ++m;
6035       }
6036       break;
6037     case REFINER_SIMPLEX_3D:
6038     case REFINER_HYBRID_SIMPLEX_3D:
6039       if ((p >= vStart) && (p < vEnd)) {
6040         /* Interior vertices stay the same */
6041         localPointsNew[m]        = vStartNew     + (p  - vStart);
6042         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6043         remotePointsNew[m].rank  = rrank;
6044         ++m;
6045       } else if ((p >= eStart) && (p < eMax)) {
6046         /* Interior edges add new edges and vertex */
6047         for (r = 0; r < 2; ++r, ++m) {
6048           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
6049           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
6050           remotePointsNew[m].rank  = rrank;
6051         }
6052         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
6053         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
6054         remotePointsNew[m].rank  = rrank;
6055         ++m;
6056       } else if ((p >= eMax) && (p < eEnd)) {
6057         /* Hybrid edges stay the same */
6058         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (p  - eMax);
6059         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]);
6060         remotePointsNew[m].rank  = rrank;
6061         ++m;
6062       } else if ((p >= fStart) && (p < fMax)) {
6063         /* Interior faces add new faces and edges */
6064         for (r = 0; r < 4; ++r, ++m) {
6065           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
6066           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
6067           remotePointsNew[m].rank  = rrank;
6068         }
6069         for (r = 0; r < 3; ++r, ++m) {
6070           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*3     + r;
6071           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*3 + r;
6072           remotePointsNew[m].rank  = rrank;
6073         }
6074       } else if ((p >= fMax) && (p < fEnd)) {
6075         /* Hybrid faces add new faces and edges */
6076         for (r = 0; r < 2; ++r, ++m) {
6077           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (p  - fMax)*2                              + r;
6078           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;
6079           remotePointsNew[m].rank  = rrank;
6080         }
6081         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (cMax                            - cStart)     + (eEnd                                    - eMax)                        + (p  - fMax);
6082         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]);
6083         remotePointsNew[m].rank  = rrank;
6084         ++m;
6085       } else if ((p >= cStart) && (p < cMax)) {
6086         /* Interior cells add new cells, faces, and edges */
6087         for (r = 0; r < 8; ++r, ++m) {
6088           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
6089           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
6090           remotePointsNew[m].rank  = rrank;
6091         }
6092         for (r = 0; r < 8; ++r, ++m) {
6093           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*8     + r;
6094           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*8 + r;
6095           remotePointsNew[m].rank  = rrank;
6096         }
6097         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*3     + (p  - cStart)*1     + 0;
6098         remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*3 + (rp - rcStart[n])*1 + 0;
6099         remotePointsNew[m].rank  = rrank;
6100         ++m;
6101       } else if ((p >= cMax) && (p < cEnd)) {
6102         /* Hybrid cells add new cells and faces */
6103         for (r = 0; r < 4; ++r, ++m) {
6104           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
6105           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
6106           remotePointsNew[m].rank  = rrank;
6107         }
6108         for (r = 0; r < 3; ++r, ++m) {
6109           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*8     + (fEnd                                          - fMax)*2                              + (p  - cMax)*3                            + r;
6110           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;
6111           remotePointsNew[m].rank  = rrank;
6112         }
6113       }
6114       break;
6115     case REFINER_HEX_3D:
6116     case REFINER_HYBRID_HEX_3D:
6117       if ((p >= vStart) && (p < vEnd)) {
6118         /* Interior vertices stay the same */
6119         localPointsNew[m]        = vStartNew     + (p  - vStart);
6120         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6121         remotePointsNew[m].rank  = rrank;
6122         ++m;
6123       } else if ((p >= eStart) && (p < eMax)) {
6124         /* Interior edges add new edges and vertex */
6125         for (r = 0; r < 2; ++r, ++m) {
6126           localPointsNew[m]        = eStartNew     + (p  - eStart)*2     + r;
6127           remotePointsNew[m].index = reStartNew[n] + (rp - reStart[n])*2 + r;
6128           remotePointsNew[m].rank  = rrank;
6129         }
6130         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - eStart);
6131         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - reStart[n]);
6132         remotePointsNew[m].rank  = rrank;
6133         ++m;
6134       } else if ((p >= eMax) && (p < eEnd)) {
6135         /* Hybrid edges stay the same */
6136         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (p  - eMax);
6137         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]);
6138         remotePointsNew[m].rank  = rrank;
6139         ++m;
6140       } else if ((p >= fStart) && (p < fMax)) {
6141         /* Interior faces add new faces, edges, and vertex */
6142         for (r = 0; r < 4; ++r, ++m) {
6143           localPointsNew[m]        = fStartNew     + (p  - fStart)*4     + r;
6144           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*4 + r;
6145           remotePointsNew[m].rank  = rrank;
6146         }
6147         for (r = 0; r < 4; ++r, ++m) {
6148           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (p  - fStart)*4     + r;
6149           remotePointsNew[m].index = reStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n])*2 + (rp - rfStart[n])*4 + r;
6150           remotePointsNew[m].rank  = rrank;
6151         }
6152         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (eMax                        - eStart)     + (p  - fStart);
6153         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rp - rfStart[n]);
6154         remotePointsNew[m].rank  = rrank;
6155         ++m;
6156       } else if ((p >= fMax) && (p < fEnd)) {
6157         /* Hybrid faces add new faces and edges */
6158         for (r = 0; r < 2; ++r, ++m) {
6159           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (p  - fMax)*2                              + r;
6160           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;
6161           remotePointsNew[m].rank  = rrank;
6162         }
6163         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (p  - fMax);
6164         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]);
6165         remotePointsNew[m].rank  = rrank;
6166         ++m;
6167       } else if ((p >= cStart) && (p < cMax)) {
6168         /* Interior cells add new cells, faces, edges, and vertex */
6169         for (r = 0; r < 8; ++r, ++m) {
6170           localPointsNew[m]        = cStartNew     + (p  - cStart)*8     + r;
6171           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*8 + r;
6172           remotePointsNew[m].rank  = rrank;
6173         }
6174         for (r = 0; r < 12; ++r, ++m) {
6175           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (p  - cStart)*12     + r;
6176           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*4 + (rp - rcStart[n])*12 + r;
6177           remotePointsNew[m].rank  = rrank;
6178         }
6179         for (r = 0; r < 6; ++r, ++m) {
6180           localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (p  - cStart)*6     + r;
6181           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;
6182           remotePointsNew[m].rank  = rrank;
6183         }
6184         for (r = 0; r < 1; ++r, ++m) {
6185           localPointsNew[m]        = vStartNew     + (eMax                        - eStart)     + (fMax                              - fStart)     + (p  - cStart)     + r;
6186           remotePointsNew[m].index = rvStartNew[n] + (rdepthMaxOld[n*(depth+1)+1] - reStart[n]) + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n]) + (rp - rcStart[n]) + r;
6187           remotePointsNew[m].rank  = rrank;
6188         }
6189       } else if ((p >= cMax) && (p < cEnd)) {
6190         /* Hybrid cells add new cells, faces, and edges */
6191         for (r = 0; r < 4; ++r, ++m) {
6192           localPointsNew[m]        = cStartNew     + (cMax                            - cStart)*8     + (p  - cMax)*4                            + r;
6193           remotePointsNew[m].index = rcStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*8 + (rp - rdepthMaxOld[n*(depth+1)+depth])*4 + r;
6194           remotePointsNew[m].rank  = rrank;
6195         }
6196         for (r = 0; r < 4; ++r, ++m) {
6197           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*4     + (cMax                            - cStart)*12     + (fEnd                                          - fMax)*2                              + (p  - cMax)*4                            + r;
6198           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;
6199           remotePointsNew[m].rank  = rrank;
6200         }
6201         localPointsNew[m]        = eStartNew     + (eMax                        - eStart)*2     + (fMax                              - fStart)*4     + (cMax                            - cStart)*6     + (eEnd                                    - eMax)                        + (fEnd                                          - fMax)                              + (p  - cMax);
6202         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]);
6203         remotePointsNew[m].rank  = rrank;
6204         ++m;
6205       }
6206       break;
6207     default:
6208       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6209     }
6210   }
6211   if (m != numLeavesNew) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of leaf point %d should be %d", m, numLeavesNew);
6212   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
6213   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
6214   {
6215     PetscSFNode *rp, *rtmp;
6216     PetscInt    *lp, *idx, *ltmp, i;
6217 
6218     /* SF needs sorted leaves to correct calculate Gather */
6219     ierr = PetscMalloc1(numLeavesNew,&idx);CHKERRQ(ierr);
6220     ierr = PetscMalloc1(numLeavesNew, &lp);CHKERRQ(ierr);
6221     ierr = PetscMalloc1(numLeavesNew, &rp);CHKERRQ(ierr);
6222     for (i = 0; i < numLeavesNew; ++i) {
6223       if ((localPointsNew[i] < pStartNew) || (localPointsNew[i] >= pEndNew)) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Local SF point %d (%d) not in [%d, %d)", localPointsNew[i], i, pStartNew, pEndNew);
6224       idx[i] = i;
6225     }
6226     ierr = PetscSortIntWithPermutation(numLeavesNew, localPointsNew, idx);CHKERRQ(ierr);
6227     for (i = 0; i < numLeavesNew; ++i) {
6228       lp[i] = localPointsNew[idx[i]];
6229       rp[i] = remotePointsNew[idx[i]];
6230     }
6231     ltmp            = localPointsNew;
6232     localPointsNew  = lp;
6233     rtmp            = remotePointsNew;
6234     remotePointsNew = rp;
6235     ierr = PetscFree(idx);CHKERRQ(ierr);
6236     ierr = PetscFree(ltmp);CHKERRQ(ierr);
6237     ierr = PetscFree(rtmp);CHKERRQ(ierr);
6238   }
6239   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6240   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
6241   ierr = PetscFree7(depthSizeOld,rdepthSizeOld,rdepthMaxOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
6242   PetscFunctionReturn(0);
6243 }
6244 
6245 #undef __FUNCT__
6246 #define __FUNCT__ "CellRefinerCreateLabels"
6247 static PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6248 {
6249   PetscInt       numLabels, l;
6250   PetscInt       depth, newp, cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax, r;
6251   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
6252   PetscErrorCode ierr;
6253 
6254   PetscFunctionBegin;
6255   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6256   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6257   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6258   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6259   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6260   if (refiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
6261   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
6262   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6263   switch (refiner) {
6264   case REFINER_NOOP:
6265   case REFINER_SIMPLEX_1D:
6266   case REFINER_SIMPLEX_2D:
6267   case REFINER_HEX_2D:
6268   case REFINER_SIMPLEX_3D:
6269   case REFINER_HEX_3D:
6270     break;
6271   case REFINER_HYBRID_SIMPLEX_3D:
6272   case REFINER_HYBRID_HEX_3D:
6273     if (eMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No edge maximum specified in hybrid mesh");
6274   case REFINER_HYBRID_SIMPLEX_2D:
6275   case REFINER_HYBRID_HEX_2D:
6276     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6277     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6278     break;
6279   default:
6280     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6281   }
6282   for (l = 0; l < numLabels; ++l) {
6283     DMLabel         label, labelNew;
6284     const char     *lname;
6285     PetscBool       isDepth;
6286     IS              valueIS;
6287     const PetscInt *values;
6288     PetscInt        numValues, val;
6289 
6290     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
6291     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
6292     if (isDepth) continue;
6293     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
6294     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
6295     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
6296     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
6297     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
6298     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
6299     for (val = 0; val < numValues; ++val) {
6300       IS              pointIS;
6301       const PetscInt *points;
6302       PetscInt        numPoints, n;
6303 
6304       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
6305       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
6306       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
6307       /* Ensure refined label is created with same number of strata as
6308        * original (even if no entries here). */
6309       if (!numPoints) {
6310         ierr = DMLabelSetValue(labelNew, 0, values[val]);CHKERRQ(ierr);
6311         ierr = DMLabelClearValue(labelNew, 0, values[val]);CHKERRQ(ierr);
6312       }
6313       for (n = 0; n < numPoints; ++n) {
6314         const PetscInt p = points[n];
6315         switch (refiner) {
6316         case REFINER_SIMPLEX_1D:
6317           if ((p >= vStart) && (p < vEnd)) {
6318             /* Old vertices stay the same */
6319             newp = vStartNew + (p - vStart);
6320             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6321           } else if ((p >= cStart) && (p < cEnd)) {
6322             /* Old cells add new cells and vertex */
6323             newp = vStartNew + (vEnd - vStart) + (p - cStart);
6324             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6325             for (r = 0; r < 2; ++r) {
6326               newp = cStartNew + (p - cStart)*2 + r;
6327               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6328             }
6329           }
6330           break;
6331         case REFINER_SIMPLEX_2D:
6332           if ((p >= vStart) && (p < vEnd)) {
6333             /* Old vertices stay the same */
6334             newp = vStartNew + (p - vStart);
6335             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6336           } else if ((p >= fStart) && (p < fEnd)) {
6337             /* Old faces add new faces and vertex */
6338             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6339             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6340             for (r = 0; r < 2; ++r) {
6341               newp = fStartNew + (p - fStart)*2 + r;
6342               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6343             }
6344           } else if ((p >= cStart) && (p < cEnd)) {
6345             /* Old cells add new cells and interior faces */
6346             for (r = 0; r < 4; ++r) {
6347               newp = cStartNew + (p - cStart)*4 + r;
6348               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6349             }
6350             for (r = 0; r < 3; ++r) {
6351               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6352               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6353             }
6354           }
6355           break;
6356         case REFINER_HEX_2D:
6357           if ((p >= vStart) && (p < vEnd)) {
6358             /* Old vertices stay the same */
6359             newp = vStartNew + (p - vStart);
6360             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6361           } else if ((p >= fStart) && (p < fEnd)) {
6362             /* Old faces add new faces and vertex */
6363             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6364             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6365             for (r = 0; r < 2; ++r) {
6366               newp = fStartNew + (p - fStart)*2 + r;
6367               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6368             }
6369           } else if ((p >= cStart) && (p < cEnd)) {
6370             /* Old cells add new cells and interior faces and vertex */
6371             for (r = 0; r < 4; ++r) {
6372               newp = cStartNew + (p - cStart)*4 + r;
6373               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6374             }
6375             for (r = 0; r < 4; ++r) {
6376               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
6377               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6378             }
6379             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
6380             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6381           }
6382           break;
6383         case REFINER_HYBRID_SIMPLEX_2D:
6384           if ((p >= vStart) && (p < vEnd)) {
6385             /* Old vertices stay the same */
6386             newp = vStartNew + (p - vStart);
6387             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6388           } else if ((p >= fStart) && (p < fMax)) {
6389             /* Old interior faces add new faces and vertex */
6390             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6391             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6392             for (r = 0; r < 2; ++r) {
6393               newp = fStartNew + (p - fStart)*2 + r;
6394               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6395             }
6396           } else if ((p >= fMax) && (p < fEnd)) {
6397             /* Old hybrid faces stay the same */
6398             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
6399             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6400           } else if ((p >= cStart) && (p < cMax)) {
6401             /* Old interior cells add new cells and interior faces */
6402             for (r = 0; r < 4; ++r) {
6403               newp = cStartNew + (p - cStart)*4 + r;
6404               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6405             }
6406             for (r = 0; r < 3; ++r) {
6407               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6408               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6409             }
6410           } else if ((p >= cMax) && (p < cEnd)) {
6411             /* Old hybrid cells add new cells and hybrid face */
6412             for (r = 0; r < 2; ++r) {
6413               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
6414               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6415             }
6416             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
6417             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6418           }
6419           break;
6420         case REFINER_HYBRID_HEX_2D:
6421           if ((p >= vStart) && (p < vEnd)) {
6422             /* Old vertices stay the same */
6423             newp = vStartNew + (p - vStart);
6424             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6425           } else if ((p >= fStart) && (p < fMax)) {
6426             /* Old interior faces add new faces and vertex */
6427             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6428             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6429             for (r = 0; r < 2; ++r) {
6430               newp = fStartNew + (p - fStart)*2 + r;
6431               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6432             }
6433           } else if ((p >= fMax) && (p < fEnd)) {
6434             /* Old hybrid faces stay the same */
6435             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
6436             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6437           } else if ((p >= cStart) && (p < cMax)) {
6438             /* Old interior cells add new cells, interior faces, and vertex */
6439             for (r = 0; r < 4; ++r) {
6440               newp = cStartNew + (p - cStart)*4 + r;
6441               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6442             }
6443             for (r = 0; r < 4; ++r) {
6444               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
6445               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6446             }
6447             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
6448             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6449           } else if ((p >= cMax) && (p < cEnd)) {
6450             /* Old hybrid cells add new cells and hybrid face */
6451             for (r = 0; r < 2; ++r) {
6452               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
6453               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6454             }
6455             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*4 + (p - cMax);
6456             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6457           }
6458           break;
6459         case REFINER_SIMPLEX_3D:
6460           if ((p >= vStart) && (p < vEnd)) {
6461             /* Old vertices stay the same */
6462             newp = vStartNew + (p - vStart);
6463             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6464           } else if ((p >= eStart) && (p < eEnd)) {
6465             /* Old edges add new edges and vertex */
6466             for (r = 0; r < 2; ++r) {
6467               newp = eStartNew + (p - eStart)*2 + r;
6468               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6469             }
6470             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6471             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6472           } else if ((p >= fStart) && (p < fEnd)) {
6473             /* Old faces add new faces and edges */
6474             for (r = 0; r < 4; ++r) {
6475               newp = fStartNew + (p - fStart)*4 + r;
6476               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6477             }
6478             for (r = 0; r < 3; ++r) {
6479               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*3 + r;
6480               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6481             }
6482           } else if ((p >= cStart) && (p < cEnd)) {
6483             /* Old cells add new cells and interior faces and edges */
6484             for (r = 0; r < 8; ++r) {
6485               newp = cStartNew + (p - cStart)*8 + r;
6486               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6487             }
6488             for (r = 0; r < 8; ++r) {
6489               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*8 + r;
6490               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6491             }
6492             for (r = 0; r < 1; ++r) {
6493               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*3 + (p - cStart)*1 + r;
6494               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6495             }
6496           }
6497           break;
6498         case REFINER_HYBRID_SIMPLEX_3D:
6499           if ((p >= vStart) && (p < vEnd)) {
6500             /* Interior vertices stay the same */
6501             newp = vStartNew + (p - vStart);
6502             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6503           } else if ((p >= eStart) && (p < eMax)) {
6504             /* Interior edges add new edges and vertex */
6505             for (r = 0; r < 2; ++r) {
6506               newp = eStartNew + (p - eStart)*2 + r;
6507               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6508             }
6509             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6510             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6511           } else if ((p >= eMax) && (p < eEnd)) {
6512             /* Hybrid edges stay the same */
6513             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - eMax);
6514             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6515           } else if ((p >= fStart) && (p < fMax)) {
6516             /* Interior faces add new faces and edges */
6517             for (r = 0; r < 4; ++r) {
6518               newp = fStartNew + (p - fStart)*4 + r;
6519               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6520             }
6521             for (r = 0; r < 3; ++r) {
6522               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*3 + r;
6523               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6524             }
6525           } else if ((p >= fMax) && (p < fEnd)) {
6526             /* Hybrid faces add new faces and edges */
6527             for (r = 0; r < 2; ++r) {
6528               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (p - fMax)*2 + r;
6529               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6530             }
6531             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (cMax - cStart) + (p - fMax);
6532             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6533           } else if ((p >= cStart) && (p < cMax)) {
6534             /* Interior cells add new cells, faces, and edges */
6535             for (r = 0; r < 8; ++r) {
6536               newp = cStartNew + (p - cStart)*8 + r;
6537               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6538             }
6539             for (r = 0; r < 8; ++r) {
6540               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*8 + r;
6541               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6542             }
6543             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*3 + (p - cStart);
6544             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6545           } else if ((p >= cMax) && (p < cEnd)) {
6546             /* Hybrid cells add new cells and faces */
6547             for (r = 0; r < 4; ++r) {
6548               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
6549               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6550             }
6551             for (r = 0; r < 3; ++r) {
6552               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*8 + (fEnd - fMax)*2 + (p - cMax)*3 + r;
6553               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6554             }
6555           }
6556           break;
6557         case REFINER_HEX_3D:
6558           if ((p >= vStart) && (p < vEnd)) {
6559             /* Old vertices stay the same */
6560             newp = vStartNew + (p - vStart);
6561             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6562           } else if ((p >= eStart) && (p < eEnd)) {
6563             /* Old edges add new edges and vertex */
6564             for (r = 0; r < 2; ++r) {
6565               newp = eStartNew + (p - eStart)*2 + r;
6566               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6567             }
6568             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6569             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6570           } else if ((p >= fStart) && (p < fEnd)) {
6571             /* Old faces add new faces, edges, and vertex */
6572             for (r = 0; r < 4; ++r) {
6573               newp = fStartNew + (p - fStart)*4 + r;
6574               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6575             }
6576             for (r = 0; r < 4; ++r) {
6577               newp = eStartNew + (eEnd - eStart)*2 + (p - fStart)*4 + r;
6578               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6579             }
6580             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (p - fStart);
6581             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6582           } else if ((p >= cStart) && (p < cEnd)) {
6583             /* Old cells add new cells, faces, edges, and vertex */
6584             for (r = 0; r < 8; ++r) {
6585               newp = cStartNew + (p - cStart)*8 + r;
6586               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6587             }
6588             for (r = 0; r < 12; ++r) {
6589               newp = fStartNew + (fEnd - fStart)*4 + (p - cStart)*12 + r;
6590               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6591             }
6592             for (r = 0; r < 6; ++r) {
6593               newp = eStartNew + (eEnd - eStart)*2 + (fEnd - fStart)*4 + (p - cStart)*6 + r;
6594               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6595             }
6596             newp = vStartNew + (vEnd - vStart) + (eEnd - eStart) + (fEnd - fStart) + (p - cStart);
6597             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6598           }
6599           break;
6600         case REFINER_HYBRID_HEX_3D:
6601           if ((p >= vStart) && (p < vEnd)) {
6602             /* Interior vertices stay the same */
6603             newp = vStartNew + (p - vStart);
6604             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6605           } else if ((p >= eStart) && (p < eMax)) {
6606             /* Interior edges add new edges and vertex */
6607             for (r = 0; r < 2; ++r) {
6608               newp = eStartNew + (p - eStart)*2 + r;
6609               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6610             }
6611             newp = vStartNew + (vEnd - vStart) + (p - eStart);
6612             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6613           } else if ((p >= eMax) && (p < eEnd)) {
6614             /* Hybrid edges stay the same */
6615             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - eMax);
6616             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6617           } else if ((p >= fStart) && (p < fMax)) {
6618             /* Interior faces add new faces, edges, and vertex */
6619             for (r = 0; r < 4; ++r) {
6620               newp = fStartNew + (p - fStart)*4 + r;
6621               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6622             }
6623             for (r = 0; r < 4; ++r) {
6624               newp = eStartNew + (eMax - eStart)*2 + (p - fStart)*4 + r;
6625               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6626             }
6627             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (p - fStart);
6628             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6629           } else if ((p >= fMax) && (p < fEnd)) {
6630             /* Hybrid faces add new faces and edges */
6631             for (r = 0; r < 2; ++r) {
6632               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (p - fMax)*2 + r;
6633               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6634             }
6635             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (p - fMax);
6636             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6637           } else if ((p >= cStart) && (p < cMax)) {
6638             /* Interior cells add new cells, faces, edges, and vertex */
6639             for (r = 0; r < 8; ++r) {
6640               newp = cStartNew + (p - cStart)*8 + r;
6641               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6642             }
6643             for (r = 0; r < 12; ++r) {
6644               newp = fStartNew + (fMax - fStart)*4 + (p - cStart)*12 + r;
6645               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6646             }
6647             for (r = 0; r < 6; ++r) {
6648               newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (p - cStart)*6 + r;
6649               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6650             }
6651             newp = vStartNew + (vEnd - vStart) + (eMax - eStart) + (fMax - fStart) + (p - cStart);
6652             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6653           } else if ((p >= cMax) && (p < cEnd)) {
6654             /* Hybrid cells add new cells, faces, and edges */
6655             for (r = 0; r < 4; ++r) {
6656               newp = cStartNew + (cMax - cStart)*8 + (p - cMax)*4 + r;
6657               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6658             }
6659             for (r = 0; r < 4; ++r) {
6660               newp = fStartNew + (fMax - fStart)*4 + (cMax - cStart)*12 + (fEnd - fMax)*2 + (p - cMax)*4 + r;
6661               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6662             }
6663             newp = eStartNew + (eMax - eStart)*2 + (fMax - fStart)*4 + (cMax - cStart)*6 + (fEnd - fMax) + (p - cMax);
6664             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6665           }
6666           break;
6667         default:
6668           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6669         }
6670       }
6671       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
6672       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
6673     }
6674     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
6675     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
6676     if (0) {
6677       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
6678       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
6679       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
6680     }
6681   }
6682   PetscFunctionReturn(0);
6683 }
6684 
6685 #undef __FUNCT__
6686 #define __FUNCT__ "DMPlexRefineUniform_Internal"
6687 /* This will only work for interpolated meshes */
6688 PetscErrorCode DMPlexRefineUniform_Internal(DM dm, CellRefiner cellRefiner, DM *dmRefined)
6689 {
6690   DM             rdm;
6691   PetscInt      *depthSize;
6692   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
6693   PetscErrorCode ierr;
6694 
6695   PetscFunctionBegin;
6696   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
6697   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
6698   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6699   ierr = DMSetDimension(rdm, dim);CHKERRQ(ierr);
6700   /* Calculate number of new points of each depth */
6701   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6702   if (depth >= 0 && dim != depth) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Mesh must be interpolated for regular refinement");
6703   ierr = PetscMalloc1(depth+1, &depthSize);CHKERRQ(ierr);
6704   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
6705   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
6706   /* Step 1: Set chart */
6707   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
6708   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
6709   /* Step 2: Set cone/support sizes */
6710   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6711   /* Step 3: Setup refined DM */
6712   ierr = DMSetUp(rdm);CHKERRQ(ierr);
6713   /* Step 4: Set cones and supports */
6714   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6715   /* Step 5: Stratify */
6716   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
6717   /* Step 6: Create pointSF */
6718   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6719   /* Step 7: Set coordinates for vertices */
6720   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6721   /* Step 8: Create labels */
6722   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6723   ierr = PetscFree(depthSize);CHKERRQ(ierr);
6724 
6725   *dmRefined = rdm;
6726   PetscFunctionReturn(0);
6727 }
6728 
6729 #undef __FUNCT__
6730 #define __FUNCT__ "DMPlexCreateCoarsePointIS"
6731 /*@
6732   DMPlexCreateCoarsePointIS - Creates an IS covering the coarse DM chart with the fine points as data
6733 
6734   Input Parameter:
6735 . dm - The coarse DM
6736 
6737   Output Parameter:
6738 . fpointIS - The IS of all the fine points which exist in the original coarse mesh
6739 
6740   Level: developer
6741 
6742 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexCreateSubpointIS()
6743 @*/
6744 PetscErrorCode DMPlexCreateCoarsePointIS(DM dm, IS *fpointIS)
6745 {
6746   CellRefiner    cellRefiner;
6747   PetscInt      *depthSize, *fpoints;
6748   PetscInt       cStartNew = 0, vStartNew = 0, fStartNew = 0, eStartNew = 0;
6749   PetscInt       depth, pStart, pEnd, p, vStart, vEnd, v;
6750   PetscErrorCode ierr;
6751 
6752   PetscFunctionBegin;
6753   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6754   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6755   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6756   ierr = DMPlexGetCellRefiner_Internal(dm, &cellRefiner);CHKERRQ(ierr);
6757   ierr = PetscMalloc1(depth+1, &depthSize);CHKERRQ(ierr);
6758   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
6759   if (cellRefiner) {ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);}
6760   ierr = PetscMalloc1(pEnd-pStart,&fpoints);CHKERRQ(ierr);
6761   for (p = 0; p < pEnd-pStart; ++p) fpoints[p] = -1;
6762   switch (cellRefiner) {
6763   case REFINER_SIMPLEX_1D:
6764   case REFINER_SIMPLEX_2D:
6765   case REFINER_HYBRID_SIMPLEX_2D:
6766   case REFINER_HEX_2D:
6767   case REFINER_HYBRID_HEX_2D:
6768   case REFINER_SIMPLEX_3D:
6769   case REFINER_HYBRID_SIMPLEX_3D:
6770   case REFINER_HEX_3D:
6771   case REFINER_HYBRID_HEX_3D:
6772     for (v = vStart; v < vEnd; ++v) fpoints[v-pStart] = vStartNew + (v - vStart);
6773     break;
6774   default:
6775     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", cellRefiner);
6776   }
6777   ierr = ISCreateGeneral(PETSC_COMM_SELF, pEnd-pStart, fpoints, PETSC_OWN_POINTER, fpointIS);CHKERRQ(ierr);
6778   ierr = PetscFree(depthSize);CHKERRQ(ierr);
6779   PetscFunctionReturn(0);
6780 }
6781 
6782 #undef __FUNCT__
6783 #define __FUNCT__ "DMPlexSetRefinementUniform"
6784 /*@
6785   DMPlexSetRefinementUniform - Set the flag for uniform refinement
6786 
6787   Input Parameters:
6788 + dm - The DM
6789 - refinementUniform - The flag for uniform refinement
6790 
6791   Level: developer
6792 
6793 .seealso: DMRefine(), DMPlexGetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
6794 @*/
6795 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
6796 {
6797   DM_Plex *mesh = (DM_Plex*) dm->data;
6798 
6799   PetscFunctionBegin;
6800   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6801   mesh->refinementUniform = refinementUniform;
6802   PetscFunctionReturn(0);
6803 }
6804 
6805 #undef __FUNCT__
6806 #define __FUNCT__ "DMPlexGetRefinementUniform"
6807 /*@
6808   DMPlexGetRefinementUniform - Retrieve the flag for uniform refinement
6809 
6810   Input Parameter:
6811 . dm - The DM
6812 
6813   Output Parameter:
6814 . refinementUniform - The flag for uniform refinement
6815 
6816   Level: developer
6817 
6818 .seealso: DMRefine(), DMPlexSetRefinementUniform(), DMPlexGetRefinementLimit(), DMPlexSetRefinementLimit()
6819 @*/
6820 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
6821 {
6822   DM_Plex *mesh = (DM_Plex*) dm->data;
6823 
6824   PetscFunctionBegin;
6825   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6826   PetscValidPointer(refinementUniform,  2);
6827   *refinementUniform = mesh->refinementUniform;
6828   PetscFunctionReturn(0);
6829 }
6830 
6831 #undef __FUNCT__
6832 #define __FUNCT__ "DMPlexSetRefinementLimit"
6833 /*@
6834   DMPlexSetRefinementLimit - Set the maximum cell volume for refinement
6835 
6836   Input Parameters:
6837 + dm - The DM
6838 - refinementLimit - The maximum cell volume in the refined mesh
6839 
6840   Level: developer
6841 
6842 .seealso: DMRefine(), DMPlexGetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
6843 @*/
6844 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
6845 {
6846   DM_Plex *mesh = (DM_Plex*) dm->data;
6847 
6848   PetscFunctionBegin;
6849   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6850   mesh->refinementLimit = refinementLimit;
6851   PetscFunctionReturn(0);
6852 }
6853 
6854 #undef __FUNCT__
6855 #define __FUNCT__ "DMPlexGetRefinementLimit"
6856 /*@
6857   DMPlexGetRefinementLimit - Retrieve the maximum cell volume for refinement
6858 
6859   Input Parameter:
6860 . dm - The DM
6861 
6862   Output Parameter:
6863 . refinementLimit - The maximum cell volume in the refined mesh
6864 
6865   Level: developer
6866 
6867 .seealso: DMRefine(), DMPlexSetRefinementLimit(), DMPlexGetRefinementUniform(), DMPlexSetRefinementUniform()
6868 @*/
6869 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
6870 {
6871   DM_Plex *mesh = (DM_Plex*) dm->data;
6872 
6873   PetscFunctionBegin;
6874   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6875   PetscValidPointer(refinementLimit,  2);
6876   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
6877   *refinementLimit = mesh->refinementLimit;
6878   PetscFunctionReturn(0);
6879 }
6880 
6881 #undef __FUNCT__
6882 #define __FUNCT__ "DMPlexGetCellRefiner_Internal"
6883 PetscErrorCode DMPlexGetCellRefiner_Internal(DM dm, CellRefiner *cellRefiner)
6884 {
6885   PetscInt       dim, cStart, cEnd, coneSize, cMax, fMax;
6886   PetscErrorCode ierr;
6887 
6888   PetscFunctionBegin;
6889   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
6890   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6891   if (cEnd <= cStart) {*cellRefiner = REFINER_NOOP; PetscFunctionReturn(0);}
6892   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
6893   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, NULL, NULL);CHKERRQ(ierr);
6894   switch (dim) {
6895   case 1:
6896     switch (coneSize) {
6897     case 2:
6898       *cellRefiner = REFINER_SIMPLEX_1D;
6899       break;
6900     default:
6901       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
6902     }
6903     break;
6904   case 2:
6905     switch (coneSize) {
6906     case 3:
6907       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_2D;
6908       else *cellRefiner = REFINER_SIMPLEX_2D;
6909       break;
6910     case 4:
6911       if (cMax >= 0 && fMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_2D;
6912       else *cellRefiner = REFINER_HEX_2D;
6913       break;
6914     default:
6915       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
6916     }
6917     break;
6918   case 3:
6919     switch (coneSize) {
6920     case 4:
6921       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_SIMPLEX_3D;
6922       else *cellRefiner = REFINER_SIMPLEX_3D;
6923       break;
6924     case 6:
6925       if (cMax >= 0) *cellRefiner = REFINER_HYBRID_HEX_3D;
6926       else *cellRefiner = REFINER_HEX_3D;
6927       break;
6928     default:
6929       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
6930     }
6931     break;
6932   default:
6933     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
6934   }
6935   PetscFunctionReturn(0);
6936 }
6937